예제 #1
0
파일: Symbol.cs 프로젝트: jonc/carto
 // Draw this color, if used, of this symbol.
 public abstract void Draw(GraphicsTarget g, SymColor color, RenderOptions renderOpts);
예제 #2
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw the pattern using the texture brush.
        void DrawPatternWithTexBrush(GraphicsTarget g, SymPathWithHoles path, float angle, SymColor color, RenderOptions renderOpts)
        {
            Brush brush = (Brush) patternBrushes[color];
            Debug.Assert(brush != null);

            if (angle != 0.0F) {
                object graphicsState = g.Save();

                try {
                    // Set the clipping region to draw only inside the area.
                    g.SetClip(path);

                    // use a transform to rotate.
                    Matrix matrix = GraphicsUtil.RotationMatrix(angle, new PointF(0, 0));
                    g.Transform(matrix);

                    // Get the correct bounding rect.
                    RectangleF bounding = Util.BoundsOfRotatedRectangle(path.BoundingBox, new PointF(), -angle);

                    g.FillRectangle(brush, bounding);
                }
                finally {
                    // restore the clip region and the transform
                    g.Restore(graphicsState);
                }
            }
            else {
                path.Fill(g, brush);
            }
        }
예제 #3
0
파일: SymDef.cs 프로젝트: jonc/carto
        void CreatePatternBrush(float pixelSize)
        {
            //  Determine adjusted pixel size of the brush to create.
            const float MAX_PATTERN_SIZE = 80;
            const float MIN_PATTERN_SIZE = 10;
            if (pixelSize < patternWidth / MAX_PATTERN_SIZE)
                pixelSize = patternWidth / MAX_PATTERN_SIZE;
            if (pixelSize < patternHeight / MAX_PATTERN_SIZE)
                pixelSize = patternHeight / MAX_PATTERN_SIZE;
            if (pixelSize > patternWidth / MIN_PATTERN_SIZE)
                pixelSize = patternWidth / MIN_PATTERN_SIZE;
            if (pixelSize > patternHeight / MIN_PATTERN_SIZE)
                pixelSize = patternHeight / MIN_PATTERN_SIZE;

            if (patternBrushes != null && Math.Abs(pixelSize - pixelSizeCached) / pixelSize < 0.01)
                return;         // the pattern brush is already OK size.

            // Get size of bitmap to create with the image of the pattern.
            float width = (float) Math.Round(patternWidth / pixelSize);
            float height = (float) Math.Round(patternHeight / pixelSize);

            // Create dictionary to hold brushes for each color.
            patternBrushes = new Dictionary<SymColor, Brush>(2);
            pixelSizeCached = pixelSize;

            RenderOptions renderOpts = new RenderOptions();
            renderOpts.minResolution = pixelSize;
            renderOpts.usePatternBitmaps = false;

            foreach (SymColor color in map.colors) {
                if (!patternGlyph.HasColor(color))
                    continue;

                // Create a new bitmap and fill it transparent.
                Bitmap bitmap = new Bitmap((int) width, (int) (offsetRows ? height * 2 : height));
                Graphics g = Graphics.FromImage(bitmap);
                g.CompositingMode = CompositingMode.SourceCopy;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, bitmap.Width, bitmap.Height);

                // Set the center of the bitmap to 0,0, and scale to mm (each pixel is 0.01 mm).
                g.TranslateTransform(width / 2.0F, height / 2.0F);
                g.ScaleTransform(width / patternWidth, height / patternHeight);

                // Draw the pattern into the bitmap.
                GraphicsTarget grTarget = new GraphicsTarget(g);
                patternGlyph.Draw(grTarget, new PointF(0F, 0F), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);

                if (offsetRows) {
                    patternGlyph.Draw(grTarget, new PointF(patternWidth / 2, patternHeight), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                    patternGlyph.Draw(grTarget, new PointF(-patternWidth / 2, patternHeight), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                }

                // Create a TextureBrush on the bitmap.
                TextureBrush brush = new TextureBrush(bitmap);

                // Scale and the texture brush.
                brush.RotateTransform(patternAngle);
                brush.ScaleTransform(patternWidth / width, patternHeight / height);
                brush.TranslateTransform(-width / 2.0F, -height / 2.0F);

                // Dispose of the graphics.
                g.Dispose();

                // Add it to the collection of brushes.
                patternBrushes.Add(color, brush);
            }
        }
예제 #4
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw the hatching into the interior of the SymPath.
        void DrawHatching(GraphicsTarget g, SymPathWithHoles path, float angle, RenderOptions renderOpts)
        {
            object graphicsState = g.Save();

            try {
                // Set the clipping region to draw only inside the area.
                g.SetClip(path);

                // use a transform to rotate and then draw hatching.
                Matrix matrix = GraphicsUtil.RotationMatrix(hatchAngle1 + angle, new PointF(0, 0));
                g.Transform(matrix);

                // Get the correct bounding rect.
                RectangleF bounding = Util.BoundsOfRotatedRectangle(path.BoundingBox, new PointF(), -(hatchAngle1 + angle));

                DrawHatchLines(g, hatchPen, hatchSpacing, bounding, renderOpts);

                // and again for the second bound of hatching
                if (hatchMode == 2) {
                    // Get the correct bounding rect.
                    bounding = Util.BoundsOfRotatedRectangle(path.BoundingBox, new PointF(), -(hatchAngle2 + angle));

                    matrix = GraphicsUtil.RotationMatrix(hatchAngle2 - hatchAngle1, new PointF(0, 0));
                    g.Transform(matrix);
                    DrawHatchLines(g, hatchPen, hatchSpacing, bounding, renderOpts);
                }
            }
            finally {
                // restore the clip region and the transform
                g.Restore(graphicsState);
            }
        }
예제 #5
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw the pattern (at the given angle) inside the path.
        void DrawPattern(GraphicsTarget g, SymPathWithHoles path, float angle, SymColor color, RenderOptions renderOpts)
        {
            object graphicsState = g.Save();

            try {
                // Set the clipping region to draw only inside the area.
                g.SetClip(path);

                // use a transform to rotate
                Matrix matrix = GraphicsUtil.RotationMatrix(patternAngle + angle, new PointF(0, 0));
                g.Transform(matrix);

                // Get the correct bounding rect.
                RectangleF bounding = Util.BoundsOfRotatedRectangle(path.BoundingBox, new PointF(), -(patternAngle + angle));

                DrawPatternRows(g, bounding, color, renderOpts);
            }
            finally {
                // restore the clip region and the transform
                g.Restore(graphicsState);
            }
        }
예제 #6
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw this area symbol in the graphics inside/around the path provided, with
        // the given color only.
        internal void Draw(GraphicsTarget g, SymPathWithHoles path, SymColor color, float angle, RenderOptions renderOpts)
        {
            if (!pensAndBrushesCreated)
                CreatePensAndBrushes();

            if (color == fillColor) {
                path.Fill(g, color.Brush);
            }

            if (hatchMode != 0 && hatchColor == color) {
                DrawHatching(g, path, angle, renderOpts);
            }

            if (drawPattern && patternGlyph.HasColor(color)) {
                // Faster to draw the pattern with a texture brush that has a bitmap
                // of the pattern in it. Better quality to do it all with glyph drawing.
                // Choose based on the renderOptions.
            #if false
                DrawPatternWithTexBrush(g, path, angle, color, renderOpts);
            #else
                if (renderOpts.usePatternBitmaps) {
                    CreatePatternBrush(renderOpts.minResolution);
                    DrawPatternWithTexBrush(g, path, angle, color, renderOpts);
                }
                else
                    DrawPattern(g, path, angle, color, renderOpts);
            #endif
            }

            // Draw the border. Take into account the subpaths defined by start/stop flags along the paths.
            if (borderSymdef != null && borderSymdef.HasColor(color)) {
                // Draw main part of border.
                foreach (SymPath subpath in path.MainPath.GetSubpaths(SymPath.AREA_BOUNDARY_STARTSTOPFLAG))
                    borderSymdef.Draw(g, subpath, color, renderOpts);

                // Draw the holes.
                if (path.Holes != null)
                    foreach (SymPath hole in path.Holes)
                        foreach (SymPath subpath in hole.GetSubpaths(SymPath.AREA_BOUNDARY_STARTSTOPFLAG))
                            borderSymdef.Draw(g, subpath, color, renderOpts);
            }
        }
예제 #7
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw a string with shadow or line framing effects, if specified. The font from this symdef is used.
        private void DrawStringWithEffects(GraphicsTarget g, SymColor color, string text, PointF pt)
        {
            if (color == fontColor) {
                DrawSingleLineString(g, text, fontColor.Brush, pt);
            }

            if (framing.framingStyle != FramingStyle.None && color == framing.framingColor) {
                if (framing.framingStyle == FramingStyle.Line) {
            #if false
                    FormattedText formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black);
                    Geometry geometry = formattedText.BuildGeometry(new Point(pt.X, pt.Y));
                    foreach (Pen p in framingPens)
                        g.DrawingContext.DrawGeometry(null, p, geometry);
            #else
                    GraphicsPath grPath = new GraphicsPath(FillMode.Winding);
                    Debug.Assert(font.Unit == GraphicsUnit.World);
                    grPath.AddString(text, font.FontFamily, (int) font.Style, font.Size, pt, stringFormat);

                    foreach (Pen p in framingPens)
                        g.Graphics.DrawPath(p, grPath);
            #endif
                }
                else if (framing.framingStyle == FramingStyle.Shadow) {
                    DrawSingleLineString(g, text, framing.framingColor.Brush, new PointF(pt.X + framing.shadowX, pt.Y - framing.shadowY));
                }
            }
        }
