コード例 #1
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void SplitPathWithGaps()
        {
            PointF[] points =
            {
                new PointF(0,   0), new PointF(10, 10), new PointF(20, 40), new PointF(-10, 10),
                new PointF(20, 20), new PointF(25, 30), new PointF(25, 30), new PointF(40, 25)
            };
            PointKind[] kinds =
            {
                PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl,
                PointKind.Normal, PointKind.Normal, PointKind.Normal,        PointKind.Normal
            };
            SymPath p = new SymPath(points, kinds);

            LegGap[] gapStartStops = { new LegGap(-2, 3), new LegGap(15, 7), new LegGap(25, 1.5F), new LegGap(300, 5) };

            SymPath[] results = LegGap.SplitPathWithGaps(p, gapStartStops);

            foreach (SymPath path in results)
            {
                Console.WriteLine(path);
            }

            Assert.AreEqual(@"N(0.71,0.71)--N(10,10)--B(10.09,10.28)--B(10.18,10.56)--N(10.27,10.83)", results[0].ToString());
            Assert.AreEqual(@"N(11.95,17.61)--B(12.12,18.8)--B(12.17,19.79)--N(12.12,20.6)", results[1].ToString());
            Assert.AreEqual(@"N(11.88,22.07)--B(9.81,28.87)--B(-3.49,12.17)--N(20,20)--N(25,30)--N(25,30)--N(40,25)", results[2].ToString());
        }
コード例 #2
0
ファイル: LegGap.cs プロジェクト: petergolde/PurplePen
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static LegGap[] AddGap(SymPath path, LegGap[] original, PointF pt1, PointF pt2)
        {
            float dist1, dist2;
            LegGap newGap;
            LegGap[] newGaps;

            // map points to closes points on the line.
            path.DistanceFromPoint(pt1, out pt1);
            path.DistanceFromPoint(pt2, out pt2);

            // Map to distances along the line.
            dist1 = path.LengthToPoint(pt1);
            dist2 = path.LengthToPoint(pt2);

            // Create the new gap.
            if (dist1 < dist2)
                newGap = new LegGap(dist1, dist2 - dist1);
            else
                newGap = new LegGap(dist2, dist1 - dist2);

            // Add to the old gaps.
            if (original == null)
                newGaps = new LegGap[1] { newGap };
            else {
                newGaps = new LegGap[original.Length + 1];
                Array.Copy(original, newGaps, original.Length);
                newGaps[original.Length] = newGap;
            }

            // Simplify
            return SimplifyGaps(newGaps, path.Length);
        }
コード例 #3
0
        // Move a gap start/stop point to a new location. Return the new gap array. The gap array is NOT simplified.
        public static LegGap[] MoveStartStopPoint(SymPath path, LegGap[] gaps, PointF oldPt, PointF newPt)
        {
            LegGap[] newGaps            = (LegGap[])gaps.Clone();
            float    newLengthAlongPath = path.LengthToPoint(newPt);

            for (int i = 0; i < newGaps.Length; ++i)
            {
                PointF startPt = path.PointAtLength(gaps[i].distanceFromStart);
                PointF endPt   = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);

                if (Geometry.Distance(startPt, oldPt) < 0.01)
                {
                    // Moving start point of the gap.
                    newGaps[i].length           -= (newLengthAlongPath - newGaps[i].distanceFromStart);
                    newGaps[i].distanceFromStart = newLengthAlongPath;
                }
                else if (Geometry.Distance(endPt, oldPt) < 0.01)
                {
                    // Moving end point of the gap.
                    newGaps[i].length = newLengthAlongPath - gaps[i].distanceFromStart;
                }
            }

            return(newGaps);
        }
コード例 #4
0
        // Given an array of points that define a path, add a new bend into it at the "right" place where it fits.
        // The oldPoints array may be null or empty.
        public static PointF[] AddPointToArray(PointF[] oldPoints, PointF newPoint)
        {
            if (oldPoints == null || oldPoints.Length == 0)
            {
                // Simple case -- no old path.
                return(new PointF[1] {
                    newPoint
                });
            }
            else
            {
                // Complex case. We need to figure out where the newPoint goes by finding the closest point
                // on the path.
                PointF  closestPoint;
                SymPath path = new SymPath(oldPoints);
                path.DistanceFromPoint(newPoint, out closestPoint);

                // On which segment does the closest point lie?
                int segmentStart, segmentEnd;
                path.FindSegmentWithPoint(closestPoint, 0.01F, out segmentStart, out segmentEnd);

                // Insert the point in that segment.
                List <PointF> list = new List <PointF>(oldPoints);
                list.Insert(segmentEnd, newPoint);
                return(list.ToArray());
            }
        }
コード例 #5
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void GapStartStopPoints()
        {
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });

            LegGap[] gaps     = { new LegGap(1, 2), new LegGap(7, 0.5F), new LegGap(12, 2) };
            PointF[] expected = { new PointF(10, 9), new PointF(10, 7), new PointF(10, 3), new PointF(10, 2.5F), new PointF(8, 0), new PointF(6, 0) };

            PointF[] result = LegGap.GapStartStopPoints(path, gaps);
            TestUtil.TestEnumerableAnyOrder(result, expected);
        }
コード例 #6
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void AddGap1()
        {
            // Add a gap to a null gap array.
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            PointF  pt1  = new PointF(7, -2);
            PointF  pt2  = new PointF(11, 4);

            LegGap[] gaps = LegGap.AddGap(path, null, pt1, pt2);
            Assert.AreEqual(1, gaps.Length);
            Assert.AreEqual(6, gaps[0].distanceFromStart);
            Assert.AreEqual(7, gaps[0].length);
        }
コード例 #7
0
ファイル: LegGapTests.cs プロジェクト: petergolde/PurplePen
        public void AddGap1()
        {
            // Add a gap to a null gap array.
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            PointF pt1 = new PointF(7, -2);
            PointF pt2 = new PointF(11, 4);

            LegGap[] gaps = LegGap.AddGap(path, null, pt1, pt2);
            Assert.AreEqual(1, gaps.Length);
            Assert.AreEqual(6, gaps[0].distanceFromStart);
            Assert.AreEqual(7, gaps[0].length);
        }
コード例 #8
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void MoveStartStopPoint()
        {
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });

            LegGap[] gaps = { new LegGap(1, 2), new LegGap(7, 0.5F), new LegGap(12, 2) };

            LegGap[] result   = LegGap.MoveStartStopPoint(path, gaps, new PointF(8, 0), new PointF(8.5F, 0));
            LegGap[] expected = { new LegGap(1, 2), new LegGap(7, 0.5F), new LegGap(11.5F, 2.5F) };
            TestUtil.TestEnumerableAnyOrder(result, expected);

            result   = LegGap.MoveStartStopPoint(path, gaps, new PointF(10, 2.5F), new PointF(8, 2));
            expected = new LegGap[] { new LegGap(1, 2), new LegGap(7, 1F), new LegGap(12, 2) };
            TestUtil.TestEnumerableAnyOrder(result, expected);
        }
コード例 #9
0
        private void CreateLegBetweenControls(CourseView.ControlView controlView1, ControlPosition controlPosition1, CourseView.ControlView controlView2, ControlPosition controlPosition2, int splitLegIndex, ForkPosition forkStart)
        {
            List <DropTarget> dropTargets;
            SymPath           path      = PathBetweenControls(controlPosition1, controlPosition2, forkStart, out dropTargets);
            CourseObj         courseObj = new TopologyLegCourseObj(controlView1.controlId, controlView1.courseControlIds[splitLegIndex], controlView2.courseControlIds[0], courseObjRatio, appearance, path);
            CourseLayer       layer;

            if (LegInSpecificVariation(controlView1.courseControlIds[splitLegIndex], controlView2.courseControlIds[0]))
            {
                layer = courseLayerSpecificVariation;
            }
            else
            {
                layer = courseLayerAllVariationsAndParts;
            }

            courseObj.layer = layer;
            courseLayout.AddCourseObject(courseObj);

            // No drop targets between map issue and start.
            if (!(eventDB.GetControl(controlView1.controlId).kind == ControlPointKind.MapIssue &&
                  eventDB.GetControl(controlView2.controlId).kind == ControlPointKind.Start))
            {
                // Add the drop targets
                foreach (DropTarget dropTarget in dropTargets)
                {
                    courseObj = new TopologyDropTargetCourseObj(controlView1.controlId, controlView1.courseControlIds[splitLegIndex], controlView2.courseControlIds[0], courseObjRatio, appearance,
                                                                LocationFromAbstractPosition(dropTarget.abstractX, dropTarget.abstractY), dropTarget.insertionLoc);

                    // Along the selected leg, show the drop targets in light gray. Along other legs, drop targets are invisible.
                    if (controlView1.courseControlIds[splitLegIndex] == courseControlIdSelection1 && controlView2.courseControlIds.Contains(courseControlIdSelection2))
                    {
                        courseObj.layer = CourseLayer.AllVariations;
                    }
                    else
                    {
                        courseObj.layer = CourseLayer.InvisibleObjects;
                    }
                    courseLayout.AddCourseObject(courseObj);
                }
            }

            if (forkStart != null && forkStart.variationCode != '\0')
            {
                // There is a variation fork.
                courseObj = CreateVariationCode(controlView1, controlPosition1, splitLegIndex, forkStart);
                courseLayout.AddCourseObject(courseObj);
            }
        }
コード例 #10
0
        public void SetSymPath_For_CurrentUser_Should_Return_Already_Exists()
        {
            //arrange
            SymPath symPath = new SymPath(mock_environmentVariable.Object, mock_Logger.Object);

            mock_environmentVariable.Setup(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.User)).Returns(NT_SYMBOL_PATH);

            //act
            symPath.SetSymPath();

            //assert
            mock_environmentVariable.Verify(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.User), Times.Once);
            mock_environmentVariable.Verify(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.Machine), Times.Never);
            mock_environmentVariable.Verify(e => e.SetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, NT_SYMBOL_PATH), Times.Never);
        }
コード例 #11
0
        // Create a leg object from one point to another. Might return null. The controlIds can be None, but if they are supplied, then
        // they are used to handle bends. If either is null, the leg object is just straight. Gaps are never displayed.
        private static LegCourseObj CreateLegHighlight(EventDB eventDB, PointF pt1, ControlPointKind kind1, Id <ControlPoint> controlId1, PointF pt2, ControlPointKind kind2, Id <ControlPoint> controlId2, float courseObjRatio, CourseAppearance appearance)
        {
            LegGap[] gaps;

            SymPath path = CourseFormatter.GetLegPath(eventDB, pt1, kind1, controlId1, pt2, kind2, controlId2, float.NaN, courseObjRatio, appearance, out gaps);

            if (path != null)
            {
                return(new LegCourseObj(controlId1, Id <CourseControl> .None, Id <CourseControl> .None, courseObjRatio, appearance, path, null));     // We never display the gaps, because it looks dumb.
            }
            else
            {
                return(null);
            }
        }
