I'm trying to create a geofence with an uncertain amount of coordinates, but C# and Xamarin Forms Maps won't accept dynamically loaded-in content. I have made sure that there always will be three or more positions to create the geofence. I have tried this, with coordinates being a string array:
Polygon geofence = new Polygon
{
StrokeColor = Color.Green,
FillColor = Color.Green,
Geopath =
{
foreach (string coordinate in coordinates)
{
string[] LongAndLat = coordinate.Split(',');
new Position(Convert.ToDouble(LongAndLat[0]), Convert.ToDouble(LongAndLat[1]));
}
}
};
Which basically tells me that C# doesn't expect a function within the Geopath parameters, but I don't know how to get to where I want without doing it.
Is there a way to do this correctly?
The C# syntax isn't valid. Since the Geopath property is readonly, you have to assign the property later. This solution works:
string[] coordinates = geodata.Split(';');
Polygon geofence = new Polygon
{
StrokeColor = Color.Green,
FillColor = Color.FromRgba(0, 255, 0, 0.4)
};
foreach(string coordinate in coordinates)
{
string[] LongAndLat = coordinate.Split(',');
geofence.Geopath.Add(new Position(Convert.ToDouble(LongAndLat[0]), Convert.ToDouble(LongAndLat[1])));
}
Related
I have a shape object drawn as a 'group' such that the two sub-shapes are direct children of the group. All the shapes in the group have distinguishing colors.
I wish to know what is that property which can help me to get the color of the shape objects (Red, Green, White).
I know that shape has style property (Shape.Style) but that does not gives me the color value.
Application visApp = new Application();
Document visDoc = visApp.Documents.Open(VisiofilePath);
var shp = visApp.ActivePage.Shapes.ItemFromID[1];
string shapeColor = string.Empty;
foreach (Visio.Shape s in shp.Shapes)
{
if(s.Text == "Child Object 1")
{
//shapeColor =
}
if(s.Text == "Child Object 2")
{
//shapeColor =
}
}
Any help will be much appreciated.
Getting hold of the fill color is not impacted by whether the shape is part of a group or not. Once you've got a reference to the right shape then you can look at the respective cells.
Visio has two main methods of setting the fill color - Pattern fill and Gradient fill. The latter is from 2013 onwards.
For Pattern fill, you're looking at three cells: FillForegnd, FillBkgnd and FillPattern. Most shapes start off with a solid fill (FillPattern 1) and this means that only the FillForegnd is used. For other pattern types you're dealing with both FillForegnd and FillBkgnd.
For Gradient fill the FillGradientEnabled cell is set to 1 and this results in the Fill Gradient Stops section taking precedents.
In the background, Visio maintains a Document.Colors collection. Some built-in colors can be accessed by index: 0 = black, 1 = white, 2 = red, 3 = green etc all the way up to 23. Any additional custom colors used are added to the collection and are also given an index. This means that, given an index, you can look up the color instance in the Colors collection.
Following is some code to demo how to access the various types of coloring. Given these four shapes:
The first 3 shapes use Pattern fill, while the last uses Gradient fill.
Sheet.1 uses an index cell formula (3),
Sheet.2 uses an RGB function,
Sheet.3 uses a Pattern (2) and so uses both Foreground and Background cells
Sheet.4 uses Gradient stops and so Foreground and Background cells are ignored
... you could use the following code to read the colors at work (note this is using LINQPad as the output window makes it clearer to see what's going on:
void Main()
{
var vApp = MyExtensions.GetRunningVisio();
for (int i = 1; i <= 4; i++)
{
var shp = vApp.ActivePage.Shapes.ItemFromID[i];
var colorInfos = new List<ColorInfo>();
colorInfos.Add(new ColorInfo(shp.CellsU["FillForegnd"]));
colorInfos.Add(new ColorInfo(shp.CellsU["FillBkgnd"]));
new
{
shp.NameID,
FillPattern = shp.CellsU["FillPattern"].ResultIU,
FillGradientEnabled = Convert.ToBoolean(shp.CellsU["FillGradientEnabled"].ResultIU),
PatternColors = colorInfos,
GradientColors = FillGradientColors(shp) ?? "Default (10 stops all white)"
}.Dump();
}
}
private dynamic FillGradientColors(Visio.Shape shp)
{
List<string> rgbs = null;
var iSect = (short)Visio.VisSectionIndices.visSectionFillGradientStops;
for (int i = 0; i < shp.RowCount[iSect]; i++)
{
var targetCell = shp.CellsSRC[iSect, (short)i, (short)Visio.VisCellIndices.visGradientStopColor];
if (targetCell.IsInherited == 0)
{
if (rgbs is null)
{
rgbs = new List<string>();
}
rgbs.Add(ColorInfo.RgbString(targetCell));
}
}
return rgbs;
}
public class ColorInfo
{
private Visio.Cell _vCell;
public ColorInfo(Visio.Cell vCell)
{
_vCell = vCell;
RGB = RgbString(_vCell);
}
public string Name => _vCell.Name;
public string RGB { get; set; }
public string FormulaU => _vCell.FormulaU;
public static string RgbString(Visio.Cell cell)
{
var colorIdx = cell.Result[(short)Visio.VisUnitCodes.visUnitsColor];
var c = cell.Document.Colors.Item16[(short)colorIdx];
return $"RGB({c.Red},{c.Green},{c.Blue})";
}
}
... this produces the following output:
something is not working as it should. If you take alook at the screenshot you will see that the result is weird. The floor of the pavilion is rendered correctly, but the columns are kinda transparent, and the roof is completele weird. I used Assimp.NET to import his mesh from a .obj file. In other engines it looked correctly. Another thing was: if i set CullMode to Back - it will cull the front faces?! I think it could be 3 things: 1,the mesh was imported wrong, or the z Buffer is not working, or maybe i need multiple world matrices (im using only one).
Does maybe anybody know what this could be?!
Screenshot:
Here is some code:
DepthBuffer/DepthStencilView
var depthBufferDescription = new Texture2DDescription
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = BackBuffer.Description.Width,
Height = BackBuffer.Description.Height,
SampleDescription = swapChainDescription.SampleDescription,
BindFlags = BindFlags.DepthStencil
};
var depthStencilViewDescription = new DepthStencilViewDescription
{
Dimension = SwapChain.Description.SampleDescription.Count > 1 || SwapChain.Description.SampleDescription.Quality > 0 ? DepthStencilViewDimension.Texture2DMultisampled : DepthStencilViewDimension.Texture2D
};
var depthStencilStateDescription = new DepthStencilStateDescription
{
IsDepthEnabled = true,
DepthComparison = Comparison.Always,
DepthWriteMask = DepthWriteMask.All,
IsStencilEnabled = false,
StencilReadMask = 0xff,
StencilWriteMask = 0xff,
FrontFace = new DepthStencilOperationDescription
{
Comparison = Comparison.Always,
PassOperation = StencilOperation.Keep,
FailOperation = StencilOperation.Keep,
DepthFailOperation = StencilOperation.Increment
},
BackFace = new DepthStencilOperationDescription
{
Comparison = Comparison.Always,
PassOperation = StencilOperation.Keep,
FailOperation = StencilOperation.Keep,
DepthFailOperation = StencilOperation.Decrement
}
};
Loading mesh files:
public static Mesh Stadafax_ModelFromFile(string path)
{
if (_importContext.IsImportFormatSupported(Path.GetExtension(path)))
{
var imported = _importContext.ImportFile(path, PostProcessSteps.Triangulate | PostProcessSteps.FindDegenerates | PostProcessSteps.FindInstances | PostProcessSteps.FindInvalidData | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.OptimizeGraph | PostProcessSteps.ValidateDataStructure | PostProcessSteps.FlipUVs);
Mesh engineMesh = new Mesh();
Assimp.Mesh assimpMesh = imported.Meshes[0];
foreach(Face f in assimpMesh.Faces)
{
engineMesh.Structure.Faces.Add(new Rendering.Triangle((uint)f.Indices[0], (uint)f.Indices[1], (uint)f.Indices[2]));
}
List<Vector3D>[] uv = assimpMesh.TextureCoordinateChannels;
for(int i = 0; i < assimpMesh.Vertices.Count; i++)
{
engineMesh.Structure.Vertices.Add(new Vertex(new Vector4(assimpMesh.Vertices[i].X, assimpMesh.Vertices[i].Y, assimpMesh.Vertices[i].Z, 1), RenderColorRGBA.White, new Vector2(uv[0][i].X, uv[0][i].Y)));
}
return engineMesh;
}
else
NoëlEngine.Common.Output.Log("Model format not supported!", "Importeur", true); return null;
}
}
If anybody only has the smallest idea what this could be please just write a comment.
What you see are polygons actually behind others still being drawn above them.
When you configure the depth buffer via DepthStencilStateDescription, you set up the DepthComparison to Comparison.Always. This is not what you want, you want to use Comparison.Less.
What's the logic behind it? Every depth value for a pixel is checked whether it can actually write to the depth buffer. This check is configured with the Comparison you specified.
Comparison.Always always allows the new value to be written. So no matter if a polygon is actually behind others or above them or whatever, it will always override ("draw above") what's already there - even if it's behind it spatially.
Comparison.Less only writes the value if it is less than the current value in the depth buffer. Don't forget that smaller depth values are closer to the viewer. So a polygon closer to an existing one will override ("draw above") the old one. But if it is behind it, it won't draw. That's exactly what you want.
You can also guess what the other Comparison enumerations now do, and play around with them :)
***I sincerely apologise as I should have posted the complete code.
I have an application where I have an IUIAutomationElementArray and I have cached data regarding bounding rectangles of each IUIAutomationElement from the array. I am then converting these to WPF borders
public class NumberRectangle : Border, IComparable
{
currently I am using iteration to convert the IUIAutomationElementArray to an array list of rectangles seen in the method declaration below.
public ArrayList createRectangles(IUIAutomationElementArray elements)
{
// create an array list to hold the rectangles
rectArray = new ArrayList();
for (int i = 0; i < elements.Length; i++)
{
IUIAutomationElement currentElement = elements.GetElement(i);
//create DragonNumberRectangle to represent automation element
NumberRectangle currentRectangle = new NumberRectangle(currentElement);
//set horizontal and vertical alignment in order to align rectangles properly on window
currentRectangle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
currentRectangle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
currentRectangle.Height = (currentElement.CachedBoundingRectangle.bottom - currentElement.CachedBoundingRectangle.top);
currentRectangle.Width = (currentElement.CachedBoundingRectangle.right - currentElement.CachedBoundingRectangle.left);
// Thickness object represents Margin property of NumberRectangle (which is basically a Border)
Thickness rectThickness = new Thickness();
//set Left and Top for position of rectangle
rectThickness.Left = (currentElement.CachedBoundingRectangle.left);
rectThickness.Top = (currentElement.CachedBoundingRectangle.top);
currentRectangle.Margin = rectThickness;
// add colour rectangle to the list of rectangles
rectArray.Add(currentRectangle);
}
//sort the rectangles to number from left to right/top to bottom
rectArray.Sort();
return rectArray;
}
I then draw the borders on a WPF window. The issue is that the createRectangles metho takes one second of processing time where the conversion of the element array to rectangles is the predominant time waster.
So the question is can I do this with Linq and how would I do this with Linq, an example would be great as I am not familiar with Linq currently. Perhaps the real question is how do I speed this up?
If you consider LINQ is more elegant than you can use conversion in this way. Surely this is a slower way to convert list of objects.
...
rectArrayList =
from e in elements
select new
{
x = e.x,
y = e.y,
width = e.width,
height = e.height,
};
To achieve a conversion from array to arraylist you could simple do the following:
IUIAutomationElementArray elements = new IUIAutomationElementArray();
//populate that array with data
var arrayList = new ArrayList();
arrayList.Addrange(elements);
Ideally though you should be using a List<T> as opposed to an ArrayList, in which case you could do the following:
List<IUIAutomationElement> myList = new List<IUIAutomationElement>(elements);
Here you are passing the array as a parameter in the constructor of the List.
I want to create several rectangles (with dynamic names) by changing the name of the rectangle
int[] num= { 1, 2, 3, 4 }; //I need infant number of rectangle but here only a symbol of four numbers.
for (int i = 0; i < 3; i = i + 1)
{
string mystring= "regctangle"+num[i].ToString();
string rectanglename = myString; //this is the rectangle name change with the loop
Rectangle rectanglename= new Rectangle(10, 10, 3, 3);
}
The results should be for first iteration rectangle
rectangle1
rectangle2
rectangle3
rectangle4
This questions is kind of interesting...here's some options I came up with, since I'm not sure what your intention is with having these unique variable names.
What you'd need to do is either:
1) Add the rectangle to a dictionary or
2) Add a name property to the Rectangle class.
I did both on the code below.
//dictionary for our rectangles
var rectangleDict = new Dictionary<string, Rectangle>();
for (int i = 0; i < 3; i = i + 1)
{
var rectangle = new Rectangle(10, 10, 3, 3);
string rectangleName = "rectangle" + i.ToString();
//add rectangle name to new dictionary entry and the Rectangle name property
rectangle.name = rectangleName;
rectangleDict[rectangleName] = rectangle;
}
Once you got that set up here are a couple of options on how to look up those rectangles and their properties.
//#1 Use the dict to iterate through them
foreach (KeyValuePair<string, Rectangle> rect in rectangleDict)
{
Console.WriteLine(rect.Key);
//iterate through any property in the rectangle such as its sides, name, etc
Console.WriteLine(rect.Value.name);
}
//#2 use the key directly to access a property
Console.WriteLine(rectangleDict["rectangle1"].name);
I guess the first problem here is how are you going to label the rectangles? Based on the MSDN api documentation for Rectangle, there is no property that you can use for storing custom names.
Just a thought, there can be a better solution out there. You can potentially extend the Rectangle class, throw in a variable call "name" or something, then write the setters and getters operators for it.
Then in your code when you need to print the label just do.
int[] num= { 1, 2, 3, 4 };
for (int i = 0; i < num.length; i++)
{
MyRectangle rectanglename = new MyRectangle("NAME_XXX", 10, 10, 3, 3);
// Probably push the instance into an array for later reference.
}
// When you need the rectangle's name just do something like
console.writeline(rectangle10.name);
Apologise here. My unix laptop don't have a copy of visual studio installed so I can't really show you a proper piece of code, only pseudo code.
I create a single contour and add it to the chart, add points with label text and also subscribe to the GetSeriesMark event, but the text is not displayed, and the event never gets fired
Contour contour1 = new Contour();
contour1.IrregularGrid = true;
//
// contour1
contour1.Brush.Color = Color.FromArgb(68, 102, 163);
contour1.ColorEach = false;
contour1.EndColor = Color.FromArgb(192, 0, 0);
contour1.FillLevels = checkEditFillLevels.Checked;
//
//
contour1.Marks.Style = MarksStyles.Label;
contour1.Marks.Visible = true;
//
//
contour1.NumLevels = 8;
contour1.PaletteMin = 0;
contour1.PaletteStep = 0;
contour1.PaletteStyle = PaletteStyles.Pale;
//
//
contour1.Pen.Color = Color.FromArgb(192, 192, 192);
contour1.Pen.Style = DashStyle.Dot;
//
//
contour1.Pointer.HorizSize = 2;
//
//
contour1.Pointer.Pen.Visible = false;
contour1.Pointer.Style = PointerStyles.Rectangle;
contour1.Pointer.VertSize = 2;
contour1.Pointer.Visible = true;
contour1.StartColor = Color.FromArgb(255, 255, 192);
contour1.Title = "contour1";
Adding points is done with this
contour1.Add(x, y, z, "My Point 1");
Is there a way to display marks on the exact points in the Contour, and moreover is there a way to display marks only on specific points in the Contour (some points are actual data, others are made using interpolation to be able to show the contour)?
I'm afraid not, Contour series calculates and displays isolines from a custom array of X, Y and Z points. Levels are calculated automatically from users data. What would you like to get exactly? You might be interested in using Annotation tools. Here you can find an example about custom annotation tool positioning.
Since it is not possible to mark single points in contour (see #Narcís Calvet's answer), I ended up adding one Points series with marks on them.
However, I still wanted only the Contour levels to be shown in the legend, and X axis to display it's values instead of Marks of the Points, so I needed to add following lines.
tChart1.Legend.LegendStyle = LegendStyles.Values;
tChart1.Legend.Series = _currentContour;
tChart1.Axes.Bottom.Labels.Style = AxisLabelStyle.Value;