예제 #8
0
파일: Map.cs 프로젝트: jonc/carto
        // Draw a particular color layer. If curColor is null, draw the image layer.
        private void DrawColor(GraphicsTarget g, SymColor curColor, RectangleF rect, bool clipRegionIsRectangle, RenderOptions renderOpts)
        {
            foreach (SymDef symdef in symdefs) {
                if (IsSymdefVisible(symdef) && symdef.HasColor(curColor)) {
                    foreach (Symbol curSym in symdef.symbols) {
                        // Only draw the symbol if it may intersect. Check
                        // the bounding box first as it's faster exclusion than MayIntersectRect.
                        RectangleF bounds = curSym.BoundingBox;
                        if (bounds.IntersectsWith(rect) &&
            #if true
                            (clipRegionIsRectangle || g.Graphics.IsVisible(Util.InflateRect(bounds, renderOpts.minResolution))) &&
            #endif
                            curSym.MayIntersectRect(rect))
                        {
                            curSym.Draw(g, curColor, renderOpts);

                            if (renderOpts.showSymbolBounds)
                                g.DrawRectangle(boundsPen, bounds);
                        }
                    }
                }
            }

            //TraceLine("Drawing color {0}: drew {1} of {2} symbols.", curColor, cDrawn, cSymbols);
        }