コード例 #12
0
        public void SetSymPath_Should_Return_Successful()
        {
            //arrange
            SymPath symPath = new SymPath(mock_environmentVariable.Object, mock_Logger.Object);

            mock_environmentVariable.Setup(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.User)).Returns(String.Empty);
            mock_environmentVariable.Setup(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.Machine)).Returns(String.Empty);

            //act
            symPath.SetSymPath();

            //assert
            mock_environmentVariable.Verify(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.User), Times.Once);
            mock_environmentVariable.Verify(e => e.GetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, EnvironmentVariableTarget.Machine), Times.Once);
            mock_environmentVariable.Verify(e => e.SetEnvironmentVariable(NT_SYMBOL_VARIABLE_NAME, NT_SYMBOL_PATH), Times.Once);
        }
コード例 #13
0
        /*
         * Static functions that work on arrays of leg gaps.
         */

        // Get the start/stop points of the gaps. Primarily useful for finding where the handles should be.
        public static PointF[] GapStartStopPoints(SymPath path, LegGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
            {
                return(null);
            }

            PointF[] pts = new PointF[gaps.Length * 2];
            for (int i = 0; i < gaps.Length; ++i)
            {
                pts[i * 2]     = path.PointAtLength(gaps[i].distanceFromStart);
                pts[i * 2 + 1] = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);
            }

            return(pts);
        }
コード例 #14
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void MoveGapsToNewPath()
        {
            SymPath oldPath = new SymPath(new PointF[] { new PointF(0, 0), new PointF(10, 10) });

            LegGap[] oldGaps = { new LegGap(1, 2), new LegGap(7, 0.5F), new LegGap(12, 2) };
            SymPath  newPath = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });

            LegGap[] expected = { new LegGap(0.1F, 1.414F), new LegGap(17.88F, 1.414F) };

            LegGap[] newGaps = LegGap.MoveGapsToNewPath(oldGaps, oldPath, newPath);

            // Make sure result and expected match.
            Assert.AreEqual(expected.Length, newGaps.Length);
            for (int i = 0; i < newGaps.Length; ++i)
            {
                Assert.AreEqual(expected[i].distanceFromStart, newGaps[i].distanceFromStart, 0.01F);
                Assert.AreEqual(expected[i].length, newGaps[i].length, 0.01F);
            }
        }
コード例 #15
0
        // Add a new gap an an array of gaps. The resulting array is simplified. The original array may be null.
        public static LegGap[] AddGap(SymPath path, LegGap[] original, PointF pt1, PointF pt2)
        {
            float  dist1, dist2;
            LegGap newGap;

            LegGap[] newGaps;

            // map points to closes points on the line.
            path.DistanceFromPoint(pt1, out pt1);
            path.DistanceFromPoint(pt2, out pt2);

            // Map to distances along the line.
            dist1 = path.LengthToPoint(pt1);
            dist2 = path.LengthToPoint(pt2);

            // Create the new gap.
            if (dist1 < dist2)
            {
                newGap = new LegGap(dist1, dist2 - dist1);
            }
            else
            {
                newGap = new LegGap(dist2, dist1 - dist2);
            }

            // Add to the old gaps.
            if (original == null)
            {
                newGaps = new LegGap[1] {
                    newGap
                }
            }
            ;
            else
            {
                newGaps = new LegGap[original.Length + 1];
                Array.Copy(original, newGaps, original.Length);
                newGaps[original.Length] = newGap;
            }

            // Simplify
            return(SimplifyGaps(newGaps, path.Length));
        }
コード例 #16
0
        // Split a path into multiple paths based on an array of LegGaps.  The gaps might extend beyond the end of the
        // or the beginning of the path. The gaps array need not be in simplified form.
        public static SymPath[] SplitPathWithGaps(SymPath pathInitial, LegGap[] gaps)
        {
            // Get the length of the path.
            float pathLength = pathInitial.Length;

            // Simply and sort the gaps.
            gaps = SimplifyGaps(gaps, pathLength);

            // If no gaps length, the entire path is correct.
            if (gaps == null)
            {
                return new SymPath[1] {
                           pathInitial
                }
            }
            ;

            // Transform into start/stop distances from beginning of path.
            float[] starts = new float[gaps.Length + 1];
            float[] ends   = new float[gaps.Length + 1];
            starts[0]         = 0;
            ends[gaps.Length] = pathLength;
            for (int i = 0; i < gaps.Length; ++i)
            {
                ends[i]       = gaps[i].distanceFromStart;
                starts[i + 1] = gaps[i].distanceFromStart + gaps[i].length;
            }

            // Each 2 points is a new path.
            List <SymPath> list = new List <SymPath>(starts.Length);

            for (int i = 0; i < starts.Length; ++i)
            {
                SymPath p = pathInitial.Segment(pathInitial.PointAtLength(starts[i]), pathInitial.PointAtLength(ends[i]));
                if (p != null)
                {
                    list.Add(p);
                }
            }

            return(list.ToArray());
        }
コード例 #17
0
        public DataTargetImpl(IDataReader dataReader, IDebugClient client)
        {
            if (dataReader == null)
            {
                throw new ArgumentNullException("dataReader");
            }

            m_dataReader   = dataReader;
            m_client       = client;
            m_architecture = m_dataReader.GetArchitecture();

            var sympath = SymPath._NT_SYMBOL_PATH;

            if (string.IsNullOrEmpty(sympath))
            {
                sympath = SymPath.MicrosoftSymbolServerPath;
            }

            m_symPath = new SymPath(sympath);
        }
コード例 #18
0
        // Transform a gap array to a new path, keeping close gaps in the closest position on the new path. Remove far away gaps.
        public static LegGap[] MoveGapsToNewPath(LegGap[] oldGaps, SymPath oldPath, SymPath newPath)
        {
            oldGaps = SimplifyGaps(oldGaps, oldPath.Length);
            if (oldGaps == null)
            {
                return(null);
            }

            PointF        oldStart, oldEnd, newStart, newEnd; // ends points of the gaps
            float         distanceStart, distanceEnd;         // distance between oldStart and newStart, distance between oldEnd and newEnd.
            List <LegGap> newGaps = new List <LegGap>();

            // Move gap to a new gap by converting start and end to point, finding closest points on new path.
            // If the gap has moved too far, just remove it, else transformit.
            for (int i = 0; i < oldGaps.Length; ++i)
            {
                oldStart      = oldPath.PointAtLength(oldGaps[i].distanceFromStart);
                oldEnd        = oldPath.PointAtLength(oldGaps[i].distanceFromStart + oldGaps[i].length);
                distanceStart = newPath.DistanceFromPoint(oldStart, out newStart);
                distanceEnd   = newPath.DistanceFromPoint(oldEnd, out newEnd);

                // If the new gap is close enough to the old gap, then add the new gap.
                if (distanceStart + distanceEnd <= 2 * oldGaps[i].length)
                {
                    float newDistanceToStart = newPath.LengthToPoint(newStart);
                    float newDistanceToEnd   = newPath.LengthToPoint(newEnd);
                    if (newDistanceToStart < newDistanceToEnd)
                    {
                        newGaps.Add(new LegGap(newDistanceToStart, newDistanceToEnd - newDistanceToStart));
                    }
                    else
                    {
                        newGaps.Add(new LegGap(newDistanceToEnd, newDistanceToStart - newDistanceToEnd));
                    }
                }
            }

            // Simply the new gap array.
            return(SimplifyGaps(newGaps.ToArray(), newPath.Length));
        }
コード例 #19
0
ファイル: LegGapTests.cs プロジェクト: petergolde/PurplePen
        public void AddGap2()
        {
            // Add a gap to an existing array.
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            LegGap[] oldGaps = { new LegGap(6, 7) };
            PointF pt1 = new PointF(8, -2);
            PointF pt2 = new PointF(11, 8.5F);

            LegGap[] gaps = LegGap.AddGap(path, oldGaps, pt1, pt2);
            Assert.AreEqual(1, gaps.Length);
            Assert.AreEqual(1.5F, gaps[0].distanceFromStart);
            Assert.AreEqual(11.5F, gaps[0].length);

            pt1 = new PointF(3, -2);
            pt2 = new PointF(1.5F, 1);
            gaps = LegGap.AddGap(path, oldGaps, pt1, pt2);
            Assert.AreEqual(2, gaps.Length);
            Assert.AreEqual(6, gaps[0].distanceFromStart);
            Assert.AreEqual(7, gaps[0].length);
            Assert.AreEqual(17F, gaps[1].distanceFromStart);
            Assert.AreEqual(1.5F, gaps[1].length);
        }
コード例 #20
0
ファイル: LegGapTests.cs プロジェクト: osorensen/PurplePen
        public void AddGap2()
        {
            // Add a gap to an existing array.
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });

            LegGap[] oldGaps = { new LegGap(6, 7) };
            PointF   pt1     = new PointF(8, -2);
            PointF   pt2     = new PointF(11, 8.5F);

            LegGap[] gaps = LegGap.AddGap(path, oldGaps, pt1, pt2);
            Assert.AreEqual(1, gaps.Length);
            Assert.AreEqual(1.5F, gaps[0].distanceFromStart);
            Assert.AreEqual(11.5F, gaps[0].length);

            pt1  = new PointF(3, -2);
            pt2  = new PointF(1.5F, 1);
            gaps = LegGap.AddGap(path, oldGaps, pt1, pt2);
            Assert.AreEqual(2, gaps.Length);
            Assert.AreEqual(6, gaps[0].distanceFromStart);
            Assert.AreEqual(7, gaps[0].length);
            Assert.AreEqual(17F, gaps[1].distanceFromStart);
            Assert.AreEqual(1.5F, gaps[1].length);
        }
コード例 #21
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Draw this text symbol along a path.
        internal void DrawTextOnPath(GraphicsTarget g, SymPath path, string text, SymColor color, RenderOptions renderOpts)
        {
            if (color == null)
                return;
            if (color != fontColor && (framing.framingStyle == FramingStyle.None || color != framing.framingColor))
                return;

            if (!objectsCreated)
                CreateObjects();

            // Get the location of each grapheme to print.
            List<GraphemePlacement> graphemeList = GetLineTextGraphemePlacement(path, text);
            PointF topAscentPoint = new PointF(0, -FontAscent);    // Drawing is relative to top of char, we want to draw at baseline.

            foreach (GraphemePlacement grapheme in graphemeList) {
                object graphicsState;
                graphicsState = g.Save();

                try {
                    // Move location to draw at to the origin, set angle for drawing text.
                    Matrix matrix = GraphicsUtil.TranslationMatrix(grapheme.pointStart.X, grapheme.pointStart.Y);
                    matrix = GraphicsUtil.Multiply(GraphicsUtil.ScalingMatrix(1, -1), matrix);      // Reverse Y so text is correct way aroun
                    matrix = GraphicsUtil.Multiply(GraphicsUtil.RotationMatrix(-grapheme.angle, new PointF(0,0)), matrix);
                    g.Transform(matrix);

                    DrawStringWithEffects(g, color, grapheme.grapheme, topAscentPoint);
                }
                finally {
                    g.Restore(graphicsState);  // restore transform
                }
            }
        }
