public void Draw(Microsoft.Xna.Framework.Graphics.GraphicsDevice graphicsDevice, VikingXNA.Scene scene, Microsoft.Xna.Framework.Graphics.Texture BackgroundLuma, Microsoft.Xna.Framework.Graphics.Texture BackgroundColors, ref int nextStencilValue) { /// <summary> /// Steps: /// Find all the locations for a section. This could be optimized to return only visible sections immediately with a better data structure /// Filter out invisible locations /// Draw the backgrounds /// Draw the overlapping linked locations over the backgrounds /// Draw the structure links /// Draw the labels /// </summary> /// <param name="graphicsDevice"></param> /// <param name="scene"></param> /// <param name="BackgroundLuma"></param> /// <param name="BackgroundColors"></param> /// <param name="nextStencilValue"></param> if(_Parent.Section == null) return; if (_Parent.spriteBatch.GraphicsDevice.IsDisposed) return; Matrix ViewProjMatrix = scene.Camera.View * scene.Projection; GridRectangle Bounds = scene.VisibleWorldBounds; nextStencilValue++; if (basicEffect == null) basicEffect = new BasicEffect(graphicsDevice); else if(basicEffect.IsDisposed) basicEffect = new BasicEffect(graphicsDevice); VikingXNA.AnnotationOverBackgroundLumaEffect overlayEffect = Parent.annotationOverlayEffect; overlayEffect.LumaTexture = BackgroundLuma; overlayEffect.RenderTargetSize = graphicsDevice.Viewport; basicEffect.Alpha = 1; RasterizerState OriginalRasterState = graphicsDevice.RasterizerState; SectionLocationsViewModel currentSectionAnnotations = CurrentSectionAnnotations; Debug.Assert(currentSectionAnnotations != null); int SectionNumber = _Parent.Section.Number; float Time = (float)TimeSpan.FromTicks(DateTime.Now.Ticks - DateTime.Today.Ticks).TotalSeconds; // Debug.WriteLine("Time: " + Time.ToString()); IncrementDepthStencilValue(graphicsDevice, ref nextStencilValue); //Get all the lines to draw first so the text and geometric shapes are over top of them LocationLink[] VisibleLinks = linksView.VisibleLocationLinks(_Parent.Section.Number, Bounds); foreach (LocationLink link in VisibleLinks) { DrawLocationLink(link, ViewProjMatrix); } graphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, float.MaxValue, 0); IncrementDepthStencilValue(graphicsDevice, ref nextStencilValue); //graphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, float.MaxValue, 0); //IncrementDepthStencilValue(graphicsDevice, ref nextStencilValue); ICollection<Location_CanvasViewModel> Locations = currentSectionAnnotations.GetLocations(); List<Location_CanvasViewModel> listLocationsToDraw = FindVisibleLocations(Locations, Bounds); //Find a circle that encloses the visible bounds GridCircle VisibleCircle = new GridCircle(Bounds.Center, GridVector2.Distance(Bounds.Center, new GridVector2(Bounds.Left, Bounds.Top))); List<Location_CanvasViewModel> RefLocations = new List<Location_CanvasViewModel>(); if(_Parent.Section.ReferenceSectionBelow != null) { SectionLocationsViewModel sectionLocations = GetAnnotationsForSection(_Parent.Section.ReferenceSectionBelow.Number); if (sectionLocations != null) RefLocations.AddRange(sectionLocations.GetLocations());//(Bounds)); } if(_Parent.Section.ReferenceSectionAbove != null) { SectionLocationsViewModel sectionLocations = GetAnnotationsForSection(_Parent.Section.ReferenceSectionAbove.Number); if (sectionLocations != null) { RefLocations.AddRange(sectionLocations.GetLocations()); } } //Draw text for locations on the reference sections List<Location_CanvasViewModel> listVisibleNonOverlappingLocationsOnAdjacentSections = FindVisibleLocations(RefLocations, Bounds); List<Location_CanvasViewModel> listVisibleOverlappingLocationsOnAdjacentSections = RemoveOverlappingLocations(listVisibleNonOverlappingLocationsOnAdjacentSections, _Parent.Section.Number); //Draw all of the locations on the current section WebAnnotation.LocationObjRenderer.DrawBackgrounds(listLocationsToDraw, graphicsDevice, basicEffect, overlayEffect, scene, SectionNumber); IncrementDepthStencilValue(graphicsDevice, ref nextStencilValue); graphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, float.MaxValue, 0); WebAnnotation.LocationObjRenderer.DrawBackgrounds(listVisibleNonOverlappingLocationsOnAdjacentSections, graphicsDevice, basicEffect, overlayEffect, scene, SectionNumber); IncrementDepthStencilValue(graphicsDevice, ref nextStencilValue); graphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, float.MaxValue, 0); WebAnnotation.LocationObjRenderer.DrawOverlappedAdjacentLinkedLocations(listLocationsToDraw, scene, graphicsDevice, basicEffect, overlayEffect, SectionNumber); TryDrawLineFromOverlappingLocation(AnnotationOverlay.LastMouseOverObject as OverlappedLocation, _Parent.LineManager, _Parent.Section.Number, Time); if (defaultBlendState == null || defaultBlendState.IsDisposed) { defaultBlendState = new BlendState(); defaultBlendState.AlphaBlendFunction = BlendFunction.Add; defaultBlendState.AlphaSourceBlend = Blend.SourceAlpha; defaultBlendState.AlphaDestinationBlend = Blend.DestinationAlpha; defaultBlendState.ColorSourceBlend = Blend.SourceColor; defaultBlendState.ColorDestinationBlend = Blend.DestinationColor; defaultBlendState.ColorBlendFunction = BlendFunction.Add; } graphicsDevice.BlendState = defaultBlendState; //Get all the lines to draw StructureLink[] VisibleStructureLinks = currentSectionAnnotations.VisibleStructureLinks(Bounds); foreach (StructureLink link in VisibleStructureLinks) { DrawStructureLink(link, ViewProjMatrix, Time); } graphicsDevice.BlendState = defaultBlendState; //Draw text DrawLocationLabels(listLocationsToDraw); DrawLocationLabels(listVisibleNonOverlappingLocationsOnAdjacentSections); graphicsDevice.RasterizerState = OriginalRasterState; }
private static List<Location_CanvasViewModel> FindVisibleLocations(ICollection<Location_CanvasViewModel> locations, GridRectangle VisibleBounds) { GridCircle VisibleCircle = new GridCircle(VisibleBounds.Center, GridVector2.Distance(VisibleBounds.Center, new GridVector2(VisibleBounds.Left, VisibleBounds.Top))); List<Location_CanvasViewModel> listLocationsToDraw = new List<Location_CanvasViewModel>(locations.Count); foreach (Location_CanvasViewModel loc in locations) { if (loc == null) continue; if (!loc.VolumePositionHasBeenCalculated) continue; //Find out if we should draw the location if (loc.TypeCode == LocationType.CIRCLE) { if (VisibleCircle.Intersects(loc.VolumePosition, loc.Radius) == false) continue; } else if (loc.TypeCode == LocationType.POINT) { if (VisibleBounds.Contains(loc.VolumePosition) == false) continue; } else { Debug.Fail("Unknown location type"); } Structure ParentStructure = loc.Parent; if (ParentStructure == null) continue; if (ParentStructure.Type == null) continue; listLocationsToDraw.Add(loc); } return listLocationsToDraw; }
/// <summary> /// Remove all locations from the collection which overlap locations on the specified section /// </summary> /// <param name="locations">The collection to remove overlapping locations from</param> /// <returns>The removed locations which overlap</returns> private static List<Location_CanvasViewModel> RemoveOverlappingLocations(List<Location_CanvasViewModel> locations, int section_number) { List<Location_CanvasViewModel> listOverlappingLocations = new List<Location_CanvasViewModel>(locations.Count); for (int i = locations.Count - 1; i >= 0; i--) { Location_CanvasViewModel loc = locations.ElementAt(i); if (loc.TypeCode == LocationType.CIRCLE) { GridCircle locCircle = new GridCircle(loc.VolumePosition, loc.OffSectionRadius); foreach (long linked in loc.Links) { LocationObj LinkedObj = Store.Locations.GetObjectByID(linked, false); if (LinkedObj == null) continue; if (LinkedObj.Section == section_number) { if (locCircle.Intersects(LinkedObj.VolumePosition, LinkedObj.Radius)) { listOverlappingLocations.Add(loc); locations.RemoveAt(i); break; } } } } } return listOverlappingLocations; }
public bool Intersects(GridCircle c) { double XDist = c.Center.X - this.Center.X; double YDist = c.Center.Y - this.Center.Y; double CombinedRadiusSquared = this.Radius + c.Radius; CombinedRadiusSquared *= CombinedRadiusSquared; return (XDist * XDist) + (YDist * YDist) <= CombinedRadiusSquared; }
/// <summary> /// This exists because the Delaunay algorithm creates a ton of circles. Allocating memory for them /// means taking the allocation lock twice instead of one (Circle is created by triangle object) /// </summary> /// <param name="One"></param> /// <param name="Two"></param> /// <param name="Three"></param> /// <returns></returns> public static void CircleFromThreePoints(GridVector2 One, GridVector2 Two, GridVector2 Three, ref GridCircle circle) { if (One.X == Two.X && Two.X == Three.X) { throw new ArgumentException("Circle from three points with three points on a vertical line"); } double A = Two.X - One.X; double B = Two.Y - One.Y; double C = Three.X - One.X; double D = Three.Y - One.Y; double E = A * (One.X + Two.X) + B * (One.Y + Two.Y); double F = C * (One.X + Three.X) + D * (One.Y + Three.Y); double G = 2 * (A * (Three.Y - Two.Y) - B * (Three.X - Two.X)); //Check for colinear // Debug.Assert(false == (G <= double.Epsilon && G >= -double.Epsilon)); if (G <= double.Epsilon && G >= -double.Epsilon) { throw new ArgumentException("Circle from three points with three points on a line"); } GridVector2 Center = new GridVector2(); Center.X = (D * E - B * F) / G; Center.Y = (A * F - C * E) / G; circle.Center = Center; circle.Radius = GridVector2.Distance(Center, One); circle.RadiusSquared = circle.Radius * circle.Radius; //return new GridCircle(Center, GridVector2.Distance(Center, One)); }
/// <summary> /// This exists because the Delaunay algorithm creates a ton of circles. Allocating memory for them /// means taking the allocation lock twice instead of one (Circle is created by triangle object) /// </summary> /// <param name="One"></param> /// <param name="Two"></param> /// <param name="Three"></param> /// <returns></returns> public static void CircleFromThreePoints(GridVector2[] points, ref GridCircle circle) { if (points == null) { throw new ArgumentNullException("points"); } Debug.Assert(points.Length == 3); if (points.Length != 3) throw new ArgumentException("GridCircle: Expected an array with three elements"); GridCircle.CircleFromThreePoints(points[0],points[1], points[2], ref circle); }
private ConcurrentDictionary<Location_CanvasCircleAnnotationViewModel, GridCircle> CalculateOverlappedLocationCircles() { ConcurrentDictionary<Location_CanvasCircleAnnotationViewModel, GridCircle> listCircles = null; if (_OverlappingLinkedLocationCircles == null) { listCircles = new ConcurrentDictionary<Location_CanvasCircleAnnotationViewModel, GridCircle>(); } else { listCircles = _OverlappingLinkedLocationCircles; listCircles.Clear(); } List<Location_CanvasCircleAnnotationViewModel> listLinksAbove = new List<Location_CanvasCircleAnnotationViewModel>(this.Links.Count); List<Location_CanvasCircleAnnotationViewModel> listLinksBelow = new List<Location_CanvasCircleAnnotationViewModel>(this.Links.Count); foreach (long linkID in Links) { LocationObj locObj = Store.Locations.GetObjectByID(linkID, false); if (locObj == null) { continue; } if (locObj.Z == this.Z) continue; Location_CanvasCircleAnnotationViewModel loc = new Location_CanvasCircleAnnotationViewModel(locObj); if (loc == null) continue; if (loc.OffSectionRadius + this.Radius < GridVector2.Distance(loc.VolumePosition, this.VolumePosition)) continue; else if (loc.Section < this.Section) { listLinksBelow.Add(loc); } else { listLinksAbove.Add(loc); } } listLinksAbove = listLinksAbove.OrderBy(L => -L.X).ThenBy(L => L.Y).ToList(); listLinksBelow = listLinksBelow.OrderBy(L => L.X).ThenBy(L => L.Y).ToList(); //Figure out how large link images would be double linkRadius = this.Radius / 6; double linkArcNormalizedDistanceFromCenter = 0.75; double linkArcDistanceFromCenter = linkArcNormalizedDistanceFromCenter * this.Radius; double circumferenceOfLinkArc = linkArcDistanceFromCenter * Math.PI; //Don't multiply by two since we only use top half of circle double UpperArcLinkRadius = linkRadius; double LowerArcLinkRadius = linkRadius; //See if we will run out of room for links if (linkRadius * listLinksAbove.Count > circumferenceOfLinkArc) { UpperArcLinkRadius = circumferenceOfLinkArc / listLinksAbove.Count; } if (linkRadius * listLinksBelow.Count > circumferenceOfLinkArc) { LowerArcLinkRadius = circumferenceOfLinkArc / listLinksBelow.Count; } double UpperArcStepSize = UpperArcLinkRadius / (circumferenceOfLinkArc / 2); double LowerArcStepSize = LowerArcLinkRadius / (circumferenceOfLinkArc / 2); //double angleOffset =((listLinksAbove.Count / 2) / (double)listLinksAbove.Count) * Math.PI; double halfNumLinksAbove = listLinksAbove.Count / 2; double angleOffset = ((double)(1 - listLinksAbove.Count) % 2) * (UpperArcStepSize / 2); for (int iLocAbove = 0; iLocAbove < listLinksAbove.Count; iLocAbove++) { Location_CanvasCircleAnnotationViewModel linkLoc = listLinksAbove[iLocAbove]; //Figure out where the link should be drawn. //Allocate the top 180 degree arc for links above, the bottom 180 for links below double angle = (((((double)iLocAbove - halfNumLinksAbove) * UpperArcStepSize) - angleOffset) * Math.PI); //- angleOffset; Vector3 positionOffset = new Vector3((float)Math.Sin(angle), (float)Math.Cos(angle), (float)0); positionOffset *= (float)linkArcDistanceFromCenter; GridCircle circle = new GridCircle(this.VolumePosition + new GridVector2(positionOffset.X, positionOffset.Y), UpperArcLinkRadius); OverlappedLocation overlapLocation = new OverlappedLocation(new LocationLink(this, linkLoc), linkLoc.modelObj, circle); bool added = listCircles.TryAdd(overlapLocation, circle); if (!added) { overlapLocation = null; linkLoc = null; } } double halfNumLinksBelow = listLinksBelow.Count / 2; angleOffset = ((double)(1 - listLinksBelow.Count) % 2) * (LowerArcStepSize / 2); for (int iLocBelow = 0; iLocBelow < listLinksBelow.Count; iLocBelow++) { Location_CanvasCircleAnnotationViewModel linkLoc = listLinksBelow[iLocBelow]; //Figure out where the link should be drawn. //Allocate the top 180 degree arc for links above, the bottom 180 for links below double angle = (((((double)iLocBelow - halfNumLinksBelow) * LowerArcStepSize) - angleOffset) * Math.PI) + Math.PI; Vector3 positionOffset = new Vector3((float)Math.Sin(angle), (float)Math.Cos(angle), (float)0); positionOffset *= (float)linkArcDistanceFromCenter; GridCircle circle = new GridCircle(this.VolumePosition + new GridVector2(positionOffset.X, positionOffset.Y), LowerArcLinkRadius); OverlappedLocation overlapLocation = new OverlappedLocation(new LocationLink(this, linkLoc), linkLoc.modelObj, circle); bool added = listCircles.TryAdd(overlapLocation, circle); if (!added) { overlapLocation = null; linkLoc = null; } } return listCircles; }
public OverlappedLocation(LocationLink linkObj, LocationObj location, GridCircle circle) : base(location) { link = linkObj; gridCircle = circle; }