예제 #9
0
파일: Map.cs 프로젝트: jonc/carto
        public void Draw(DrawingContext dc, RectangleF rect, RenderOptions renderOpts)
        {
            CheckReadable();

            TraceLine("Begin drawing rectangle ({0},{1})-({2},{3})", rect.Left, rect.Top, rect.Right, rect.Bottom);
            Trace.Indent();

            GraphicsTarget grTarget = new GraphicsTarget(dc);

            if (renderOpts.showSymbolBounds)
                boundsPen = GraphicsUtil.CreateSolidPen(Color.FromArgb(100, 255, 0, 0), 0.01F, LineStyle.Mitered);

            // Draw the image layer.
            DrawColor(grTarget, null, rect, true, renderOpts);

            // Draw each color separately, to get correct layering.
            foreach (SymColor curColor in colors) {
                DrawColor(grTarget, curColor, rect, true, renderOpts);
            }

            if (renderOpts.showSymbolBounds)
                GraphicsUtil.DisposePen(boundsPen);

            Trace.Unindent();
        }
예제 #10
0
파일: Glyph.cs 프로젝트: jonc/carto
        void DrawSimple(GraphicsTarget g, PointF pt, RenderOptions renderOpts)
        {
            Debug.Assert(parts.Length == 1);
            Debug.Assert(parts[0].kind == GlyphPartKind.Circle || parts[0].kind == GlyphPartKind.FilledCircle);
            Debug.Assert(parts[0].point.X == 0.0F && parts[0].point.Y == 0.0F);

            if (parts[0].kind == GlyphPartKind.Circle) {
                if (parts[0].lineWidth > 0 && parts[0].circleDiam > 0) {
                    if (parts[0].pen == null)
                        parts[0].pen = GraphicsUtil.CreateSolidPen(parts[0].color.ColorValue, parts[0].lineWidth, LineStyle.Mitered);
                    float radius = (parts[0].circleDiam - parts[0].lineWidth) / 2;
                    g.DrawEllipse(parts[0].pen, pt, radius, radius);
                }
            }
            else {
             	// filled circle
                if (parts[0].circleDiam > 0) {
                    float radius = parts[0].circleDiam / 2;
                    g.FillEllipse(parts[0].color.Brush, pt, radius, radius);
                }
            }
        }