コード例 #22
0
        SymPath PathFromStartToEnd(float xStart, float yStart, float xEnd, float yEnd, bool startHorizontal, float yLoopBottom)
        {
            const float yUp = 0.45F;  // Horizontal line above end
            const float xCorner = 0.15F, yCorner = xCorner * widthUnit / heightUnit;
            const float xBez = 0.075F, yBez = xBez * widthUnit / heightUnit;

            float xDir = Math.Sign(xEnd - xStart);
            float yDir = (yEnd <= yStart) ? -1 : 1;

            yEnd -= 0.3F * yDir;
            if (startHorizontal)
            {
                xStart += 0.4F * xDir;
            }
            else
            {
                yStart += 0.3F;
            }

            SymPath path;

            if (xStart == xEnd)
            {
                path = new SymPath(new[] { LocationFromAbstractPosition(xStart, yStart), LocationFromAbstractPosition(xEnd, yEnd) });
            }
            else if (startHorizontal)
            {
                float yHoriz = yStart;
                path = new SymPath(new[] {
                    LocationFromAbstractPosition(xStart, yHoriz),
                    /* horizontal line */
                    LocationFromAbstractPosition(xEnd - xCorner * xDir, yHoriz),
                    LocationFromAbstractPosition(xEnd - xBez * xDir, yHoriz),
                    /* corner: LocationFromAbstractPosition(xEnd, yHoriz), */
                    LocationFromAbstractPosition(xEnd, yHoriz + yBez * yDir),
                    LocationFromAbstractPosition(xEnd, yHoriz + yCorner * yDir),
                    /* vertical line */
                    LocationFromAbstractPosition(xEnd, yEnd)
                },
                                   new[] { PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal });
            }
            else
            {
                float yHoriz;

                if (yDir < 0)
                {
                    yHoriz = yLoopBottom + yUp;
                    xEnd  -= 0.3F * xDir;
                }
                else
                {
                    yHoriz = yEnd - yUp;
                }

                path = new SymPath(new[] { LocationFromAbstractPosition(xStart, yStart),
                                           /* vertical line */
                                           LocationFromAbstractPosition(xStart, yHoriz - yCorner),
                                           LocationFromAbstractPosition(xStart, yHoriz - yBez),
                                           /* corner: LocationFromAbstractPosition(xStart, yHoriz), */
                                           LocationFromAbstractPosition(xStart + xBez * xDir, yHoriz),
                                           LocationFromAbstractPosition(xStart + xCorner * xDir, yHoriz),
                                           /* horizontal line */
                                           LocationFromAbstractPosition(xEnd - xCorner * xDir, yHoriz),
                                           LocationFromAbstractPosition(xEnd - xBez * xDir, yHoriz),
                                           /* corner: LocationFromAbstractPosition(xEnd, yHoriz), */
                                           LocationFromAbstractPosition(xEnd, yHoriz + yBez * yDir),
                                           LocationFromAbstractPosition(xEnd, yHoriz + yCorner * yDir),
                                           /* vertical line */
                                           LocationFromAbstractPosition(xEnd, yEnd) },
                                   new[] { PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal });
            }

            return(path);
        }
コード例 #23
0
ファイル: QueryEvent.cs プロジェクト: petergolde/PurplePen
 // Get Length of a special, in meters.
 public static float ComputeSpecialLength(EventDB eventDB, Id<Special> specialId)
 {
     Special special = eventDB.GetSpecial(specialId);
     SymPath path = new SymPath(special.locations);
     return (float)((eventDB.GetEvent().mapScale * path.Length) / 1000.0);
 }
コード例 #24
0
ファイル: SymbolDB.cs プロジェクト: osorensen/PurplePen
            // Add the stroke to an OCAD Map glyph with the given box size.
            public void AddToMapGlyph(Glyph glyph, SymColor color, float boxSize)
            {
                float scaleFactor = boxSize / 200.0F; // symbols are designed in box from -100 to 100.

                switch (kind)
                {
                case SymbolStrokes.Disc:
                    glyph.AddFilledCircle(color, new PointF(points[0].X * scaleFactor, points[0].Y * scaleFactor), radius * 2 * scaleFactor);
                    break;

                case SymbolStrokes.Circle:
                    glyph.AddCircle(color, new PointF(points[0].X * scaleFactor, points[0].Y * scaleFactor), thickness * scaleFactor, (radius * 2 + thickness) * scaleFactor);
                    break;

                case SymbolStrokes.Polyline: {
                    PointKind[] pathKinds  = new PointKind[points.Length];
                    PointF[]    pathPoints = new PointF[points.Length];
                    for (int i = 0; i < points.Length; ++i)
                    {
                        pathKinds[i]  = PointKind.Normal;
                        pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                    }
                    SymPath path = new SymPath(pathPoints, pathKinds);

                    glyph.AddLine(color, path, thickness * scaleFactor, corners, ends);
                    break;
                }

                case SymbolStrokes.Polygon: {
                    PointKind[] pathKinds  = new PointKind[points.Length + 1];
                    PointF[]    pathPoints = new PointF[points.Length + 1];
                    for (int i = 0; i < points.Length; ++i)
                    {
                        pathKinds[i]  = PointKind.Normal;
                        pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                    }
                    pathKinds[points.Length]  = pathKinds[0];
                    pathPoints[points.Length] = pathPoints[0];
                    SymPath path = new SymPath(pathPoints, pathKinds);

                    glyph.AddLine(color, path, thickness * scaleFactor, corners, corners == LineJoin.Round ? LineCap.Round : LineCap.Flat);
                    break;
                }

                case SymbolStrokes.FilledPolygon: {
                    PointKind[] pathKinds  = new PointKind[points.Length + 1];
                    PointF[]    pathPoints = new PointF[points.Length + 1];
                    for (int i = 0; i < points.Length; ++i)
                    {
                        pathKinds[i]  = PointKind.Normal;
                        pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                    }
                    pathKinds[points.Length]  = pathKinds[0];
                    pathPoints[points.Length] = pathPoints[0];
                    SymPath path = new SymPath(pathPoints, pathKinds);
                    glyph.AddArea(color, new SymPathWithHoles(path, null));
                    break;
                }

                case SymbolStrokes.PolyBezier: {
                    PointKind[] pathKinds  = new PointKind[points.Length];
                    PointF[]    pathPoints = new PointF[points.Length];
                    for (int i = 0; i < points.Length; ++i)
                    {
                        pathKinds[i]  = (i % 3 == 0) ? PointKind.Normal : PointKind.BezierControl;
                        pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                    }
                    SymPath path = new SymPath(pathPoints, pathKinds);
                    glyph.AddLine(color, path, thickness * scaleFactor, corners, ends);
                    break;
                }

                case SymbolStrokes.FilledPolyBezier: {
                    PointKind[] pathKinds  = new PointKind[points.Length];
                    PointF[]    pathPoints = new PointF[points.Length];
                    for (int i = 0; i < points.Length; ++i)
                    {
                        pathKinds[i]  = (i % 3 == 0) ? PointKind.Normal : PointKind.BezierControl;
                        pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                    }
                    SymPath path = new SymPath(pathPoints, pathKinds);
                    glyph.AddArea(color, new SymPathWithHoles(path, null));
                    break;
                }

                default:
                    Debug.Fail("Bad SymbolStroke kind");
                    break;
                }
            }
コード例 #25
0
        public void MoveGapsToNewPath()
        {
            SymPath oldPath = new SymPath(new PointF[] { new PointF(0, 0), new PointF(10, 10) });
            CircleGap[] oldGaps = new CircleGap[] { new CircleGap(1, 2), new CircleGap(7, 0.5F), new CircleGap(12, 2) };
            SymPath newPath = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            CircleGap[] expected = new CircleGap[] { new CircleGap(0.1F, 1.414F), new CircleGap(17.88F, 1.414F) };

            CircleGap[] newGaps = CircleGap.MoveGapsToNewPath(oldGaps, oldPath, newPath);

            // Make sure result and expected match.
            Assert.AreEqual(expected.Length, newGaps.Length);
            for (int i = 0; i < newGaps.Length; ++i) {
                Assert.AreEqual(expected[i].distanceFromStart, newGaps[i].distanceFromStart, 0.01F);
                Assert.AreEqual(expected[i].length, newGaps[i].length, 0.01F);
            }
        }
コード例 #26
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        private static float[] ComputeDashDistances(SymPath path, LocationKind kind, float dashLength, float firstDashLength, float lastDashLength, float gapLength, int minGaps, float offset, 
                                                                               int numEndSecGaps, float lengthEndSecGaps, int numMiddleSecGaps, float lengthMiddleSecGaps, float decreaseLimit, bool decreaseBothEnds)
        {
            // Get length of each segment, deliniated by corner points.
            PointKind[] pointkinds;
            float[] segmentLengths = path.GetCornerAndDashPointDistancesBizzarro(out pointkinds);
            float[] lengthAtEnd = new float[segmentLengths.Length];
            float[][] dashDistances = new float[segmentLengths.Length][];

            // Compute dash distances for each segment of the path.
            int totalDistances = 0;
            for (int i = 0; i < dashDistances.Length; ++i) {
                // Compute first and last lengths of the segment in question.
                float firstLength, lastLength;
                if (i != 0 && pointkinds[i] == PointKind.Dash)
                    firstLength = dashLength / 2;
                else
                    firstLength = firstDashLength;

                if (i < dashDistances.Length - 1 && pointkinds[i + 1] == PointKind.Dash)
                    lastLength = dashLength / 2;
                else
                    lastLength = lastDashLength;

                // Note that minGaps is only required on the LAST segment. This is because that the minGaps requirement is for
                // all segments together, not each segment.
                int numGaps;
                dashDistances[i] = ComputeDashDistances(segmentLengths[i], kind, dashLength, firstLength, lastLength, gapLength,
                                                        (i == dashDistances.Length - 1) ? minGaps : 0, offset, numEndSecGaps, lengthEndSecGaps, numMiddleSecGaps, lengthMiddleSecGaps, decreaseLimit, decreaseBothEnds, out lengthAtEnd[i], out numGaps);
                minGaps = Math.Max(minGaps - numGaps, 0);
                totalDistances += dashDistances[i].Length;

                // The last dash and first dash of adjacent parts merge together.
                if (kind == LocationKind.DashAndGapLengths && i > 0)
                    --totalDistances;
            }

            if (dashDistances.Length == 1) {
                return dashDistances[0];
            }

            // Combine the distances from each segment into a single array. For dash and gap lengths, combine the
            // dash lengths around segment boundaries.
            float[] distances = new float[totalDistances];

            int index = 0;
            for (int i = 0; i < dashDistances.Length; ++i) {
                Array.Copy(dashDistances[i], 0, distances, index, dashDistances[i].Length);
                if (i > 0 && dashDistances[i].Length > 0) {
                    distances[index] += lengthAtEnd[i - 1];
                }
                if (i > 0 && (dashDistances[i].Length == 0 || (kind == LocationKind.DashAndGapLengths && dashDistances[i].Length == 1)))
                    lengthAtEnd[i] += lengthAtEnd[i - 1];

                index += dashDistances[i].Length;
                if (kind == LocationKind.DashAndGapLengths)
                    --index;
            }

            if (kind == LocationKind.DashAndGapLengths)
                distances = RemoveZeroGaps(distances);

            return distances;
        }
