public void Paint(Graphics graphics, IDrawingSurface layer, ITile iTile, bool isPrint) { if (!m_enabled) { return; } //LibSys.StatusBar.Trace("Track::Paint() - " + m_trackpoints.Count + " : " + Name); int prevX = 0; int prevY = 0; int arrowWingsTrk = Math.Max(15, (int)(7.0f * TrackPalette.penTrackThickness)); int arrowWingsRte = Math.Max(18, (int)(9.0f * TrackPalette.penRouteThickness)); float trackThicknessFactor = TrackPalette.penTrackThickness / 2.0f; Pen penHighlight = new Pen(Color.Red, 3.0f * trackThicknessFactor); Pen penHighlight2 = new Pen(Color.Yellow, 3.0f * trackThicknessFactor); int diam = (int)Math.Ceiling(4.0f * trackThicknessFactor); int rad = diam / 2; Waypoint _lastHighlightedWaypoint = null; int step = getStep(this, layer.getCameraElevation()); bool doDrawPoints = Project.drawTrackpoints && (layer.getCameraElevation() < DRAW_POINT_TRESHOLD); int pointCount = 0; int lastArrowCount = 0; // Point tailPoint = Point.Empty; Point lastArrowPoint = Point.Empty; // prepare default brushes/pens, with either random or preset color: Brush trkBrush = getBrush(); // filled circles, arrow heads Pen trkPen = getTrackPen(); // lines Pen rtePen = getRoutePen(); // lines Pen rteTrkPen; // square (flat) Cap is a pain in neck; this kind of works: GraphicsPath objPath = new GraphicsPath(); // objPath.AddRectangle(new Rectangle(0, -1, 0, 0)); CustomLineCap squareCap = new System.Drawing.Drawing2D.CustomLineCap(objPath, null, LineCap.Flat); squareCap.WidthScale = 0.0f; bool skipOne; for (int i = 0; i < m_trackpoints.Count; i += step) { skipOne = false; try { Waypoint wp1 = (Waypoint)m_trackpoints.GetByIndex(i); bool doDrawThisPoint = doDrawPoints; if (wp1.ThumbImage != null) { skipOne = true; // draw and move to next trackpoint; keep in sync with the stepping logic } pointCount++; Waypoint wp2 = null; if (i != m_trackpoints.Count - 1 && (i + step) < m_trackpoints.Count) // last point { wp2 = (Waypoint)m_trackpoints.GetByIndex(i + step); } if (!layer.insideScreenRectangle(wp1.Location) && wp2 != null && !layer.insideScreenRectangle(wp2.Location)) { goto nextLoop; } Point p1 = isPrint ? layer.toPixelLocationPrint(wp1.Location, iTile) : layer.toPixelLocation(wp1.Location, iTile); // if(tailPoint.IsEmpty) // { // tailPoint = p1; // } int dd = diam; bool staying = false; bool doHighlight = false; bool hasContent = wp1.hasContent; bool hasUrl = wp1.Url != null && wp1.Url.Length > 0; string stayLbl = ""; if (TimeFilter.Enabled) { doHighlight = TimeFilter.passes(wp1.DateTime); if (!doHighlight && TimeFilter.beforeFrom(wp1.DateTime)) { // in case it doesn't pass directly, but we are in the middle of the track // and the time filter boundaries are between this point and next point, // we highlight both points because we are sitting there at this time. if (i > 0 && wp2 != null) // mid-track { if (TimeFilter.afterTo(wp2.DateTime)) { doHighlight = true; dd *= 3; staying = true; DateTime wp2LocalTime = Project.zuluToLocal(wp2.DateTime); stayLbl = "staying till " + wp2LocalTime.TimeOfDay; } } } } if (SelectFilter.Enabled) { doHighlight = SelectFilter.passes(wp1); dd = 2; } if (doHighlight) { if (_lastHighlightedWaypoint == null) { _lastHighlightedWaypoint = wp1; } graphics.DrawEllipse(penHighlight, p1.X - dd, p1.Y - dd, dd * 2, dd * 2); if (staying) { int x = p1.X + 10; int y = p1.Y - dd * 2; Font font = Project.getLabelFont(Project.FONT_SIZE_REGULAR + 2); if (Project.waypointUseShadow) { graphics.DrawString(stayLbl, font, Project.blackBrush, x, y); graphics.DrawString(stayLbl, font, Project.blackBrush, x + 2, y); graphics.DrawString(stayLbl, font, Project.blackBrush, x, y - 2); graphics.DrawString(stayLbl, font, Project.blackBrush, x + 2, y - 2); } graphics.DrawString(stayLbl, font, Project.whiteBrush, x + 1, y - 1); } } if (hasUrl) { graphics.DrawEllipse(penHighlight2, p1.X - 4, p1.Y - 4, 8, 8); } if (hasContent) { if (!hasUrl) { graphics.DrawEllipse(Pens.Cyan, p1.X - 4, p1.Y - 4, 8, 8); } graphics.DrawEllipse(penHighlight, p1.X - 2, p1.Y - 2, 4, 4); } if (hasUrl || hasContent || (wp2 == null && (i == 0 || !Project.makeRouteMode))) // last point { int offsetX = 0; int offsetY = 0; if (isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wp1.Location, null); Point pixelPosDispl = wp1.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wp1.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); } if (wp2 != null) // not the last point { Point p2 = isPrint ? layer.toPixelLocationPrint(wp2.Location, iTile) : layer.toPixelLocation(wp2.Location, iTile); bool thickPen = false; if (m_isRoute) { rteTrkPen = rtePen; } else { if (Project.trackElevColor) { double elevRange = ElevMax - ElevMin; if (elevRange > 1.0d && elevRange < 20000.0d) { double elevFactor = elevRange / 256.0d; double elev = wp2.Location.Elev; int r = (int)((elev - ElevMin) / elevFactor); if (r > 255) { r = 255; } int b = 255 - r; int g = (255 - (r > b ? r : b)) * 2; // will be high where R and B are close to equal, amounts to cyan Color legColor = Color.FromArgb(r, g, b); trkBrush = new SolidBrush(legColor); trkPen = new Pen(trkBrush, (r > 250 ? 5.0f : 3.0f) * trackThicknessFactor); thickPen = true; } } else if (Project.trackSpeedColor) { double speedRange = SpeedMax - SpeedMin; if (speedRange > 1000.0d && speedRange < 1000000000.0d) { double speedFactor = speedRange / 256.0d; double speed = wp2.Speed; int r = (int)((speed - SpeedMin) / speedFactor); if (r > 255) { r = 255; } int b = 255 - r; int g = (255 - (r > b ? r : b)) * 2; // will be high where R and B are close to equal, amounts to cyan Color legColor = Color.FromArgb(r, g, b); trkBrush = new SolidBrush(legColor); trkPen = new Pen(trkBrush, (r > 250 ? 5.0f : 3.0f) * trackThicknessFactor); thickPen = true; } } rteTrkPen = doHighlight ? penHighlight : trkPen; } int dltaX = p2.X - p1.X; int dltaY = p2.Y - p1.Y; double lenSq = dltaX * dltaX + dltaY * dltaY; int dlta2X = p2.X - lastArrowPoint.X; int dlta2Y = p2.Y - lastArrowPoint.Y; double lenSq2 = dlta2X * dlta2X + dlta2Y * dlta2Y; if (lenSq2 > 10000.0d || lenSq > 900.0d) // big enough to hold arrow? { float arrowWidth = thickPen ? 4 : 3; float arrowHeight = 6; bool arrowFill = true; rteTrkPen.CustomEndCap = new AdjustableArrowCap(arrowWidth, arrowHeight, arrowFill); lastArrowCount = pointCount; lastArrowPoint = p2; // tailPoint = p2; //doDrawThisPoint = false; } else { // no cap - null doesn't work here rteTrkPen.CustomEndCap = squareCap; } graphics.DrawLine(rteTrkPen, p1, p2); if (doDrawThisPoint && diam > 2) { graphics.FillEllipse(trkBrush, p2.X - rad, p2.Y - rad, diam, diam); } if (i == 0) { int offsetX = 0; int offsetY = 0; if (isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wp1.Location, null); Point pixelPosDispl = wp1.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wp1.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); prevX = p1.X; prevY = p1.Y; } else if ((p1.X - prevX) * (p1.X - prevX) + (p1.Y - prevY) * (p1.Y - prevY) > 900) { if (Project.showTrackpointNumbers) { // call simplified PaintLabel, not regular one: PaintLabel(graphics, wp1.Name, p1.X, p1.Y, isPrint); } prevX = p1.X; prevY = p1.Y; } } else if (doDrawThisPoint) { graphics.FillEllipse(trkBrush, p1.X - rad, p1.Y - rad, diam, diam); } } catch (Exception e) { LibSys.StatusBar.Error("Track::Paint() - " + e.Message); } nextLoop: if (skipOne) { i -= (step - 1); // move to the next trackpoint continue; } int pointsLeft = m_trackpoints.Count - i; if (pointsLeft > 1 && pointsLeft < step) { step = pointsLeft - 2; if (step < 1) { step = 1; } } } if (Project.thumbDoDisplay) { SortedList ppts = Project.mainCommand.getWaypointsWithThumbs(m_id); for (int i = 0; i < ppts.Count; i++) { Waypoint wpt = (Waypoint)ppts.GetByIndex(i); Pen thumbBorderPen = Pens.Blue; Pen thumbCornerPen = new Pen(Color.Blue, 3.0f); int width = wpt.ThumbImage.Width; int height = wpt.ThumbImage.Height; Point p1 = isPrint ? layer.toPixelLocationPrint(wpt.Location, iTile) : layer.toPixelLocation(wpt.Location, iTile); switch (wpt.ThumbPosition) { case 0: // top right graphics.DrawImage(wpt.ThumbImage, p1.X, p1.Y - height, width, height); graphics.DrawRectangle(thumbBorderPen, p1.X, p1.Y - height, width - 1, height - 1); graphics.DrawLine(thumbCornerPen, p1.X + 2, p1.Y, p1.X + 2, p1.Y - 10); graphics.DrawLine(thumbCornerPen, p1.X, p1.Y - 2, p1.X + 10, p1.Y - 2); break; case 1: // center default: graphics.DrawImage(wpt.ThumbImage, p1.X - width / 2, p1.Y - height / 2, width, height); graphics.DrawRectangle(thumbBorderPen, p1.X - width / 2, p1.Y - height / 2, width - 1, height - 1); break; } int offsetX = 0; int offsetY = 0; if (isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wpt.Location, null); Point pixelPosDispl = wpt.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wpt.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); } } if (_lastHighlightedWaypoint != null) { lastHighlightedWaypoint = _lastHighlightedWaypoint; } }
public void Paint(Graphics graphics, IDrawingSurface layer, ITile iTile, bool isPrint) { if(!m_enabled) { return; } //LibSys.StatusBar.Trace("Track::Paint() - " + m_trackpoints.Count + " : " + Name); int prevX = 0; int prevY = 0; int arrowWingsTrk = Math.Max(15, (int)(7.0f * TrackPalette.penTrackThickness)); int arrowWingsRte = Math.Max(18, (int)(9.0f * TrackPalette.penRouteThickness)); float trackThicknessFactor = TrackPalette.penTrackThickness / 2.0f; Pen penHighlight = new Pen(Color.Red, 3.0f * trackThicknessFactor); Pen penHighlight2 = new Pen(Color.Yellow, 3.0f * trackThicknessFactor); int diam = (int)Math.Ceiling(4.0f * trackThicknessFactor); int rad = diam/2; Waypoint _lastHighlightedWaypoint = null; int step = getStep(this, layer.getCameraElevation()); bool doDrawPoints = Project.drawTrackpoints && (layer.getCameraElevation() < DRAW_POINT_TRESHOLD); int pointCount = 0; int lastArrowCount = 0; // Point tailPoint = Point.Empty; Point lastArrowPoint = Point.Empty; // prepare default brushes/pens, with either random or preset color: Brush trkBrush = getBrush(); // filled circles, arrow heads Pen trkPen = getTrackPen(); // lines Pen rtePen = getRoutePen(); // lines Pen rteTrkPen; // square (flat) Cap is a pain in neck; this kind of works: GraphicsPath objPath = new GraphicsPath(); // objPath.AddRectangle(new Rectangle(0, -1, 0, 0)); CustomLineCap squareCap = new System.Drawing.Drawing2D.CustomLineCap(objPath, null, LineCap.Flat); squareCap.WidthScale = 0.0f; bool skipOne; for(int i=0; i < m_trackpoints.Count ;i+=step) { skipOne = false; try { Waypoint wp1 = (Waypoint)m_trackpoints.GetByIndex(i); bool doDrawThisPoint = doDrawPoints; if(wp1.ThumbImage != null) { skipOne = true; // draw and move to next trackpoint; keep in sync with the stepping logic } pointCount++; Waypoint wp2 = null; if(i != m_trackpoints.Count-1 && (i + step) < m_trackpoints.Count) // last point { wp2 = (Waypoint)m_trackpoints.GetByIndex(i+step); } if(!layer.insideScreenRectangle(wp1.Location) && wp2 != null && !layer.insideScreenRectangle(wp2.Location)) { goto nextLoop; } Point p1 = isPrint ? layer.toPixelLocationPrint(wp1.Location, iTile) : layer.toPixelLocation(wp1.Location, iTile); // if(tailPoint.IsEmpty) // { // tailPoint = p1; // } int dd = diam; bool staying = false; bool doHighlight = false; bool hasContent = wp1.hasContent; bool hasUrl = wp1.Url != null && wp1.Url.Length > 0; string stayLbl = ""; if(TimeFilter.Enabled) { doHighlight = TimeFilter.passes(wp1.DateTime); if(!doHighlight && TimeFilter.beforeFrom(wp1.DateTime)) { // in case it doesn't pass directly, but we are in the middle of the track // and the time filter boundaries are between this point and next point, // we highlight both points because we are sitting there at this time. if(i > 0 && wp2 != null) // mid-track { if(TimeFilter.afterTo(wp2.DateTime)) { doHighlight = true; dd *= 3; staying = true; DateTime wp2LocalTime = Project.zuluToLocal(wp2.DateTime); stayLbl = "staying till " + wp2LocalTime.TimeOfDay; } } } } if(SelectFilter.Enabled) { doHighlight = SelectFilter.passes(wp1); dd = 2; } if(doHighlight) { if(_lastHighlightedWaypoint == null) { _lastHighlightedWaypoint = wp1; } graphics.DrawEllipse(penHighlight, p1.X-dd, p1.Y-dd, dd*2, dd*2); if(staying) { int x = p1.X + 10; int y = p1.Y - dd*2; Font font = Project.getLabelFont(Project.FONT_SIZE_REGULAR + 2); if(Project.waypointUseShadow) { graphics.DrawString(stayLbl, font, Project.blackBrush, x, y); graphics.DrawString(stayLbl, font, Project.blackBrush, x+2, y); graphics.DrawString(stayLbl, font, Project.blackBrush, x, y-2); graphics.DrawString(stayLbl, font, Project.blackBrush, x+2, y-2); } graphics.DrawString(stayLbl, font, Project.whiteBrush, x+1, y-1); } } if(hasUrl) { graphics.DrawEllipse(penHighlight2, p1.X-4, p1.Y-4, 8, 8); } if(hasContent) { if(!hasUrl) { graphics.DrawEllipse(Pens.Cyan, p1.X-4, p1.Y-4, 8, 8); } graphics.DrawEllipse(penHighlight, p1.X-2, p1.Y-2, 4, 4); } if(hasUrl || hasContent || (wp2 == null && (i==0 || !Project.makeRouteMode))) // last point { int offsetX = 0; int offsetY = 0; if(isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wp1.Location, null); Point pixelPosDispl = wp1.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wp1.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); } if(wp2 != null) // not the last point { Point p2 = isPrint ? layer.toPixelLocationPrint(wp2.Location, iTile) : layer.toPixelLocation(wp2.Location, iTile); bool thickPen = false; if(m_isRoute) { rteTrkPen = rtePen; } else { if(Project.trackElevColor) { double elevRange = ElevMax - ElevMin; if(elevRange > 1.0d && elevRange < 20000.0d) { double elevFactor = elevRange / 256.0d; double elev = wp2.Location.Elev; int r = (int)((elev - ElevMin) / elevFactor); if(r > 255) { r = 255; } int b = 255 - r; int g = (255 - (r > b ? r : b)) * 2; // will be high where R and B are close to equal, amounts to cyan Color legColor = Color.FromArgb(r, g, b); trkBrush = new SolidBrush(legColor); trkPen = new Pen(trkBrush, (r > 250 ? 5.0f : 3.0f) * trackThicknessFactor); thickPen = true; } } else if(Project.trackSpeedColor) { double speedRange = SpeedMax - SpeedMin; if(speedRange > 1000.0d && speedRange < 1000000000.0d) { double speedFactor = speedRange / 256.0d; double speed = wp2.Speed; int r = (int)((speed - SpeedMin) / speedFactor); if(r > 255) { r = 255; } int b = 255 - r; int g = (255 - (r > b ? r : b)) * 2; // will be high where R and B are close to equal, amounts to cyan Color legColor = Color.FromArgb(r, g, b); trkBrush = new SolidBrush(legColor); trkPen = new Pen(trkBrush, (r > 250 ? 5.0f : 3.0f) * trackThicknessFactor); thickPen = true; } } rteTrkPen = doHighlight ? penHighlight : trkPen; } int dltaX = p2.X - p1.X; int dltaY = p2.Y - p1.Y; double lenSq = dltaX * dltaX + dltaY * dltaY; int dlta2X = p2.X - lastArrowPoint.X; int dlta2Y = p2.Y - lastArrowPoint.Y; double lenSq2 = dlta2X * dlta2X + dlta2Y * dlta2Y; if(lenSq2 > 10000.0d || lenSq > 900.0d) // big enough to hold arrow? { float arrowWidth = thickPen ? 4 : 3; float arrowHeight = 6; bool arrowFill = true; rteTrkPen.CustomEndCap = new AdjustableArrowCap(arrowWidth, arrowHeight, arrowFill); lastArrowCount = pointCount; lastArrowPoint = p2; // tailPoint = p2; //doDrawThisPoint = false; } else { // no cap - null doesn't work here rteTrkPen.CustomEndCap = squareCap; } graphics.DrawLine(rteTrkPen, p1, p2); if(doDrawThisPoint && diam > 2) { graphics.FillEllipse(trkBrush, p2.X-rad, p2.Y-rad, diam, diam); } if(i == 0) { int offsetX = 0; int offsetY = 0; if(isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wp1.Location, null); Point pixelPosDispl = wp1.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wp1.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); prevX = p1.X; prevY = p1.Y; } else if((p1.X - prevX)*(p1.X - prevX) + (p1.Y - prevY)*(p1.Y - prevY) > 900) { if(Project.showTrackpointNumbers) { // call simplified PaintLabel, not regular one: PaintLabel(graphics, wp1.Name, p1.X, p1.Y, isPrint); } prevX = p1.X; prevY = p1.Y; } } else if(doDrawThisPoint) { graphics.FillEllipse(trkBrush, p1.X-rad, p1.Y-rad, diam, diam); } } catch (Exception e) { LibSys.StatusBar.Error("Track::Paint() - " + e.Message); } nextLoop: if(skipOne) { i -= (step - 1); // move to the next trackpoint continue; } int pointsLeft = m_trackpoints.Count - i; if(pointsLeft > 1 && pointsLeft < step) { step = pointsLeft - 2; if(step < 1) { step = 1; } } } if(Project.thumbDoDisplay) { SortedList ppts = Project.mainCommand.getWaypointsWithThumbs(m_id); for (int i=0; i < ppts.Count ;i++) { Waypoint wpt = (Waypoint)ppts.GetByIndex(i); Pen thumbBorderPen = Pens.Blue; Pen thumbCornerPen = new Pen(Color.Blue, 3.0f); int width = wpt.ThumbImage.Width; int height = wpt.ThumbImage.Height; Point p1 = isPrint ? layer.toPixelLocationPrint(wpt.Location, iTile) : layer.toPixelLocation(wpt.Location, iTile); switch(wpt.ThumbPosition) { case 0: // top right graphics.DrawImage(wpt.ThumbImage, p1.X, p1.Y-height, width, height); graphics.DrawRectangle(thumbBorderPen, p1.X, p1.Y-height, width-1, height-1); graphics.DrawLine(thumbCornerPen, p1.X+2, p1.Y, p1.X+2, p1.Y-10); graphics.DrawLine(thumbCornerPen, p1.X, p1.Y-2, p1.X+10, p1.Y-2); break; case 1: // center default: graphics.DrawImage(wpt.ThumbImage, p1.X-width/2, p1.Y-height/2, width, height); graphics.DrawRectangle(thumbBorderPen, p1.X-width/2, p1.Y-height/2, width-1, height-1); break; } int offsetX = 0; int offsetY = 0; if(isPrint) { Point pixelPosPrint = layer.toPixelLocationPrint(wpt.Location, null); Point pixelPosDispl = wpt.PixelLocation; offsetX = pixelPosPrint.X - pixelPosDispl.X; offsetY = pixelPosPrint.Y - pixelPosDispl.Y; } wpt.PaintLabel(graphics, layer, iTile, isPrint, offsetX, offsetY); } } if(_lastHighlightedWaypoint != null) { lastHighlightedWaypoint = _lastHighlightedWaypoint; } }