예제 #11
0
파일: Glyph.cs 프로젝트: jonc/carto
            // Draw this glyph part. gaps is used only for Circle parts, and is a set of gaps in the circle in degrees.
            public void Draw(GraphicsTarget g, float[] gaps, RenderOptions renderOpts)
            {
                float radius;

                switch (kind) {
                case GlyphPartKind.Line:
                    if (lineWidth > 0 && path.Length > 0) {
                        if (pen == null) {
                            pen = GraphicsUtil.CreateSolidPen(color.ColorValue, lineWidth, lineStyle);
                        }
                        path.Draw(g, pen);
                    }
                    break;

                case GlyphPartKind.Area:
                    areaPath.Fill(g, color.Brush);
                    break;

                case GlyphPartKind.Circle:
                    if (lineWidth > 0 && circleDiam > lineWidth) {
                        if (pen == null) {
                            pen = GraphicsUtil.CreateSolidPen(color.ColorValue, lineWidth, LineStyle.Mitered);
                        }

                        radius = (circleDiam - lineWidth) / 2;
                        if (gaps == null || gaps.Length == 0) {
                            g.DrawEllipse(pen, point, radius, radius);
                        }
                        else {
                            // There are gaps in the circle. The arcs to draw are from end of one gap to start of the next.
                            RectangleF rect = new RectangleF(point.X - radius, point.Y - radius, radius * 2, radius * 2);
                            for (int i = 1; i < gaps.Length; i += 2) {
                                float startArc = gaps[i];
                                float endArc = (i == gaps.Length - 1) ? gaps[0] : gaps[i + 1];
                #if false
                                Point ptStart = new Point(Math.Cos(startArc * Math.PI / 180.0) * radius, Math.Sin(startArc * Math.PI / 180.0) * radius);
                                Point ptEnd = new Point(Math.Cos(endArc * Math.PI / 180.0) * radius, Math.Sin(endArc * Math.PI / 180.0) * radius);
                                ArcSegment segment = new ArcSegment(ptEnd, new Size(radius, radius), 0, ((endArc - startArc + 360.0) % 360.0) > 180.0, SweepDirection.Clockwise, true);
                                PathFigure figure = new PathFigure(ptStart, new PathSegment[] { segment }, false);
                                PathGeometry geometry = new PathGeometry(new PathFigure[] { figure });
                                g.DrawingContext.DrawGeometry(null, pen, geometry);
                #else
                                g.Graphics.DrawArc(pen, rect, startArc, (float) ((endArc - startArc + 360.0) % 360.0));
                #endif
                            }
                        }
                    }
                    break;

                case GlyphPartKind.FilledCircle:
                    if (circleDiam > 0) {
                        radius = circleDiam / 2;
                        g.FillEllipse(color.Brush, point, radius, radius);
                    }
                    break;
                }
            }