コード例 #27
0
ファイル: OcadImport.cs プロジェクト: jonc/carto
        // Rectangle symbols may be translated into multiple symbols (if there is a grid).
        Symbol[] CreateRectangleSymbol(OcadObject obj, LineSymDef symdef, RectangleInfo rectinfo)
        {
            List<Symbol> symlist = new List<Symbol>();  // list of symbols we're creating.

            if (symdef == null)
                throw new OcadFileFormatException("Object has unknown or inconsistent symbol type {0}", obj.Sym);

            if (obj.coords == null || obj.coords.Length < 2)
                return null;

            // Create the main rectangle symbol.
            // Determine size of the rectangle, and matrix needed to transform points to their correct location.
            PointF[] pts = {PointFromOcadCoord(obj.coords[0]), PointFromOcadCoord(obj.coords[1]), PointFromOcadCoord(obj.coords[2]), PointFromOcadCoord(obj.coords[3])};
            SizeF size = new SizeF(Util.DistanceF(pts[0], pts[1]), Util.DistanceF(pts[0], pts[3]));
            float angle = Util.Angle(pts[0], pts[1]);
            Matrix matrix = new Matrix();
            matrix.Translate(pts[0].X, pts[0].Y);
            matrix.Rotate(angle);

            SymPath path;
            PointKind[] kinds;
            PointF[] pathpts;
            if (rectinfo.cornerRadius == 0) {
                kinds = new PointKind[] {PointKind.Corner, PointKind.Corner, PointKind.Corner, PointKind.Corner, PointKind.Corner};
                pathpts = new PointF[] { new PointF(0,0), new PointF(0, size.Height), new PointF(size.Width, size.Height),
                                           new PointF(size.Width, 0), new PointF(0,0)};
            }
            else {
                kinds = new PointKind[] {PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl,
                                            PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl,
                                            PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl,
                                            PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl,
                                            PointKind.Normal};
                pathpts = new PointF[] { new PointF(rectinfo.cornerRadius, 0),
                                           new PointF(size.Width - rectinfo.cornerRadius, 0),
                                           new PointF(size.Width - (1-Util.kappa) * rectinfo.cornerRadius, 0),
                                           new PointF(size.Width, (1-Util.kappa) * rectinfo.cornerRadius),
                                           new PointF(size.Width, rectinfo.cornerRadius),
                                           new PointF(size.Width, size.Height - rectinfo.cornerRadius),
                                           new PointF(size.Width, size.Height - (1-Util.kappa) * rectinfo.cornerRadius),
                                           new PointF(size.Width - (1-Util.kappa) * rectinfo.cornerRadius, size.Height),
                                           new PointF(size.Width - rectinfo.cornerRadius, size.Height),
                                           new PointF(rectinfo.cornerRadius, size.Height),
                                           new PointF((1-Util.kappa) * rectinfo.cornerRadius, size.Height),
                                           new PointF(0, size.Height - (1-Util.kappa) * rectinfo.cornerRadius),
                                           new PointF(0, size.Height - rectinfo.cornerRadius),
                                           new PointF(0, rectinfo.cornerRadius),
                                           new PointF(0, (1-Util.kappa) * rectinfo.cornerRadius),
                                           new PointF((1-Util.kappa) * rectinfo.cornerRadius, 0),
                                           new PointF(rectinfo.cornerRadius, 0)};
            }

            pathpts = GraphicsUtil.TransformPoints(pathpts, matrix);
            for (int i = 0; i < pathpts.Length; ++i)
                pathpts[i] = new PointF((float) Math.Round(pathpts[i].X, 2), (float) Math.Round(pathpts[i].Y, 2));   // round to 2 decimals, so round trip to OCAD without change.
            path = new SymPath(pathpts, kinds);
            symlist.Add(new LineSymbol(symdef, path));

            if (rectinfo.grid) {
                if (size.Width > 0 && size.Height > 0) {
                    int cxCells = (int) Math.Round(size.Width / rectinfo.cellWidth);
                    if (cxCells < 1)
                        cxCells = 1;
                    int cyCells = (int) Math.Round(size.Height / rectinfo.cellHeight);
                    if (cyCells < 1)
                        cyCells = 1;

                    float width = size.Width / cxCells;
                    float height = size.Height / cyCells;

                    CreateGridLines(size, matrix, cxCells, cyCells, width, height, rectinfo.gridLines, symlist);
                    CreateGridText(size, matrix, angle, cxCells, cyCells, width, height, rectinfo, symlist);
                }
            }

            return symlist.ToArray();
        }
コード例 #28
0
ファイル: OcadImport.cs プロジェクト: jonc/carto
        // Create the grid lines for a rectangle of the given size with given cellwidth/height and using the
        // line symdef. Transform the points by the given matrix before creating.
        void CreateGridLines(SizeF size, Matrix matrix, int cxCells, int cyCells, float width, float height, LineSymDef symdef, List<Symbol> symlist)
        {
            PointKind[] kinds = { PointKind.Normal, PointKind.Normal };
            PointF[] pts = new PointF[2];

            for (int x = 1; x < cxCells; ++x) {
                pts[0] = new PointF(x * width, 0);
                pts[1] = new PointF(x * width, size.Height);
                pts = GraphicsUtil.TransformPoints(pts, matrix);
                SymPath path = new SymPath(pts, kinds);
                symlist.Add(new LineSymbol(symdef, path));
            }

            for (int y = 1; y < cyCells; ++y) {
                pts[0] = new PointF(0, y * height);
                pts[1] = new PointF(size.Width, y * height);
                pts = GraphicsUtil.TransformPoints(pts, matrix);
                SymPath path = new SymPath(pts, kinds);
                symlist.Add(new LineSymbol(symdef, path));
            }
        }
コード例 #29
0
        public override void LeftButtonDrag(Pane pane, PointF location, PointF locationStart, float pixelSize, ref bool displayUpdateNeeded)
        {
            Debug.Assert(pane == Pane.Map);

            currentLocation = location;

            // Update the highlight.
            courseObjectDrag = ((CourseObj)courseObjectStart.Clone());
            courseObjectDrag.Offset(location.X - startDrag.X, location.Y - startDrag.Y);

            // If we're dragging a control in a course (not all controls) then add additional highlights for the leg(s) to/from the control.
            if (AreDraggingControlPoint() && courseObjectStart.courseControlId.IsNotNone)
            {
                ControlPoint control    = eventDB.GetControl(courseObjectStart.controlId);
                CourseView   courseView = selectionMgr.ActiveCourseView;

                // Find index of this course control in the course view.
                int index;
                for (index = 0; index < courseView.ControlViews.Count; ++index)
                {
                    if (courseView.ControlViews[index].courseControlIds.Contains(courseObjectStart.courseControlId))
                    {
                        break;
                    }
                }

                if (index < courseView.ControlViews.Count)
                {
                    // Get previous and next controls.
                    int prevIndex = courseView.GetPrevControl(index), nextIndex = courseView.GetNextControl(index);
                    Id <CourseControl> prevCourseControl = (prevIndex >= 0) ? courseView.ControlViews[prevIndex].courseControlIds[0] : Id <CourseControl> .None;
                    Id <CourseControl> nextCourseControl = (nextIndex >= 0) ? courseView.ControlViews[nextIndex].courseControlIds[0] : Id <CourseControl> .None;

                    // Get additional highlights to and from those controls.
                    additionalHighlights = AddControlMode.CreateLegHighlights(eventDB, ((PointCourseObj)courseObjectDrag).location, courseObjectDrag.controlId, control.kind, prevCourseControl, nextCourseControl,
                                                                              courseView.CourseObjRatio(courseObjectStart.appearance), courseObjectStart.appearance);

                    // If we're dragging the start, update the angle of the start appropriately.
                    if ((control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange || control.kind == ControlPointKind.MapIssue) &&
                        additionalHighlights.Length > 0 &&
                        (courseView.Kind == CourseView.CourseViewKind.Normal || courseView.Kind == CourseView.CourseViewKind.AllVariations))
                    {
                        SymPath  pathFromStart = ((LineCourseObj)additionalHighlights[additionalHighlights.Length - 1]).path;
                        PointF[] pts           = pathFromStart.FlattenedPoints;
                        double   angleOut      = Math.Atan2(pts[1].Y - pts[0].Y, pts[1].X - pts[0].X);
                        if (!double.IsNaN(angleOut))
                        {
                            float angleInDegrees = (float)Geometry.RadiansToDegrees(angleOut);
                            if (control.kind == ControlPointKind.MapIssue)
                            {
                                ((MapIssueCourseObj)courseObjectDrag).orientation = angleInDegrees;
                            }
                            else
                            {
                                ((StartCourseObj)courseObjectDrag).orientation = angleInDegrees;
                            }
                        }
                    }
                }
            }

            displayUpdateNeeded = true;
        }
