public GeoTiffProvider(string tiffPath, List <Color>?noDataColors = null) { if (!File.Exists(tiffPath)) { throw new ArgumentException($"Tiff file expected at {tiffPath}"); } var worldPath = GetPathWithoutExtension(tiffPath) + WorldExtension; if (!File.Exists(worldPath)) { throw new ArgumentException($"World file expected at {worldPath}"); } var tiffProperties = LoadTiff(tiffPath); var worldProperties = LoadWorld(worldPath); _extent = CalculateExtent(tiffProperties, worldProperties); using var data = ReadImageAsStream(tiffPath, noDataColors); _mRaster = new MRaster(data.ToArray(), _extent); _feature = new RasterFeature(_mRaster); _feature.Styles.Add(new VectorStyle()); }
private static SKMatrix CreateRotationMatrix(IReadOnlyViewport viewport, MRect rect, SKMatrix priorMatrix) { // The front-end sets up the canvas with a matrix based on screen scaling (e.g. retina). // We need to retain that effect by combining our matrix with the incoming matrix. // We'll create four matrices in addition to the incoming matrix. They perform the // zoom scale, focal point offset, user rotation and finally, centering in the screen. var userRotation = SKMatrix.CreateRotationDegrees((float)viewport.Rotation); var focalPointOffset = SKMatrix.CreateTranslation( (float)(rect.Left - viewport.Center.X), (float)(viewport.Center.Y - rect.Top)); var zoomScale = SKMatrix.CreateScale((float)(1.0 / viewport.Resolution), (float)(1.0 / viewport.Resolution)); var centerInScreen = SKMatrix.CreateTranslation((float)(viewport.Width / 2.0), (float)(viewport.Height / 2.0)); // We'll concatenate them like so: incomingMatrix * centerInScreen * userRotation * zoomScale * focalPointOffset var matrix = SKMatrix.Concat(zoomScale, focalPointOffset); matrix = SKMatrix.Concat(userRotation, matrix); matrix = SKMatrix.Concat(centerInScreen, matrix); matrix = SKMatrix.Concat(priorMatrix, matrix); return(matrix); }
private static MRect GrowBox(MRect box, double resolution) { const int symbolSize = 32; // todo: determine margin by symbol size const int boxMargin = symbolSize / 2; return(box.Grow(boxMargin * resolution)); }
/// <summary> /// This method returns the query string for 'GetFeature'. /// </summary> /// <param name="featureTypeInfo">A <see cref="WfsFeatureTypeInfo"/> instance providing metadata of the featuretype to query</param> /// <param name="labelProperties">A list of properties necessary for label rendering</param> /// <param name="boundingBox">The bounding box of the query</param> /// <param name="filter">An instance implementing <see cref="IFilter"/></param> public string GetFeatureGETRequest(WfsFeatureTypeInfo featureTypeInfo, List <string>?labelProperties, MRect boundingBox, IFilter?filter) { var qualification = string.IsNullOrEmpty(featureTypeInfo.Prefix) ? string.Empty : featureTypeInfo.Prefix + ":"; var paramBuilder = new StringBuilder(); paramBuilder.Append("?SERVICE=WFS&Version=1.0.0&REQUEST=GetFeature&TYPENAME="); paramBuilder.Append(HttpUtility.UrlEncode(qualification + featureTypeInfo.Name)); paramBuilder.Append("&srsName="); paramBuilder.Append(HttpUtility.UrlEncode(CrsHelper.EpsgPrefix + featureTypeInfo.SRID)); if (filter != null || boundingBox != null) { paramBuilder.Append("&FILTER="); using var sWriter = new StringWriter(); using var xWriter = new XmlTextWriter(sWriter); { AppendGml2Filter(xWriter, featureTypeInfo, boundingBox, filter, qualification); } paramBuilder.Append(HttpUtility.UrlEncode(sWriter.ToString())); } return(paramBuilder.ToString()); }
public async Task TestFeatureFetcherDelayAsync() { // arrange var extent = new MRect(0, 0, 10, 10); using var layer = new Layer { DataSource = new MemoryProvider(GenerateRandomPoints(extent, 25)) }; layer.Delayer.MillisecondsToWait = 0; var notifications = new List <bool>(); layer.PropertyChanged += (_, args) => { if (args.PropertyName == nameof(Layer.Busy)) { notifications.Add(layer.Busy); } }; var fetchInfo = new FetchInfo(extent, 1, null, ChangeType.Discrete); // act layer.RefreshData(fetchInfo); // assert await Task.Run(() => { while (notifications.Count < 2) { // just wait until we have two } }); Assert.IsTrue(notifications[0]); Assert.IsFalse(notifications[1]); }
public FetchInfo(FetchInfo fetchInfo) { Extent = new MRect(fetchInfo.Extent); Resolution = fetchInfo.Resolution; CRS = fetchInfo.CRS; ChangeType = fetchInfo.ChangeType; }
public MRect Grow(double amountInX, double amountInY) { var grownBox = new MRect(Min.X - amountInX, Min.Y - amountInY, Max.X + amountInX, MaxY + amountInY); EnforceMinMax(); return(grownBox); }
public FetchInfo(MRect extent, double resolution, string?crs = null, ChangeType changeType = ChangeType.Discrete) { Extent = extent; Resolution = resolution; CRS = crs; ChangeType = changeType; }
public MRect?GetExtent() { if (_provider.GetExtent() == null) { return(null); } var extent = _provider.GetExtent() !; if (!CrsHelper.IsProjectionNeeded(_provider.CRS, CRS)) { return(extent); } if (!CrsHelper.IsCrsProvided(_provider.CRS, CRS)) { throw new NotSupportedException($"CRS is not provided. From CRS: {_provider.CRS}. To CRS {CRS}"); } // This projects the full extent of the source. Usually the full extent of the source does not change, // so perhaps this should be calculated just once. Then again, there are probably situations where it does // change so a way to refresh this should be possible. var copiedExtent = new MRect(extent); _projection.Project(_provider.CRS, CRS, copiedExtent); return(copiedExtent); }
public IEnumerable <IFeature> GetFeatures(FetchInfo fetchInfo) { // Note that the FetchInfo.CRS is ignored in this method. A better solution // would be to use the fetchInfo.CRS everywhere, but that would only make // sense if GetExtent would also get a CRS argument. Room for improvement. if (fetchInfo.Extent == null) { return(new List <IFeature>()); } var copiedExtent = new MRect(fetchInfo.Extent); // throws exception when CRS or _provider.CRS is null (so I don't have to check it here) _projection.Project(CRS !, _provider.CRS !, copiedExtent); fetchInfo = new FetchInfo(copiedExtent, fetchInfo.Resolution, CRS, fetchInfo.ChangeType); var features = _provider.GetFeatures(fetchInfo) ?? new List <IFeature>(); if (!CrsHelper.IsProjectionNeeded(_provider.CRS, CRS)) { return(features); } if (!CrsHelper.IsCrsProvided(_provider.CRS, CRS)) { throw new NotSupportedException($"CRS is not provided. From CRS: {_provider.CRS}. To CRS {CRS}"); } var copiedFeatures = features.Copy().ToList(); _projection.Project(_provider.CRS, CRS, copiedFeatures); return(copiedFeatures); }
/// <summary> /// This method returns the POST request for 'GetFeature'. /// </summary> /// <param name="featureTypeInfo">A <see cref="WfsFeatureTypeInfo"/> instance providing metadata of the featuretype to query</param> /// <param name="labelProperties">A list of properties necessary for label rendering</param> /// <param name="boundingBox">The bounding box of the query</param> /// <param name="filter">An instance implementing <see cref="IFilter"/></param> public byte[] GetFeaturePOSTRequest(WfsFeatureTypeInfo featureTypeInfo, List <string>?labelProperties, MRect boundingBox, IFilter?filter) { var qualification = string.IsNullOrEmpty(featureTypeInfo.Prefix) ? string.Empty : featureTypeInfo.Prefix + ":"; using (var sWriter = new StringWriter()) { using (var xWriter = new XmlTextWriter(sWriter)) { xWriter.Namespaces = true; xWriter.WriteStartElement("GetFeature", NSWFS); xWriter.WriteAttributeString("service", "WFS"); xWriter.WriteAttributeString("version", "1.0.0"); xWriter.WriteStartElement("Query", NSWFS); xWriter.WriteAttributeString("typeName", qualification + featureTypeInfo.Name); xWriter.WriteAttributeString("srsName", CrsHelper.EpsgPrefix + featureTypeInfo.SRID); xWriter.WriteElementString("PropertyName", qualification + featureTypeInfo.Geometry.GeometryName); if (labelProperties != null && !labelProperties.All(string.IsNullOrWhiteSpace)) { xWriter.WriteElementString("PropertyName", string.Join(",", labelProperties.Where(x => !string.IsNullOrWhiteSpace(x)).Select(lbl => qualification + lbl))); } AppendGml2Filter(xWriter, featureTypeInfo, boundingBox, filter, qualification); xWriter.WriteEndElement(); xWriter.WriteEndElement(); xWriter.Flush(); return(Encoding.UTF8.GetBytes(sWriter.ToString())); } } }
/// <inheritdoc /> public override IEnumerable <IFeature> GetFeatures(MRect extent, double resolution) { if (_tileSource.Schema == null) { return(Enumerable.Empty <IFeature>()); } UpdateMemoryCacheMinAndMax(); return(_renderFetchStrategy.Get(extent, resolution, _tileSource.Schema, MemoryCache)); }
public IList <IFeature> Get(MRect extent, double resolution, ITileSchema schema, ITileCache <IFeature?> memoryCache) { var dictionary = new Dictionary <TileIndex, IFeature>(); var level = BruTile.Utilities.GetNearestLevel(schema.Resolutions, resolution); GetRecursive(dictionary, schema, memoryCache, extent.ToExtent(), level); var sortedFeatures = dictionary.OrderByDescending(t => schema.Resolutions[t.Key.Level].UnitsPerPixel); return(sortedFeatures.ToDictionary(pair => pair.Key, pair => pair.Value).Values.ToList()); }
public static Polygon ToPolygon(this MRect rect) { return(new Polygon(new LinearRing(new[] { rect.TopLeft.ToCoordinate(), rect.TopRight.ToCoordinate(), rect.BottomRight.ToCoordinate(), rect.BottomLeft.ToCoordinate(), rect.TopLeft.ToCoordinate() }))); }
public static Viewport ToViewport(this MRect rect, double width) { return(new Viewport { Resolution = rect.Width / width, CenterX = rect.Centroid.X, CenterY = rect.Centroid.Y, Width = width, Height = width * (rect.Height / rect.Width) }); }
public MRect m_monitorrect; // the display portions of the larger image public MonitorConfig() { m_XDLPRes = 1024; m_YDLPRes = 768; m_Xpixpermm = 1.0; m_Ypixpermm = 1.0; m_displayconnectionenabled = false; // -SHS m_displayconnection = new ConnectionConfig(); m_monitorrect = new MRect(); m_displayconnection.CreateDefault(); m_monitorid = ""; }
private static SKRect WorldToScreen(IReadOnlyViewport viewport, MRect rect) { var first = viewport.WorldToScreen(rect.Min.X, rect.Min.Y); var second = viewport.WorldToScreen(rect.Max.X, rect.Max.Y); return(new SKRect ( (float)Math.Min(first.X, second.X), (float)Math.Min(first.Y, second.Y), (float)Math.Max(first.X, second.X), (float)Math.Max(first.Y, second.Y) )); }
private static IEnumerable <IFeature> GenerateRandomPoints(MRect envelope, int count) { var random = new Random(0); var result = new List <PointFeature>(); for (var i = 0; i < count; i++) { result.Add(new PointFeature(new MPoint( random.NextDouble() * envelope.Width + envelope.Left, random.NextDouble() * envelope.Height + envelope.Bottom))); } return(result); }
private bool GetFetchInfo(ref FetchInfo fetchInfo) { // Note that the FetchInfo.CRS is ignored in this method. A better solution // would be to use the fetchInfo.CRS everywhere, but that would only make // sense if GetExtent would also get a CRS argument. Room for improvement. if (fetchInfo.Extent == null) { return(true); } var copiedExtent = new MRect(fetchInfo.Extent); // throws exception when CRS or _provider.CRS is null (so I don't have to check it here) _projection.Project(CRS !, _provider.CRS !, copiedExtent); fetchInfo = new FetchInfo(copiedExtent, fetchInfo.Resolution, CRS, fetchInfo.ChangeType); return(false); }
/// <summary> /// This method returns the POST request for 'GetFeature'. /// </summary> /// <param name="featureTypeInfo">A <see cref="WfsFeatureTypeInfo"/> instance providing metadata of the featuretype to query</param> /// <param name="labelProperties">A list of properties necessary for label rendering</param> /// <param name="boundingBox">The bounding box of the query</param> /// <param name="filter">An instance implementing <see cref="IFilter"/></param> public byte[] GetFeaturePOSTRequest(WfsFeatureTypeInfo featureTypeInfo, List <string>?labelProperties, MRect boundingBox, IFilter?filter) { var qualification = string.IsNullOrEmpty(featureTypeInfo.Prefix) ? string.Empty : featureTypeInfo.Prefix + ":"; using (var sWriter = new StringWriter()) { using (var xWriter = new XmlTextWriter(sWriter)) { xWriter.Namespaces = true; xWriter.WriteStartElement("GetFeature", NSWFS); xWriter.WriteAttributeString("service", "WFS"); xWriter.WriteAttributeString("version", "1.1.0"); if (!string.IsNullOrEmpty(featureTypeInfo.Prefix) && !string.IsNullOrEmpty(featureTypeInfo.FeatureTypeNamespace)) { xWriter.WriteAttributeString("xmlns:" + featureTypeInfo.Prefix, featureTypeInfo.FeatureTypeNamespace); } //added by PDD to get it to work for degree default sample xWriter.WriteStartElement("Query", NSWFS); xWriter.WriteAttributeString("typeName", qualification + featureTypeInfo.Name); xWriter.WriteAttributeString("srsName", CrsHelper.EpsgPrefix + featureTypeInfo.SRID); xWriter.WriteElementString("PropertyName", qualification + featureTypeInfo.Geometry.GeometryName); if (labelProperties != null) { foreach (var labelProperty in labelProperties.Where(labelProperty => !string.IsNullOrWhiteSpace(labelProperty))) { xWriter.WriteElementString("PropertyName", qualification + labelProperty); } } AppendGml3Filter(xWriter, featureTypeInfo, boundingBox, filter, qualification); xWriter.WriteEndElement(); xWriter.WriteEndElement(); xWriter.Flush(); return(Encoding.UTF8.GetBytes(sWriter.ToString())); } } }
public override IEnumerable <IFeature> GetFeatures(MRect box, double resolution) { var features = _source.GetFeatures(box, resolution).Cast <GeometryFeature>().ToList(); foreach (var feature in features) { if (feature.Geometry is Point || feature.Geometry is MultiPoint) { continue; // Points with a vertex on top confuse me } if (feature.Geometry != null) { foreach (var vertex in feature.Geometry.MainCoordinates()) { yield return(new GeometryFeature { Geometry = new Point(vertex) }); } } } }
public override IEnumerable <IFeature> GetFeatures(MRect box, double resolution) { if (box == null) { return(Enumerable.Empty <IFeature>()); } var biggerBox = box.Grow( SymbolStyle.DefaultWidth * 2 * resolution, SymbolStyle.DefaultHeight * 2 * resolution); var fetchInfo = new FetchInfo(biggerBox, resolution, CRS); if (DataSource is null) { return(Enumerable.Empty <IFeature>()); } #pragma warning disable VSTHRD002 // Allow use of .Result for test purposes return(DataSource.GetFeaturesAsync(fetchInfo).Result); #pragma warning restore VSTHRD002 // }
/// <summary> /// Renderer for PerformanceWidget /// </summary> /// <param name="x">X position of widget on screen</param> /// <param name="y">Y position of widget on screen</param> /// <param name="textSize">Size of text</param> /// <param name="textColor">Color for text</param> /// <param name="backgroundColor">Color for background</param> public PerformanceWidgetRenderer(float x, float y, int textSize, SKColor textColor, SKColor backgroundColor) { _textSize = textSize; _textPaint = new SKPaint { Color = textColor, TextSize = textSize, }; _backgroundPaint = new SKPaint { Color = backgroundColor, Style = SKPaintStyle.Fill, }; for (var i = 0; i < _textHeader.Length; i++) { _widthHeader = System.Math.Max(_widthHeader, _textPaint.MeasureText(_textHeader[5])); } var width = _widthHeader + 20 + _textPaint.MeasureText("0000.000"); _rect = new SKRect(x, y, x + width + 4, y + _textHeader.Length * (textSize + 2) - 2 + 4); _envelope = new MRect(_rect.Left, _rect.Top, _rect.Right, _rect.Bottom); }
private MRect CreateSelectRect(int x, int y) { MRect mr = new MRect(); mr.LayerNo = ICON_LAYER_NO; mr.BackColor = Color.Blue; //mr.LineWidth = 0; mr.LineWidth = 3; mr.X = x; mr.Y = y; mr.MinX = x - 500; mr.MaxX = x + 500; mr.MinY = y - 500; mr.MaxY = y + 500; mr.Visible = false; return mr; }
public RectFeature(MRect rect) { Rect = rect; }
/// <summary> /// Creates a node and either splits the objects recursively into sub-nodes, or stores them at the node depending on the heuristics. /// Tree is built top->down /// </summary> /// <param name="objList">Geometries to index</param> /// <param name="depth">Current depth of tree</param> /// <param name="heurdata">Heuristics data</param> public QuadTree(List <BoxObjects> objList, uint depth, Heuristic heurdata) { _depth = depth; _box = objList[0].Box; for (var i = 0; i < objList.Count; i++) { _box = _box.Join(objList[i].Box); } // test our build heuristic - if passes, make children if (depth < heurdata.Maxdepth && objList.Count > heurdata.Mintricnt && (objList.Count > heurdata.Tartricnt || ErrorMetric(_box) > heurdata.Minerror)) { var objBuckets = new List <BoxObjects> [2]; // buckets of geometries objBuckets[0] = new List <BoxObjects>(); objBuckets[1] = new List <BoxObjects>(); var useXAxis = _box.Width > _box.Height; // longest axis double geoAverage = 0; // geometric average - midpoint of ALL the objects // go through all bbox and calculate the average of the midpoints double fraction = 1.0f / objList.Count; for (var i = 0; i < objList.Count; i++) { var centroid = useXAxis ? objList[i].Box.Centroid.X : objList[i].Box.Centroid.Y; geoAverage += centroid * fraction; } // bucket bbox based on their midpoint's side of the geo average in the longest axis for (var i = 0; i < objList.Count; i++) { var centroid = useXAxis ? objList[i].Box.Centroid.X : objList[i].Box.Centroid.Y; objBuckets[geoAverage > centroid ? 1 : 0].Add(objList[i]); } //If objects couldn't be split, just store them at the leaf //TODO: Try splitting on another axis if (objBuckets[0].Count == 0 || objBuckets[1].Count == 0) { _child0 = null; _child1 = null; // copy object list _objList = objList; } else { // create new children using the buckets _child0 = new QuadTree(objBuckets[0], depth + 1, heurdata); _child1 = new QuadTree(objBuckets[1], depth + 1, heurdata); } } else { // otherwise the build heuristic failed, this is // set the first child to null (identifies a leaf) _child0 = null; _child1 = null; // copy object list _objList = objList; } }
private void AppendGml2Filter(XmlTextWriter xWriter, WfsFeatureTypeInfo featureTypeInfo, MRect boundingBox, IFilter?filter, string qualification) { xWriter.WriteStartElement("Filter", NSOGC); if (filter != null && boundingBox != null) { xWriter.WriteStartElement("And"); } if (boundingBox != null) { xWriter.WriteStartElement("BBOX"); if (!string.IsNullOrEmpty(featureTypeInfo.Prefix) && !string.IsNullOrEmpty(featureTypeInfo.FeatureTypeNamespace)) { xWriter.WriteElementString("PropertyName", qualification + featureTypeInfo.Geometry.GeometryName); } //added qualification to get it to work for degree default sample else { xWriter.WriteElementString("PropertyName", featureTypeInfo.Geometry.GeometryName); } xWriter.WriteStartElement("gml", "Box", NSGML); xWriter.WriteAttributeString("srsName", "http://www.opengis.net/gml/srs/epsg.xml#" + featureTypeInfo.SRID); xWriter.WriteElementString("coordinates", NSGML, XmlConvert.ToString(boundingBox.Left) + "," + XmlConvert.ToString(boundingBox.Bottom) + " " + XmlConvert.ToString(boundingBox.Right) + "," + XmlConvert.ToString(boundingBox.Top)); xWriter.WriteEndElement(); xWriter.WriteEndElement(); } if (filter != null) { xWriter.WriteRaw(filter.Encode()); } if (filter != null && boundingBox != null) { xWriter.WriteEndElement(); } xWriter.WriteEndElement(); }
/// <summary> /// This constructor is used internally for loading a tree from a file /// </summary> private QuadTree() { _box = default !;
private static double CalculateResolutionAtWhichMapFillsViewport(double screenWidth, double screenHeight, MRect mapEnvelope) { return(Math.Min(mapEnvelope.Width / screenWidth, mapEnvelope.Height / screenHeight)); }
public static Extent ToExtent(this MRect rect) { return(new Extent(rect.MinX, rect.MinY, rect.MaxX, rect.MaxY)); }
/// <summary> Win32 </summary> public MRect(MRect rcSrc) { left = rcSrc.left; top = rcSrc.top; right = rcSrc.right; bottom = rcSrc.bottom; }
public RectFeature(RectFeature rectFeature) : base(rectFeature) { Rect = new MRect(rectFeature.Rect); }