예제 #12
0
파일: Glyph.cs 프로젝트: jonc/carto
        internal void Draw(GraphicsTarget g, PointF pt, float angle, Matrix extraTransform, float[] gaps, SymColor color, RenderOptions renderOpts)
        {
            Debug.Assert(constructed);

            if (! simple || gaps != null || !extraTransform.IsIdentity) {
                object graphicsState = null;
                for (int i = 0; i < parts.Length; ++i) {
                    if (parts[i].color == color) {
                        // Establish transformation matrix.
                        if (graphicsState == null) {
                            graphicsState = g.Save();

                            Matrix matrix = GraphicsUtil.Multiply(GraphicsUtil.RotationMatrix(angle, new PointF(0,0)), GraphicsUtil.TranslationMatrix(pt.X, pt.Y));
                            if (extraTransform != null)
                                matrix = GraphicsUtil.Multiply(extraTransform, matrix);

                            g.Transform(matrix);
                        }
                        parts[i].Draw(g, gaps, renderOpts);
                    }
                }

                if (graphicsState != null)
                    g.Restore(graphicsState);
            }
            else if (color == parts[0].color) {
                DrawSimple(g, pt, renderOpts);
            }
        }
예제 #13
0
파일: Symbol.cs 프로젝트: jonc/carto
 // Draw this color, if used, of this symbol.
 public override void Draw(GraphicsTarget g, SymColor color, RenderOptions renderOpts)
 {
     def.Draw(g, path, color, angle, renderOpts);
 }
예제 #14
0
파일: Symbol.cs 프로젝트: jonc/carto
 // Draw this color, if used, of this symbol.
 public override void Draw(GraphicsTarget g, SymColor color, RenderOptions renderOpts)
 {
     def.Draw(g, wrappedText, wrappedLineWidths, adjustedLocation, rotation, width, color, renderOpts);
 }
예제 #15
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
                }
            }
        }
예제 #16
0
파일: Map.cs 프로젝트: jonc/carto
        // Draw the elements of the map that lie within the rectange rect
        // into the Graphics g, which already has its world coordinates set up
        // correctly and the clipping region.
        public void Draw(Graphics g, RectangleF rect, RenderOptions renderOpts)
        {
            CheckReadable();

            TraceLine("Begin drawing rectangle ({0},{1})-({2},{3})", rect.Left, rect.Top, rect.Right, rect.Bottom);
            Trace.Indent();

            GraphicsState graphicsState = g.Save();
            GraphicsTarget grTarget = new GraphicsTarget(g);
            try {
                // Get clipping region and bounding rectangle. If the clipping region isn't a rectangle,
                // then it is worth doing extra work to eliminate symbols.
                // UNDONE: clipRegionIsRectangle is given false on full repaint. Need to fix this.
                Region clipRegion;
                rect.Intersect(g.ClipBounds);
                clipRegion = g.Clip.Clone();
                clipRegion.Xor(rect);
                bool clipRegionIsRectangle = clipRegion.IsEmpty(g);
                clipRegion.Dispose();

                g.TextRenderingHint = TextRenderingHint.AntiAlias;

                if (renderOpts.showSymbolBounds)
                    boundsPen = new Pen(Color.FromArgb(100, Color.Red), 0);

                // Draw the image layer.
                DrawColor(grTarget, null, rect, clipRegionIsRectangle, renderOpts);

                // Draw each color separately, to get correct layering.
                foreach (SymColor curColor in colors) {
                    DrawColor(grTarget, curColor, rect, clipRegionIsRectangle, renderOpts);
                }

                if (renderOpts.showSymbolBounds)
                    boundsPen.Dispose();

                Trace.Unindent();
            }
            finally {
                g.Restore(graphicsState);
            }
        }