コード例 #30
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Draw the pointy ends on a line.
        void DrawPointyEnds(GraphicsTarget g, SymPath longPath, float pointyLengthStart, float pointyLengthEnd, float lineWidth)
        {
            // Get locations of points at the tip, half-way, and base of the pointy tips.
            float length = longPath.BizzarroLength;
            float[] distances, angles;
            if (length >= pointyLengthStart + pointyLengthEnd) {
                distances = new float[6] { 0, pointyLengthStart / 2, pointyLengthStart / 2, length - pointyLengthEnd - pointyLengthStart, pointyLengthEnd / 2, pointyLengthEnd / 2 };
            }
            else {
                float scaleFactor = length / (pointyLengthStart + pointyLengthEnd);
                distances = new float[6] { 0, (pointyLengthStart / 2) * scaleFactor, (pointyLengthStart / 2) * scaleFactor, 0, (pointyLengthEnd / 2) * scaleFactor, (pointyLengthEnd / 2) * scaleFactor };
            }
            PointF[] pointsAlongPath = longPath.FindPointsAlongLineBizzarro(distances, out angles);

            // Each pointy tip is composed of a polygon of 5 points.
            PointF[] tipCorners = new PointF[5];
            float midpointWidth = lineWidth * 0.666F;  // Makes a sort of curvy tip.

            if (pointyLengthStart > 0) {
                // Draw point at beginning.
                tipCorners[0] = pointsAlongPath[0];
                tipCorners[1] = Util.MoveDistance(pointsAlongPath[1], midpointWidth / 2, angles[1] - 90.0F);
                tipCorners[4] = Util.MoveDistance(pointsAlongPath[1], midpointWidth / 2, angles[1] + 90.0F);
                tipCorners[2] = Util.MoveDistance(pointsAlongPath[2], lineWidth / 2, angles[2] - 90.0F);
                tipCorners[3] = Util.MoveDistance(pointsAlongPath[2], lineWidth / 2, angles[2] + 90.0F);
                g.FillPolygon(pointyEndsBrush, tipCorners, true);
            }

            if (pointyLengthEnd > 0) {
                // Draw point at end.
                tipCorners[0] = pointsAlongPath[5];
                tipCorners[1] = Util.MoveDistance(pointsAlongPath[4], midpointWidth / 2, angles[4] - 90.0F);
                tipCorners[4] = Util.MoveDistance(pointsAlongPath[4], midpointWidth / 2, angles[4] + 90.0F);
                tipCorners[2] = Util.MoveDistance(pointsAlongPath[3], lineWidth / 2, angles[3] - 90.0F);
                tipCorners[3] = Util.MoveDistance(pointsAlongPath[3], lineWidth / 2, angles[3] + 90.0F);
                g.FillPolygon(pointyEndsBrush, tipCorners, true);
            }
        }
コード例 #31
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        private static void DrawDashedWithOffset(GraphicsTarget g, SymPath path, Pen pen, DashInfo dashes, float offsetRight, float miterLimit, RenderOptions renderOpts)
        {
            float[] distances;

            distances = ComputeDashDistances(path, LocationKind.DashAndGapLengths, dashes.dashLength, dashes.firstDashLength, dashes.lastDashLength, dashes.gapLength, dashes.minGaps, 0, dashes.secondaryEndGaps, dashes.secondaryEndLength, dashes.secondaryMiddleGaps, dashes.secondaryMiddleLength, 1.0F, false);

            if (distances.Length == 0 || (dashes.gapLength < renderOpts.minResolution && (dashes.secondaryMiddleGaps == 0 || dashes.secondaryMiddleLength < renderOpts.minResolution) && (dashes.secondaryEndGaps == 0 || dashes.secondaryEndLength < renderOpts.minResolution))) {
                // No dashes, or the dashes are too small to be visible. Draw solid.
                if (offsetRight != 0) {
                    SymPath offsetPath = path.OffsetRight(offsetRight, miterLimit);
                    offsetPath.Draw(g, pen);
                }
                else
                    path.Draw(g, pen);
            }
            else {
                path.DrawDashedOffsetBizzarro(g, pen, distances, 0, offsetRight, miterLimit);
            }
        }
コード例 #32
0
        // Render the description into the given map at the given location in the given color.
        public void RenderToMap(Map map, SymColor color, PointF point, Dictionary<object, SymDef> dict)
        {
            IRenderer renderer = new MapRenderer(map, color, dict);

            // Set the correct transform.
            Matrix mat = new Matrix();
            mat.Scale(1, -1);      // flip Y axis.
            mat.Translate(point.X, -point.Y);
            renderer.Transform = mat;

            // White out the background.
            SizeF size = Measure();
            PointKind[] kinds = { PointKind.Normal, PointKind.Normal, PointKind.Normal, PointKind.Normal, PointKind.Normal};
            PointF[] pts = {Geometry.TransformPoint(new PointF(0, 0), mat), Geometry.TransformPoint(new PointF(size.Width, 0), mat),Geometry.TransformPoint(new PointF(size.Width, size.Height), mat),
                Geometry.TransformPoint(new PointF(0, size.Height), mat),Geometry.TransformPoint(new PointF(0, 0), mat) };
            SymPath path = new SymPath(pts, kinds);
            AreaSymbol whiteout = new AreaSymbol((AreaSymDef) dict[CourseLayout.KeyWhiteOut], new SymPathWithHoles(path, null), 0, new PointF());
            map.AddSymbol(whiteout);

            replaceMultiplySign = false;   // OCAD doesn't handle the multiple character well.
            Render(renderer, new RectangleF(-100000, -100000, 200000, 200000), 0, description.Length);
        }
コード例 #33
0
 public void DrawLine(object pen, float x1, float y1, float x2, float y2)
 {
     LineSymDef symdef = (LineSymDef) pen;
     PointKind[] kinds = {PointKind.Normal, PointKind.Normal};
     PointF[] points = { Geometry.TransformPoint(new PointF(x1, y1), currentTransform), Geometry.TransformPoint(new PointF(x2, y2), currentTransform) };
     SymPath path = new SymPath(points, kinds);
     LineSymbol symbol = new LineSymbol(symdef, path);
     map.AddSymbol(symbol);
 }
コード例 #34
0
        // Determine the path between controls, and the drop targets.
        SymPath PathBetweenControls(ControlPosition controlPosition1, ControlPosition controlPosition2, ForkPosition forkStart, out List <DropTarget> dropTargets)
        {
            float xStart = controlPosition1.x;
            float yStart = controlPosition1.y;
            float xEnd   = controlPosition2.x;
            float yEnd   = controlPosition2.y;

            dropTargets = new List <DropTarget>();

            if (forkStart != null)
            {
                if (forkStart.loopFallThru)
                {
                    dropTargets.Add(new DropTarget(xEnd, yEnd - 0.5F, LegInsertionLoc.Normal));
                }
                else if (forkStart.loopStart)
                {
                    dropTargets.Add(new DropTarget(forkStart.x, forkStart.y - 0.5F, LegInsertionLoc.Normal));
                }
                else
                {
                    dropTargets.Add(new DropTarget(xStart, yStart + 0.5F, LegInsertionLoc.PreSplit));
                    dropTargets.Add(new DropTarget(forkStart.x, forkStart.y - 0.5F, LegInsertionLoc.Normal));
                    if (forkStart.x != xEnd)
                    {
                        // Empty fork.
                        dropTargets.Add(new DropTarget(xEnd, yEnd - 0.5F, LegInsertionLoc.PostJoin));
                    }
                }
            }
            else if (xEnd != xStart)
            {
                // Below start control (use when a join is going)
                dropTargets.Add(new DropTarget(xStart, yStart + 0.5F, LegInsertionLoc.Normal));
                if (yEnd > yStart)
                {
                    // Right before join point.
                    dropTargets.Add(new DropTarget(xEnd, yEnd - 0.5F, LegInsertionLoc.PostJoin));
                }
            }
            else if (yEnd > yStart + 1.25)
            {
                // Straight down, but must have join at end.
                dropTargets.Add(new DropTarget(xStart, yStart + 0.5F, LegInsertionLoc.Normal));
                dropTargets.Add(new DropTarget(xEnd, yEnd - 0.5F, LegInsertionLoc.PostJoin));
            }
            else
            {
                // Above end control (other cases).
                dropTargets.Add(new DropTarget(xEnd, yEnd - 0.5F, LegInsertionLoc.Normal));
            }

            bool startHorizontal = false;

            if (forkStart != null)
            {
                startHorizontal = forkStart.loopStart;
            }

            if (forkStart != null && forkStart.x != controlPosition2.x)
            {
                // The fork start in a different horizontal position than it ends. This is probably due to a fork with no controls on it.
                // Create the path in two pieces.
                float   xMiddle = forkStart.x;
                float   yMiddle = forkStart.y;
                SymPath path1   = PathFromStartToEnd(xStart, yStart, xMiddle, yMiddle, startHorizontal, 0);
                SymPath path3   = PathFromStartToEnd(xMiddle, yMiddle, xEnd, yEnd, false, controlPosition2.loopBottom);
                SymPath path2   = new SymPath(new[] { path1.LastPoint, path3.FirstPoint });
                return(SymPath.Join(SymPath.Join(path1, path2, PointKind.Normal), path3, PointKind.Normal));
            }
            else
            {
                return(PathFromStartToEnd(xStart, yStart, xEnd, yEnd, startHorizontal, controlPosition2.loopBottom));
            }
        }
コード例 #35
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Calculate the bounding box
        internal RectangleF CalcBounds(SymPath path)
        {
            float thickness = maxThickness;

            // If the path has sharp mitered corners, the thickness is increased.
            if (maxMiteredThickness > 0) {
                float miterThickness = Math.Min(path.MaxMiter, GraphicsUtil.MITER_LIMIT) * maxMiteredThickness;
                if (miterThickness > thickness)
                    thickness = miterThickness;
            }

            RectangleF box = path.BoundingBox;
            box.Inflate(thickness / 2, thickness / 2);
            return box;
        }
コード例 #36
0
ファイル: OcadImport.cs プロジェクト: jonc/carto
        // Creates holes, and also closes the path (and holes)
        SymPathWithHoles CreateAreaSymPath(OcadCoord[] coords)
        {
            int numHoles;
            bool anyCutouts;

            coords = FixOcadCoords(coords, true, out numHoles, out anyCutouts);

            SymPath[] holes;
            if (numHoles > 0)
                holes = new SymPath[numHoles];
            else
                holes = null;

            SymPath path = null;

            // Pass 2: allocate the correct sizes of arrays and fill them in
            int startIndex = 0;
            int holeNumber = -1;
            for (int i = 1; i <= coords.Length; ++i) {
                if (i == coords.Length || IsOcadCoordHoleStart(coords[i])) {
                    // Found the end of the main path or hole.

                    int size = i - startIndex;
                    int arraySize = size;

                    // Make a closed path by duplicating first coord?
                    bool closed = (size <= 1 || PointFromOcadCoord(coords[i-1]) != PointFromOcadCoord(coords[startIndex]));
                    if (closed) {
                        ++arraySize;
                    }

                    PointF[] points = new PointF[arraySize];
                    PointKind[] kinds = new PointKind[arraySize];
                    byte[] startStopFlags = null;
                    if (anyCutouts)
                        startStopFlags = new byte[arraySize - 1];

                    for (int pointIndex = 0; pointIndex < size; ++pointIndex) {
                        points[pointIndex] = PointFromOcadCoord(coords[pointIndex + startIndex]);
                        kinds[pointIndex] = PointKindFromOcadCoord(coords[pointIndex + startIndex]);
                        if (startStopFlags != null && pointIndex < startStopFlags.Length)
                            startStopFlags[pointIndex] = StartStopFlagsFromCoord(coords[pointIndex + startIndex]);
                    }
                    if (closed) {
                        points[arraySize - 1] = PointFromOcadCoord(coords[startIndex]);
                        kinds[arraySize - 1] = PointKindFromOcadCoord(coords[startIndex]);
                    }

                    SymPath p = new SymPath(points, kinds, startStopFlags, closed);
                    if (holeNumber == -1)
                        path = p;
                    else
                        holes[holeNumber] = p;

                    ++holeNumber;
                    startIndex = i;
                }
            }

            return new SymPathWithHoles(path, holes);
        }