예제 #17
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw the framing rectangle around some text. The top of the text is at 0, and the bottom baseline of text is at "bottomOfText".
        private void DrawFramingRectangle(GraphicsTarget g, float[] lineWidths, float fullWidth, SymColor color, float bottomOfText)
        {
            if (framing.framingStyle == FramingStyle.Rectangle && color == framing.framingColor) {
                // First, figure out the width of the rectangle. If fullWidth is zero, used the maximum line width.
                fullWidth = CalcFullWidth(lineWidths, fullWidth);

                // Next, figure out the rectangle, not counting padding.
                float l, t, r, b;
                if (fontAlign == TextSymDefAlignment.Right)
                    l = -fullWidth;
                else if (fontAlign == TextSymDefAlignment.Center)
                    l = -(fullWidth / 2F);
                else
                    l = 0;
                r = l + fullWidth;
                t = FontAscent - WHeight;           // Place the top of the rectangle at top of letter "W", not top of accents.
                b = bottomOfText;

                // Add padding.
                t -= framing.rectBorderTop;
                b += framing.rectBorderBottom;
                l -= framing.rectBorderLeft;
                r += framing.rectBorderRight;

                // Draw the rectangle
                g.FillRectangle(color.Brush, new RectangleF(l, t, r - l, b - t));
            }
        }
예제 #18
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);
 }
예제 #19
0
파일: SymDef.cs 프로젝트: jonc/carto
 // Draw a single line of text at the given point with the given brush.
 private void DrawSingleLineString(GraphicsTarget g, string text, Brush brush, PointF pt)
 {
     #if false
     FormattedText formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, fontSize, brush);
     g.DrawingContext.DrawText(formattedText, new Point(pt.X, pt.Y));
     #else
     // Occasonal GDI+ throws an exception if the font size is super small.
     try {
         g.Graphics.DrawString(text, font, brush, pt, stringFormat);
     }
     catch (System.Runtime.InteropServices.ExternalException) {
         // Do nothing
     }
     #endif
 }
예제 #20
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);
            }
        }
예제 #21
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw an underline under the text, if applicable.
        private void DrawUnderline(GraphicsTarget g, SymColor color, float baseline, float width, float indent)
        {
            if (underline.underlineOn && color == underline.underlineColor) {
                // Figure out the left and right sides of the underline.
                float l, r;
                if (fontAlign == TextSymDefAlignment.Right)
                    l = -width;
                else if (fontAlign == TextSymDefAlignment.Center)
                    l = -(width / 2F);
                else
                    l = indent;
                r = l + width;

                // figure out y coordinate of line.
                float y = baseline + underline.underlineDistance + underline.underlineWidth / 2;

                // draw the line.
                g.DrawLine(underlinePen, new PointF(l, y), new PointF(r, y));
            }
        }
예제 #22
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);
                }
            }
        }
예제 #23
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw a set of horizontal hatching lines at the given spacing with
        // the given pen. A line should be centered on the zero y coordinate.
        void DrawHatchLines(GraphicsTarget g, Pen pen, float spacing, RectangleF boundingRect, RenderOptions renderOpts)
        {
            double firstLine = Math.Round(boundingRect.Top / spacing) * spacing;
            double lastLine = (Math.Round(boundingRect.Bottom / spacing) + 0.5) * spacing;

            for (double y = firstLine; y <= lastLine; y += spacing) {
                g.DrawLine(pen, new PointF(boundingRect.Left, (float) y), new PointF(boundingRect.Right, (float) y));
            }
        }
예제 #24
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);
            }
        }
예제 #25
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw a set of rows of the pattern with the given rectangle
        void DrawPatternRows(GraphicsTarget g, RectangleF boundingRect, SymColor color, RenderOptions renderOpts)
        {
            double topLine = Math.Round(boundingRect.Top / patternHeight) * patternHeight;
            double bottomLine = (Math.Round(boundingRect.Bottom / patternHeight) + 0.5) * patternHeight;
            double leftLine = Math.Round(boundingRect.Left / patternWidth) * patternWidth;
            double rightLine = (Math.Round(boundingRect.Right / patternWidth) + 0.5) * patternWidth;
            double offsetLeftLine = leftLine - (patternWidth / 2);
            double offsetRightLine = rightLine + (patternWidth / 2);
            bool firstLineOffset = ((long) Math.Round(boundingRect.Top / patternHeight) & 1) != 0;

            bool offsetThisLine = offsetRows && firstLineOffset;
            for (double y = topLine; y <= bottomLine; y += patternHeight) {
                if (offsetThisLine) {
                    for (double x = offsetLeftLine; x <= offsetRightLine; x += patternWidth) {
                        patternGlyph.Draw(g, new PointF((float) x, (float) y), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                    }
                }
                else {
                    for (double x = leftLine; x <= rightLine; x += patternWidth) {
                        patternGlyph.Draw(g, new PointF((float) x, (float) y), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                    }
                }

                if (offsetRows)
                    offsetThisLine = !offsetThisLine;
            }
        }
예제 #26
0
파일: SymDef.cs 프로젝트: jonc/carto
 // Draw this point symbol at point pt with angle ang in this graphics (given color only).
 internal void Draw(GraphicsTarget g, PointF pt, float angle, float[] gaps, SymColor color, RenderOptions renderOpts)
 {
     glyph.Draw(g, pt, angle, GraphicsUtil.IdentityMatrix, gaps, color, renderOpts);
 }
예제 #27
0
파일: SymDef.cs 프로젝트: jonc/carto
        void CreatePatternBrush()
        {
            patternBrushes = new Dictionary<SymColor, Brush>(2);

            foreach (SymColor color in map.colors) {
                if (!patternGlyph.HasColor(color))
                    continue;

                RenderOptions renderOpts = new RenderOptions();
                renderOpts.minResolution = 0.001F;
                renderOpts.usePatternBitmaps = false;

                // Create a visual with the glyph to tile in it.
                DrawingVisual visual = new DrawingVisual();
                DrawingContext dc = visual.RenderOpen();
                GraphicsTarget grTarget = new GraphicsTarget(dc);

                patternGlyph.Draw(grTarget, new PointF(0F, 0F), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                if (offsetRows) {
                    patternGlyph.Draw(grTarget, new PointF(patternWidth / 2, patternHeight), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                    patternGlyph.Draw(grTarget, new PointF(-patternWidth / 2, patternHeight), -patternAngle, GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                }

                dc.Close();

                // Get a drawing from the drawingvisual
                Drawing drawing = visual.Drawing;
                drawing.Freeze();

                // Create a brush from the drawing.
                DrawingBrush brush = new DrawingBrush(drawing);
                brush.Stretch = Stretch.Fill;
                brush.TileMode = TileMode.Tile;
                brush.ViewboxUnits = BrushMappingMode.Absolute;
                brush.ViewportUnits = BrushMappingMode.Absolute;
                if (offsetRows)
                    brush.Viewbox = brush.Viewport = new Rect(-patternWidth / 2, -patternHeight / 2, patternWidth, patternHeight * 2);
                else
                    brush.Viewbox = brush.Viewport = new Rect(-patternWidth / 2, -patternHeight / 2, patternWidth, patternHeight);
                brush.Transform = new RotateTransform(patternAngle);

                // Set the minimum and maximum relative sizes for regenerating the tiled brush.
                // The tiled brush will be regenerated when the size is
                //   0.5x, 0.25x (and so forth)
                // and
                //   2x, 4x, 8x (and so forth)
                // of the original size.
                System.Windows.Media.RenderOptions.SetCacheInvalidationThresholdMinimum(brush, 0.5);
                System.Windows.Media.RenderOptions.SetCacheInvalidationThresholdMaximum(brush, 2.0);

                // Set the caching hint option for the brush.
                System.Windows.Media.RenderOptions.SetCachingHint(brush, CachingHint.Cache);

                // Freeze the brush.
                brush.Freeze();

                // Add it to the collection of brushes.
                patternBrushes.Add(color, brush);
            }
        }
예제 #28
0
파일: SymDef.cs 프로젝트: jonc/carto
        // Draw this text symbol at point pt with angle ang in this graphics (given color only).
        internal void Draw(GraphicsTarget g, string[] text, float[] lineWidths, PointF location, float angle,  float fullWidth, SymColor color, RenderOptions renderOpts)
        {
            if (color == null)
                return;
            if (color != fontColor && (framing.framingStyle == FramingStyle.None || color != framing.framingColor) && (!underline.underlineOn || color != underline.underlineColor))
                return;

            if (!objectsCreated)
                CreateObjects();

            // Move location to draw at to the origin.
            object graphicsState = g.Save();

            Matrix matrix = GraphicsUtil.TranslationMatrix(location.X, location.Y);
            matrix = GraphicsUtil.Multiply(GraphicsUtil.ScalingMatrix(1, -1), matrix); // Reverse Y direction so text is correct way around.
            if (angle != 0)
                matrix = GraphicsUtil.Multiply(GraphicsUtil.RotationMatrix(-angle, new PointF(0,0)), matrix);
            g.Transform(matrix);

            try {
                // Draw all the lines of text.
                PointF pt = new PointF(0F, 0F);
                float baselineOfLine = 0;          // y coordinate of baseline of line.
                bool firstLineOfPara = true, lastLineOfPara;
                for (int lineIndex = 0; lineIndex < text.Length; ++lineIndex) {
                    string line = text[lineIndex];
                    float lineWidth = lineWidths[lineIndex];

                    lastLineOfPara = (lineIndex == text.Length - 1 || text[lineIndex + 1] == ParagraphMark);        // are we on the last line of a paragraph?

                    if (line == ParagraphMark) {
                        pt.Y += paraSpacing;
                        firstLineOfPara = true;
                    }
                    else {
                        float indent = 0;
                        float leftEdge;          // tabs are relative to this X position.
                        if (fontAlign == TextSymDefAlignment.Right)
                            pt.X = leftEdge = -lineWidth;
                        else if (fontAlign == TextSymDefAlignment.Center)
                            pt.X = leftEdge = -(lineWidth / 2F);
                        else {
                            leftEdge = 0;
                            pt.X = indent = firstLineOfPara ? firstIndent : restIndent;     // indents only used for left align or justified
                        }

                        // Get the size of spaces. Justification is done by adjusting this.
                        float sizeOfSpace = wordSpacing * spaceWidth;            // basic width of spaces as set by the symdef
                        if (fontAlign == TextSymDefAlignment.Justified && !lastLineOfPara && fullWidth > 0)
                            sizeOfSpace += JustifyText(line, lineWidth, fullWidth - indent);

                        // Draw all the text segments in the line. (A text segment is a word, unless charSpacing>0, in which case it is graphemes).
                        int index = 0;
                        for (; ; ) {
                            string textSegment;

                            if (charSpacing > 0)
                                textSegment = StringInfo.GetNextTextElement(line.Substring(index));
                            else
                                textSegment = GetNextTextSegment(line.Substring(index));
                            if (string.IsNullOrEmpty(textSegment))
                                break;

                            if (textSegment == " ")
                                pt.X += sizeOfSpace;
                            else if (textSegment == "\t")
                                pt.X += WidthOfTextSegment("\t", pt.X - leftEdge);
                            else {
                                DrawStringWithEffects(g, color, textSegment, pt);
                                pt.X += MeasureStringWidth(textSegment);

                                if (charSpacing > 0)
                                    pt.X += charSpacing * spaceWidth;
                            }

                            index += textSegment.Length;
                        }

                        baselineOfLine = pt.Y + FontAscent;        // Set the bottom of the text.

                        if (lastLineOfPara)
                            DrawUnderline(g, color, baselineOfLine, Math.Max(fullWidth, lineWidth), (fullWidth == 0) ? indent : 0);

                        pt.Y += lineSpacing;
                        firstLineOfPara = false;
                    }
                }

                // Draw the framing rectangle, if any.
                if (underline.underlineOn)
                    baselineOfLine += underline.underlineDistance + underline.underlineWidth;
                DrawFramingRectangle(g, lineWidths, fullWidth, color, baselineOfLine);
            }
            finally {
                g.Restore(graphicsState);
            }
        }
예제 #29
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);
                }
            }
        }
예제 #30
0
파일: Symbol.cs 프로젝트: jonc/carto
 // Draw this color, if used, of this symbol.
 public override void Draw(GraphicsTarget g, SymColor color, RenderOptions renderOpts)
 {
     def.Draw(g, location, rotation, gaps, color, renderOpts);
 }