コード例 #37
0
ファイル: LegGap.cs プロジェクト: petergolde/PurplePen
        // Transform a gap array to a new path, keeping close gaps in the closest position on the new path. Remove far away gaps.
        public static LegGap[] MoveGapsToNewPath(LegGap[] oldGaps, SymPath oldPath, SymPath newPath)
        {
            oldGaps = SimplifyGaps(oldGaps, oldPath.Length);
            if (oldGaps == null)
                return null;

            PointF oldStart, oldEnd, newStart, newEnd;  // ends points of the gaps
            float distanceStart, distanceEnd;  // distance between oldStart and newStart, distance between oldEnd and newEnd.
            List<LegGap> newGaps = new List<LegGap>();

            // Move gap to a new gap by converting start and end to point, finding closest points on new path.
            // If the gap has moved too far, just remove it, else transformit.
            for (int i = 0; i < oldGaps.Length; ++i) {
                oldStart = oldPath.PointAtLength(oldGaps[i].distanceFromStart);
                oldEnd = oldPath.PointAtLength(oldGaps[i].distanceFromStart + oldGaps[i].length);
                distanceStart = newPath.DistanceFromPoint(oldStart, out newStart);
                distanceEnd = newPath.DistanceFromPoint(oldEnd, out newEnd);

                // If the new gap is close enough to the old gap, then add the new gap.
                if (distanceStart + distanceEnd <= 2 * oldGaps[i].length) {
                    float newDistanceToStart = newPath.LengthToPoint(newStart);
                    float newDistanceToEnd = newPath.LengthToPoint(newEnd);
                    if (newDistanceToStart < newDistanceToEnd)
                        newGaps.Add(new LegGap(newDistanceToStart, newDistanceToEnd - newDistanceToStart));
                    else
                        newGaps.Add(new LegGap(newDistanceToEnd, newDistanceToStart - newDistanceToEnd));
                }
            }

            // Simply the new gap array.
            return SimplifyGaps(newGaps.ToArray(), newPath.Length);
        }
コード例 #38
0
        public void GapStartStopPoints()
        {
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            CircleGap[] gaps = new CircleGap[] { new CircleGap(1, 2), new CircleGap(7, 0.5F), new CircleGap(12, 2) };
            PointF[] expected = new PointF[] { new PointF(10, 9), new PointF(10, 7), new PointF(10, 3), new PointF(10, 2.5F), new PointF(8, 0), new PointF(6, 0) };

            PointF[] result = CircleGap.GapStartStopPoints(path, gaps);
            TestUtil.TestEnumerableAnyOrder(result, expected);
        }
コード例 #39
0
ファイル: LegGap.cs プロジェクト: petergolde/PurplePen
        // Move a gap start/stop point to a new location. Return the new gap array. The gap array is NOT simplified.
        public static LegGap[] MoveStartStopPoint(SymPath path, LegGap[] gaps, PointF oldPt, PointF newPt)
        {
            LegGap[] newGaps = (LegGap[]) gaps.Clone();
            float newLengthAlongPath = path.LengthToPoint(newPt);

            for (int i = 0; i < newGaps.Length; ++i) {
                PointF startPt = path.PointAtLength(gaps[i].distanceFromStart);
                PointF endPt = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);

                if (Geometry.Distance(startPt, oldPt) < 0.01) {
                    // Moving start point of the gap.
                    newGaps[i].length -= (newLengthAlongPath - newGaps[i].distanceFromStart);
                    newGaps[i].distanceFromStart = newLengthAlongPath;
                }
                else if (Geometry.Distance(endPt, oldPt) < 0.01) {
                    // Moving end point of the gap.
                    newGaps[i].length = newLengthAlongPath - gaps[i].distanceFromStart;
                }
            }

            return newGaps;
        }
コード例 #40
0
        public void MoveStartStopPoint()
        {
            SymPath path = new SymPath(new PointF[] { new PointF(10, 10), new PointF(10, 0), new PointF(0, 0) });
            CircleGap[] gaps = new CircleGap[] { new CircleGap(1, 2), new CircleGap(7, 0.5F), new CircleGap(12, 2) };

            CircleGap[] result = CircleGap.MoveStartStopPoint(path, gaps, new PointF(8, 0), new PointF(8.5F, 0));
            CircleGap[] expected = new CircleGap[] { new CircleGap(1, 2), new CircleGap(7, 0.5F), new CircleGap(11.5F, 2.5F) };
            TestUtil.TestEnumerableAnyOrder(result, expected);

            result = CircleGap.MoveStartStopPoint(path, gaps, new PointF(10, 2.5F), new PointF(8, 2));
            expected = new CircleGap[] { new CircleGap(1, 2), new CircleGap(7, 1F), new CircleGap(12, 2) };
            TestUtil.TestEnumerableAnyOrder(result, expected);
        }
コード例 #41
0
ファイル: LegGap.cs プロジェクト: petergolde/PurplePen
        // Split a path into multiple paths based on an array of LegGaps.  The gaps might extend beyond the end of the
        // or the beginning of the path. The gaps array need not be in simplified form.
        public static SymPath[] SplitPathWithGaps(SymPath pathInitial, LegGap[] gaps)
        {
            // Get the length of the path.
            float pathLength = pathInitial.Length;

            // Simply and sort the gaps.
            gaps = SimplifyGaps(gaps, pathLength);

            // If no gaps length, the entire path is correct.
            if (gaps == null)
                return new SymPath[1] { pathInitial };

            // Transform into start/stop distances from beginning of path.
            float[] starts = new float[gaps.Length + 1];
            float[] ends = new float[gaps.Length + 1];
            starts[0] = 0;
            ends[gaps.Length] = pathLength;
            for (int i = 0; i < gaps.Length; ++i) {
                ends[i] = gaps[i].distanceFromStart;
                starts[i + 1] = gaps[i].distanceFromStart + gaps[i].length;
            }

            // Each 2 points is a new path.
            List<SymPath> list = new List<SymPath>(starts.Length);
            for (int i = 0; i < starts.Length; ++i) {
                SymPath p = pathInitial.Segment(pathInitial.PointAtLength(starts[i]), pathInitial.PointAtLength(ends[i]));
                if (p != null)
                    list.Add(p);
            }

            return list.ToArray();
        }
コード例 #42
0
ファイル: SymDef.cs プロジェクト: jonc/carto
 private static void DrawDashed(GraphicsTarget g, SymPath path, Pen pen, DashInfo dashes, RenderOptions renderOpts)
 {
     DrawDashedWithOffset(g, path, pen, dashes, 0, 1, renderOpts);
 }
コード例 #43
0
ファイル: SymbolDB.cs プロジェクト: petergolde/PurplePen
            // Add the stroke to an OCAD Map glyph with the given box size.
            public void AddToMapGlyph(Glyph glyph, SymColor color, float boxSize)
            {
                float scaleFactor = boxSize / 200.0F; // symbols are designed in box from -100 to 100.

                switch (kind) {
                case SymbolStrokes.Disc:
                    glyph.AddFilledCircle(color, new PointF(points[0].X * scaleFactor, points[0].Y * scaleFactor), radius * 2 * scaleFactor);
                    break;

                case SymbolStrokes.Circle:
                    glyph.AddCircle(color, new PointF(points[0].X * scaleFactor, points[0].Y * scaleFactor), thickness * scaleFactor, (radius * 2 + thickness) * scaleFactor);
                    break;

                case SymbolStrokes.Polyline: {
                        PointKind[] pathKinds = new PointKind[points.Length];
                        PointF[] pathPoints = new PointF[points.Length];
                        for (int i = 0; i < points.Length; ++i) {
                            pathKinds[i] = PointKind.Normal;
                            pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                        }
                        SymPath path = new SymPath(pathPoints, pathKinds);

                        glyph.AddLine(color, path, thickness * scaleFactor, corners, ends);
                        break;
                    }

                case SymbolStrokes.Polygon: {
                        PointKind[] pathKinds = new PointKind[points.Length + 1];
                        PointF[] pathPoints = new PointF[points.Length + 1];
                        for (int i = 0; i < points.Length; ++i) {
                            pathKinds[i] = PointKind.Normal;
                            pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                        }
                        pathKinds[points.Length] = pathKinds[0];
                        pathPoints[points.Length] = pathPoints[0];
                        SymPath path = new SymPath(pathPoints, pathKinds);

                        glyph.AddLine(color, path, thickness * scaleFactor, corners, corners == LineJoin.Round ? LineCap.Round : LineCap.Flat);
                        break;
                    }

                case SymbolStrokes.FilledPolygon: {
                        PointKind[] pathKinds = new PointKind[points.Length + 1];
                        PointF[] pathPoints = new PointF[points.Length + 1];
                        for (int i = 0; i < points.Length; ++i) {
                            pathKinds[i] = PointKind.Normal;
                            pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                        }
                        pathKinds[points.Length] = pathKinds[0];
                        pathPoints[points.Length] = pathPoints[0];
                        SymPath path = new SymPath(pathPoints, pathKinds);
                        glyph.AddArea(color, new SymPathWithHoles(path, null));
                        break;
                    }

                case SymbolStrokes.PolyBezier: {
                        PointKind[] pathKinds = new PointKind[points.Length];
                        PointF[] pathPoints = new PointF[points.Length];
                        for (int i = 0; i < points.Length; ++i) {
                            pathKinds[i] = (i % 3 == 0) ? PointKind.Normal : PointKind.BezierControl;
                            pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                        }
                        SymPath path = new SymPath(pathPoints, pathKinds);
                        glyph.AddLine(color, path, thickness * scaleFactor, corners, ends);
                        break;
                    }

                case SymbolStrokes.FilledPolyBezier: {
                        PointKind[] pathKinds = new PointKind[points.Length];
                        PointF[] pathPoints = new PointF[points.Length];
                        for (int i = 0; i < points.Length; ++i) {
                            pathKinds[i] = (i % 3 == 0) ? PointKind.Normal : PointKind.BezierControl;
                            pathPoints[i] = new PointF(points[i].X * scaleFactor, points[i].Y * scaleFactor);
                        }
                        SymPath path = new SymPath(pathPoints, pathKinds);
                        glyph.AddArea(color, new SymPathWithHoles(path, null));
                        break;
                    }

                default:
                    Debug.Fail("Bad SymbolStroke kind");
                    break;
                }
            }
コード例 #44
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Draw the glyphs along the path. "longPath" is the same as path unless shortening of the ends has occurred, in which case
        // path is the shortened path (used for all glyphs except start and end), and longPath is used for the start and end.
        private void DrawGlyphs(GraphicsTarget g, GlyphInfo glyphInfo, SymPath path, SymPath longPath, SymColor color, RenderOptions renderOpts)
        {
            float[] distances;
            PointF[] points;
            float[] perpAngles, subtendedAngles;
            float firstDistance;

            // Figure out the distances of the glyphs along the line.
            switch (glyphInfo.location) {
            case GlyphLocation.Corners:
                // Corner points are done somewhat differently. Only can have 1 symbol.
                // There is an interesting feature in OCAD where the dimensions of corner glyphs are stretched a certain amount at
                // very acute angles. This is so that power line crossbars always extend beyond the power lines themselves.
                // This is handled by stretching the glyph based on the subtended angle at the corner.
                points = path.FindCornerPoints(out perpAngles, out subtendedAngles);
                if (points != null) {
                    for (int i = 0; i < points.Length; ++i) {
                        float subtendedAngle = subtendedAngles[i];
                        float stretch;
                        if (subtendedAngle != 0)
                            stretch = Util.MiterFactor(subtendedAngle);
                        else
                            stretch = 1.0F;
                        stretch = Math.Min(stretch, CORNER_GLYPH_STRETCH_LIMIT);

                        Matrix stretchMatrix = new Matrix();
                        stretchMatrix.Scale(1.0F, stretch);

                        glyphInfo.glyph.Draw(g, points[i], perpAngles[i] + 90.0F, stretchMatrix, null, color, renderOpts);
                    }
                }
                return;

            case GlyphLocation.Spaced:
                distances = ComputeDashDistances(path, LocationKind.GapCenters, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.SpacedOffset:
                distances = ComputeDashDistances(path, LocationKind.GapCentersOffset, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, glyphInfo.offset, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.SpacedDecrease:
                distances = ComputeDashDistances(path, LocationKind.GapCentersDecrease, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, 0, 0, 0, 0, 0, glyphInfo.decreaseLimit, glyphInfo.decreaseBothEnds);

                if (distances != null && distances.Length > 0) {
                    firstDistance = distances[0];

                    for (int n = 0; n < glyphInfo.number; ++n) {
                        distances[0] = Math.Max(0.0F, firstDistance - ((glyphInfo.number - 1 - n * 2) * (glyphInfo.spacing / 2.0F)));

                        points = path.FindPointsAlongLineBizzarro(distances, out perpAngles);

                        for (int i = 0; i < points.Length; ++i) {
                            float decreaseFactor;
                            if (glyphInfo.decreaseBothEnds) {
                                if (points.Length <= 2)
                                    decreaseFactor = glyphInfo.decreaseLimit;
                                else
                                    decreaseFactor = 1.0F - (Math.Abs(i - ((points.Length-1) / 2F)) * (1 - glyphInfo.decreaseLimit) / ((points.Length-1) / 2F));
                            }
                            else {
                                if (i == 0)
                                    decreaseFactor = 1.0F;
                                else
                                    decreaseFactor = 1.0F - (i * (1 - glyphInfo.decreaseLimit) / (points.Length - 1));
                            }
                            Matrix matrixTransform = new Matrix();
                            matrixTransform.Scale(decreaseFactor, decreaseFactor);
                            glyphInfo.glyph.Draw(g, points[i], perpAngles[i], matrixTransform, null, color, renderOpts);
                        }
                    }
                }

                return;
            case GlyphLocation.DashCenters:
                distances = ComputeDashDistances(path, LocationKind.DashCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, dashInfo.minGaps, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.MiddleDashCenters:
                distances = ComputeDashDistances(path, LocationKind.MiddleDashCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, dashInfo.minGaps, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.GapCenters:
                // OCAD doesn't respect the "0 minimum gaps" for the symbols, although it does for the gaps. Always have at least one symbol. This is handled on import by having glyphInfo.minimum be 1.
                distances = ComputeDashDistances(path, LocationKind.GapCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, Math.Max(glyphInfo.minimum, dashInfo.minGaps), 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.Start:
                distances = new float[1] { 0 };
                break;
            case GlyphLocation.End:
                distances = new float[1] { longPath.BizzarroLength };
                break;
            default:
                Debug.Fail("bad glyph location");
                return;
            }

            if (distances == null || distances.Length == 0)
                return;
            firstDistance = distances[0];

            for (int n = 0; n < glyphInfo.number; ++n) {
                distances[0] = Math.Max(0.0F, firstDistance - ((glyphInfo.number - 1 - n * 2) * (glyphInfo.spacing / 2.0F)));

                if (glyphInfo.location == GlyphLocation.Start || glyphInfo.location == GlyphLocation.End)
                    points = longPath.FindPointsAlongLineBizzarro(distances, out perpAngles);
                else
                    points = path.FindPointsAlongLineBizzarro(distances, out perpAngles);

                for (int i = 0; i < points.Length; ++i) {
                    glyphInfo.glyph.Draw(g, points[i], perpAngles[i], GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                }
            }
        }
コード例 #45
0
ファイル: Glyph.cs プロジェクト: jonc/carto
 public void AddLine(SymColor color, SymPath path, float width, LineStyle lineStyle)
 {
     path.CheckConstructed();
     GlyphPart part = new GlyphPart();
     part.kind = GlyphPartKind.Line;
     part.color = color;
     part.lineWidth = width;
     part.path = path;
     part.lineStyle = lineStyle;
     AddGlyphPart(part);
 }
コード例 #46
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Calculate bounds of text along a path with this symbol.
        internal RectangleF CalcBounds(SymPath path, string text)
        {
            // This doesn't take into account the text at all -- just the line. It is probably good enought. We could do better
            // with a bunch of work by calling GetLineTextGraphemePlacement() and unioning the bounds of each grapheme.
            // But not that necessary.

            RectangleF rect = path.BoundingBox;
            rect.Inflate(FontAscent, FontAscent);

            if (framing.framingStyle == FramingStyle.Line)
                rect.Inflate(framing.lineWidth, framing.lineWidth);
            else if (framing.framingStyle == FramingStyle.Shadow)
                rect.Inflate(Math.Max(framing.shadowX, framing.shadowY), Math.Max(framing.shadowX, framing.shadowY));

            return rect;
        }
コード例 #47
0
        SymPath PathBetweenControls(ControlPosition controlPosition1, ControlPosition controlPosition2, ForkPosition forkStart, out PointF dropTargetPosition)
        {
            float xStart = controlPosition1.x;
            float yStart = controlPosition1.y;
            float xEnd = controlPosition2.x;
            float yEnd = controlPosition2.y;

            if (forkStart != null) {
                if (forkStart.loopFallThru) {
                    dropTargetPosition = LocationFromAbstractPosition(xEnd, yEnd - 0.5F);
                }
                else {
                    // above end of fork start.
                    dropTargetPosition = LocationFromAbstractPosition(forkStart.x, forkStart.y - 0.5F);
                }
            }
            else if (xEnd != xStart) {
                // Below start control (use when a join is going)
                dropTargetPosition = LocationFromAbstractPosition(xStart, yStart + 0.5F);
            }
            else {
                // Above end control (other cases).
                dropTargetPosition = LocationFromAbstractPosition(xEnd, yEnd - 0.5F);
            }

            bool startHorizontal = false;
            if (forkStart != null)
                startHorizontal = forkStart.loopStart;

            if (forkStart != null && forkStart.x != controlPosition2.x) {
                // The fork start in a different horizontal position than it ends. This is probably due to a fork with no controls on it.
                // Create the path in two pieces.
                float xMiddle = forkStart.x;
                float yMiddle = forkStart.y;
                SymPath path1 = PathFromStartToEnd(xStart, yStart, xMiddle, yMiddle, startHorizontal, 0);
                SymPath path3 = PathFromStartToEnd(xMiddle, yMiddle, xEnd, yEnd, false, controlPosition2.loopBottom);
                SymPath path2 = new SymPath(new[] { path1.LastPoint, path3.FirstPoint });
                return SymPath.Join(SymPath.Join(path1, path2, PointKind.Normal), path3, PointKind.Normal);
            }
            else {
                return PathFromStartToEnd(xStart, yStart, xEnd, yEnd, startHorizontal, controlPosition2.loopBottom);
            }
        }
コード例 #48
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Determine where each grapheme (essentially character) will go when drawing text along a path.
        // The algorithm for how text is laid out along a path makes sense, with one MAJOR weirdness.
        // The basic algorithm is that the width of each character to draw is determined. Starting where the last
        // character ends, the path is followed for that character width (around corners if needed), and the point along
        // the path at that point is connected to the start point of the character with a line. The character is drawn along that
        // baseline, starting at the start point. The end point is used as the start of the next character. If there are bends,
        // of course, the character won't end right at that end point, but we ignore that.
        //
        // THe weirdness is this: instead of measuring distance along the path correctly with the Pythagorian formula, a
        // strange alternate metric of dx + 1/2 dy is used, where dx is the larger ordinate delta and dy is the smaller ordinate
        // delta. Thus, text along diagonals is squished together more than it should be. I have no explanation as to why
        // this might work but it reproduces what OCAD does. See the function "BizzarroDistance" in SymPath.
        private List<GraphemePlacement> GetLineTextGraphemePlacement(SymPath path, string text)
        {
            float totalWidth = 0;
            List<GraphemePlacement> graphemeList = new List<GraphemePlacement>();
            float pathLength = path.BizzarroLength;
            if (pathLength == 0)
                return graphemeList;            // nothing to draw.

            // First, determine all the graphemes and their width
            TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(text);
            while (enumerator.MoveNext()) {
                string grapheme = enumerator.GetTextElement();
                float graphemeWidth;

                if (grapheme == " ")
                    graphemeWidth = wordSpacing * spaceWidth;
                else {
                    float width = MeasureStringWidth(grapheme);
                    graphemeWidth = width + charSpacing * spaceWidth;
                }

                graphemeList.Add(new GraphemePlacement(grapheme, graphemeWidth, new PointF(), 0));
                totalWidth += graphemeWidth;
                if (totalWidth + 0.01F >= pathLength && fontAlign != TextSymDefAlignment.Justified)
                    break;          // We don't have any room for more characters. (0.01 prevents a very small tail at the end.)
            }

            // For OCAD compatibility, truncate right aligned text if too big to fit so the whole
            // string fits. (Note that left-aligned text will typically show one more character than this.)
            if (pathLength < totalWidth && fontAlign != TextSymDefAlignment.Left && fontAlign != TextSymDefAlignment.Justified) {
                totalWidth -= graphemeList[graphemeList.Count - 1].width;
                if (fontAlign == TextSymDefAlignment.Right)
                    graphemeList.RemoveAt(graphemeList.Count - 1);
            }

            // Where does the text begin?
            float startingDistance = 0;
            if (fontAlign == TextSymDefAlignment.Left || fontAlign == TextSymDefAlignment.Justified)
                startingDistance = 0;
            else if (fontAlign == TextSymDefAlignment.Right)
                startingDistance = pathLength - totalWidth;
            else if (fontAlign == TextSymDefAlignment.Center)
                startingDistance = (pathLength - totalWidth) / 2;

            // For justified (all-line) text, adjust the widths of each character so they all fit.
            if (fontAlign == TextSymDefAlignment.Justified && graphemeList.Count > 1) {
                if (charSpacing > 0) {
                    // last character doesn't have space added.
                    GraphemePlacement graphemePlacement = graphemeList[graphemeList.Count - 1];
                    graphemePlacement.width -= charSpacing * spaceWidth;
                    totalWidth -= charSpacing * spaceWidth;
                    graphemeList[graphemeList.Count - 1] = graphemePlacement;
                }

                float adjustment = (pathLength - totalWidth) / (graphemeList.Count - 1);
                for (int i = 0; i < graphemeList.Count - 1; ++i) {
                    GraphemePlacement graphemePlacement = graphemeList[i];
                    graphemePlacement.width += adjustment;
                    graphemeList[i] = graphemePlacement;
                }
            }

            // Find points along the path that are the start/end of each grapheme.
            PointF[] points = new PointF[graphemeList.Count + 1];
            float curDistance = startingDistance;
            for (int i = 0; i < graphemeList.Count; ++i) {
                points[i] = path.PointAtLengthBizzarro(curDistance);
                curDistance += graphemeList[i].width;
            }
            points[graphemeList.Count] = path.PointAtLengthBizzarro(Math.Min(curDistance, pathLength));

            // Fill in graphemeList with start points and angles
            for (int i = 0; i < graphemeList.Count; ++i) {
                GraphemePlacement graphemePlacement = graphemeList[i];
                graphemePlacement.pointStart = points[i];
                float distX = points[i + 1].X - points[i].X;
                float distY = points[i + 1].Y - points[i].Y;
                graphemePlacement.angle = (float) (Math.Atan2(distY, distX) * 360.0 / (Math.PI * 2));
                graphemeList[i] = graphemePlacement;
            }

            return graphemeList;
        }
コード例 #49
0
        SymPath PathFromStartToEnd(float xStart, float yStart, float xEnd, float yEnd, bool startHorizontal, float yLoopBottom)
        {
            const float yUp = 0.45F;  // Horizontal line above end
            const float xCorner = 0.15F, yCorner = xCorner * widthUnit / heightUnit;
            const float xBez = 0.075F, yBez = xBez * widthUnit / heightUnit;

            float xDir = Math.Sign(xEnd - xStart);
            float yDir = (yEnd <= yStart) ? -1 : 1;

            yEnd -= 0.3F * yDir;
            if (startHorizontal) {
                xStart += 0.4F * xDir;
            }
            else {
                yStart += 0.3F;
            }

            SymPath path;
            if (xStart == xEnd) {
                path = new SymPath(new[] { LocationFromAbstractPosition(xStart, yStart), LocationFromAbstractPosition(xEnd, yEnd) });
            }
            else if (startHorizontal) {
                float yHoriz = yStart;
                path = new SymPath(new[] {
                                            LocationFromAbstractPosition(xStart, yHoriz),
                                            /* horizontal line */
                                            LocationFromAbstractPosition(xEnd - xCorner * xDir, yHoriz),
                                            LocationFromAbstractPosition(xEnd - xBez * xDir, yHoriz),
                                            /* corner: LocationFromAbstractPosition(xEnd, yHoriz), */
                                            LocationFromAbstractPosition(xEnd, yHoriz + yBez * yDir),
                                            LocationFromAbstractPosition(xEnd, yHoriz + yCorner * yDir),
                                            /* vertical line */
                                            LocationFromAbstractPosition(xEnd, yEnd) },
                                   new[] { PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal });

            }
            else {
                float yHoriz;

                if (yDir < 0) {
                    yHoriz = yLoopBottom + yUp;
                    xEnd -= 0.3F * xDir;
                }
                else {
                    yHoriz = yEnd - yUp;
                }

                path = new SymPath(new[] { LocationFromAbstractPosition(xStart, yStart),
                                            /* vertical line */
                                            LocationFromAbstractPosition(xStart, yHoriz - yCorner),
                                            LocationFromAbstractPosition(xStart, yHoriz - yBez),
                                            /* corner: LocationFromAbstractPosition(xStart, yHoriz), */
                                            LocationFromAbstractPosition(xStart + xBez * xDir, yHoriz),
                                            LocationFromAbstractPosition(xStart + xCorner * xDir, yHoriz),
                                            /* horizontal line */
                                            LocationFromAbstractPosition(xEnd - xCorner * xDir, yHoriz),
                                            LocationFromAbstractPosition(xEnd - xBez * xDir, yHoriz),
                                            /* corner: LocationFromAbstractPosition(xEnd, yHoriz), */
                                            LocationFromAbstractPosition(xEnd, yHoriz + yBez * yDir),
                                            LocationFromAbstractPosition(xEnd, yHoriz + yCorner * yDir),
                                            /* vertical line */
                                            LocationFromAbstractPosition(xEnd, yEnd) },
                                   new[] { PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal, PointKind.BezierControl, PointKind.BezierControl, PointKind.Normal, PointKind.Normal });

            }

            return path;
        }
コード例 #50
0
ファイル: SymDef.cs プロジェクト: jonc/carto
        // Draw this line symbol in the graphics along the path provided, with
        // the given color only.
        internal void Draw(GraphicsTarget g, SymPath path, SymColor color, RenderOptions renderOpts)
        {
            Debug.Assert(map != null);

            if (path.Length == 0)
                return;             // Don't draw anything for a zero-length path.

            if (!pensCreated)
                CreatePens();

            SymPath mainPath = path;  // the path for the main part of the line (might be shortened).
            if (shortenInfo.shortenBeginning > 0.0F || shortenInfo.shortenEnd > 0.0F) {
                mainPath = path.ShortenBizzarro(shortenInfo.shortenBeginning, shortenInfo.shortenEnd);
                // NOTE: mainPath can be NULL below here!!!
            }

            if (color == lineColor && thickness > 0.0F && mainPath != null) {
                if (!isDashed) {
                    // simple drawing.
                    mainPath.Draw(g, mainPen);
                }
                else {
                    // Draw the dashed line.
                    DrawDashed(g, mainPath, mainPen, dashInfo, renderOpts);
                }
            }

            // Draw the pointy ends of the line. If mainPath is null, this is all the line!
            if (color == lineColor && shortenInfo.pointyEnds && thickness > 0.0F && (shortenInfo.shortenBeginning > 0.0F || shortenInfo.shortenEnd > 0.0F))
                DrawPointyEnds(g, path, shortenInfo.shortenBeginning, shortenInfo.shortenEnd, thickness);

            if (color == secondLineColor && secondThickness > 0.0F && path != null) {
                // note that shortened path not used for secondary line, the full length path is.
                path.Draw(g, secondPen);
            }

            // Double lines don't use the shortened path, but the full-length path.
            if (isDoubleLine) {
                if (doubleLines.doubleFillColor == color) {
                    if (doubleLines.doubleFillDashed)
                        DrawDashed(g, path, doubleFillPen, doubleLines.doubleDashes, renderOpts);
                    else
                        path.Draw(g, doubleFillPen);
                }

                if (doubleLines.doubleLeftColor == color && doubleLines.doubleLeftWidth > 0.0F) {
                    foreach (SymPath subpath in path.GetSubpaths(SymPath.DOUBLE_LEFT_STARTSTOPFLAG)) {
                        float offsetRight = -(doubleLines.doubleThick + doubleLines.doubleLeftWidth) / 2F;
                        if (doubleLines.doubleLeftDashed) {
                            DrawDashedWithOffset(g, subpath, doubleLeftPen, doubleLines.doubleDashes, offsetRight, GraphicsUtil.MITER_LIMIT, renderOpts);
                        }
                        else {
                            SymPath leftPath = subpath.OffsetRight(offsetRight, GraphicsUtil.MITER_LIMIT);
                            leftPath.Draw(g, doubleLeftPen);
                        }
                    }
                }

                if (doubleLines.doubleRightColor == color && doubleLines.doubleRightWidth > 0.0F) {
                    foreach (SymPath subpath in path.GetSubpaths(SymPath.DOUBLE_RIGHT_STARTSTOPFLAG)) {
                        float offsetRight = (doubleLines.doubleThick + doubleLines.doubleRightWidth) / 2F;
                        if (doubleLines.doubleRightDashed) {
                            DrawDashedWithOffset(g, subpath, doubleRightPen, doubleLines.doubleDashes, offsetRight, GraphicsUtil.MITER_LIMIT, renderOpts);
                        }
                        else {
                            SymPath rightPath = subpath.OffsetRight(offsetRight, GraphicsUtil.MITER_LIMIT);
                            rightPath.Draw(g, doubleRightPen);
                        }
                    }
                }
            }

            if (glyphs != null && mainPath != null) {
                foreach (GlyphInfo glyphInfo in glyphs) {
                    if (glyphInfo.glyph.HasColor(color))
                        DrawGlyphs(g, glyphInfo, mainPath, path, color, renderOpts);
                }
            }
        }
コード例 #51
0
ファイル: LegGap.cs プロジェクト: petergolde/PurplePen
        /*
         * Static functions that work on arrays of leg gaps.
         */
        // Get the start/stop points of the gaps. Primarily useful for finding where the handles should be.
        public static PointF[] GapStartStopPoints(SymPath path, LegGap[] gaps)
        {
            if (gaps == null || gaps.Length == 0)
                return null;

            PointF[] pts = new PointF[gaps.Length * 2];
            for (int i = 0; i < gaps.Length; ++i) {
                pts[i * 2] = path.PointAtLength(gaps[i].distanceFromStart);
                pts[i * 2 + 1] = path.PointAtLength(gaps[i].distanceFromStart + gaps[i].length);
            }

            return pts;
        }