I have a Polygon persisted on a SQL Server 2012 database as Sys.Geography type. How can I obtain all points for the Polygon?
I'm thinking to use AsText() method and parse the string, but maybe there is a better choice?
Found a way, here is an extension method:
public static IEnumerable<MyEntityWithLatAndLng> GetPointsFromPolygon(this System.Data.Entity.Spatial.DbGeography geo)
{
for (int i = 1; i < geo.PointCount; i++)
{
var p = geo.PointAt(i);
yield return new MyEntityWithLatAndLng(){ Latitude = p.Latitude.Value, Longitude = p.Longitude.Value };
}
}
I think Alexandre nearly has this correct, he is missing the last element of the polygon from the points list. See the updated code below.
public static IEnumerable<MyEntityWithLatAndLng> GetPointsFromPolygon(this System.Data.Entity.Spatial.DbGeography geo)
{
for (int i = 1; i <= geo.PointCount; i++)
{
var p = geo.PointAt(i);
yield return new MyEntityWithLatAndLng(){ Latitude = p.Latitude.Value, Longitude = p.Longitude.Value };
}
}
SqlGeography
class has a method STPolyFromText
which allows you to get polygon with array of points.
In C# for example:
SqlGeography poly = SqlGeography.STPolyFromText(
new SqlChars(yourEntity.geoColumn.WellKnownValue.WellKnownText),
yourEntity.geoColumn.CoordinateSystemId);
for (int i = 1; i <= poly.STNumPoints(); i++)
{
SqlGeography point = poly.STPointN(i);
//do something with point
}
Related
For a sailing game I'm working on, I've added functionality to programmatically create damage holes in a mesh (e.g. cannonball holes in a sail). This is largely based on the method here (link to the example code here)
private void MessWithMesh() {
filter = this.transform.parent.gameObject.GetComponent<MeshFilter>();
mesh = filter.mesh;
filter.mesh = GenerateMeshWithHoles();
}
private IEnumerator GenerateTrisWithVertex() {
// Destroying the sail won't work until this has finished, but it only takes a second or two so I don't think anybody will notice.
trisWithVertex = new List<int>[origvertices.Length];
for (int i = 0; i <origvertices.Length; ++i)
{
trisWithVertex[i] = ArrayHelper.IndexOf(origtriangles, i);
yield return null;
}
yield return null;
}
Mesh GenerateMeshWithHoles()
{
float damageRadius = 1f;
Transform parentTransform = this.transform.parent.transform;
Hole[] holes = this.GetComponentsInChildren<Hole>();
foreach (Hole hole in holes) {
Vector3 trackPos = hole.transform.position;
float closest = float.MaxValue;
int closestIndex = -1;
int countDisabled = 0;
damageRadius = hole.diameter;
for (int i = 0; i <origvertices.Length; ++i)
{
Vector3 v = new Vector3(origvertices[i].x * parentTransform.localScale.x, origvertices[i].y * parentTransform.localScale.y, origvertices[i].z * parentTransform.localScale.z) + parentTransform.position;
Vector3 difference = v - trackPos;
if (difference.magnitude < closest)
{
closest = difference.magnitude;
closestIndex = i;
}
if (difference.magnitude < damageRadius)
{
for (int j = 0; j <trisWithVertex[i].Count; ++j)
{
int value = trisWithVertex[i][j];
int remainder = value % 3;
trianglesDisabled[value - remainder] = true;
trianglesDisabled[value - remainder + 1] = true;
trianglesDisabled[value - remainder + 2] = true;
countDisabled++;
}
}
}
// If no triangles were removed, then we'll just remove the one that was closest to the hole.
// This shouldn't really happen, but in case the hole is off by a bit from where it should have hit the mesh, we'll do this to make sure there's at least a hole.
if (countDisabled == 0 && closestIndex > -1) {
Debug.Log("Removing closest vertex: " + closestIndex);
for (int j = 0; j < trisWithVertex[closestIndex].Count; ++j)
{
int value = trisWithVertex[closestIndex][j];
int remainder = value % 3;
trianglesDisabled[value - remainder] = true;
trianglesDisabled[value - remainder + 1] = true;
trianglesDisabled[value - remainder + 2] = true;
}
}
}
triangles = ArrayHelper.RemoveAllSpecifiedIndicesFromArray(origtriangles, trianglesDisabled).ToArray();
mesh.SetTriangles(triangles, 0);
for (int i = 0; i <trianglesDisabled.Length; ++i)
trianglesDisabled[i] = false;
return mesh;
}
When a cannonball hits the sail, I add a Hole object at the location of the impact, and I call MessWithMesh. The holes are often generated correctly, but many times they're only visible from one side of the sail (it looks fully intact from the other side). It's often visible from the opposite side of the sail that the cannonball impacted (the far side, not the near side), if that's at all helpful. The ship I'm using is this free asset.
I'm not really familiar with meshes, so I don't really understand what's going on.
I am sure that everybody knows about this script, http://wiki.unity3d.com/index.php/Floating_Origin, that fixes problems with floating origin easily.
The problem is that the script is outdated and does not move the particle effects created by visual effect graph.
I was trying to rewrite it but I cant seem to make an array to store all the particles, like with the previous one, thus I can't continue from there.
Here is my code:
// Based on the Unity Wiki FloatingOrigin script by Peter Stirling
// URL: http://wiki.unity3d.com/index.php/Floating_Origin
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.VFX;
using UnityEngine.Experimental.VFX;
public class FloatingOrigin : MonoBehaviour
{
[Tooltip("Point of reference from which to check the distance to origin.")]
public Transform ReferenceObject = null;
[Tooltip("Distance from the origin the reference object must be in order to trigger an origin shift.")]
public float Threshold = 5000f;
[Header("Options")]
[Tooltip("When true, origin shifts are considered only from the horizontal distance to orign.")]
public bool Use2DDistance = false;
[Tooltip("When true, updates ALL open scenes. When false, updates only the active scene.")]
public bool UpdateAllScenes = true;
[Tooltip("Should ParticleSystems be moved with an origin shift.")]
public bool UpdateParticles = true;
[Tooltip("Should TrailRenderers be moved with an origin shift.")]
public bool UpdateTrailRenderers = true;
[Tooltip("Should LineRenderers be moved with an origin shift.")]
public bool UpdateLineRenderers = true;
private ParticleSystem.Particle[] parts = null;
VisualEffect[] visualEffect = null;
void LateUpdate()
{
if (ReferenceObject == null)
return;
Vector3 referencePosition = ReferenceObject.position;
if (Use2DDistance)
referencePosition.y = 0f;
if (referencePosition.magnitude > Threshold)
{
MoveRootTransforms(referencePosition);
if (UpdateParticles)
MoveParticles(referencePosition);
if (UpdateTrailRenderers)
MoveTrailRenderers(referencePosition);
if (UpdateLineRenderers)
MoveLineRenderers(referencePosition);
}
}
private void MoveRootTransforms(Vector3 offset)
{
if (UpdateAllScenes)
{
for (int z = 0; z < SceneManager.sceneCount; z++)
{
foreach (GameObject g in SceneManager.GetSceneAt(z).GetRootGameObjects())
g.transform.position -= offset;
}
}
else
{
foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
g.transform.position -= offset;
}
}
private void MoveTrailRenderers(Vector3 offset)
{
var trails = FindObjectsOfType<TrailRenderer>() as TrailRenderer[];
foreach (var trail in trails)
{
Vector3[] positions = new Vector3[trail.positionCount];
int positionCount = trail.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
trail.SetPositions(positions);
}
}
private void MoveLineRenderers(Vector3 offset)
{
var lines = FindObjectsOfType<LineRenderer>() as LineRenderer[];
foreach (var line in lines)
{
Vector3[] positions = new Vector3[line.positionCount];
int positionCount = line.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
line.SetPositions(positions);
}
}
private void MoveParticles(Vector3 offset)
{
var particles = FindObjectsOfType<ParticleSystem>() as ParticleSystem[];
foreach (ParticleSystem system in particles)
{
if (system.main.simulationSpace != ParticleSystemSimulationSpace.World)
continue;
int particlesNeeded = system.main.maxParticles;
if (particlesNeeded <= 0)
continue;
bool wasPaused = system.isPaused;
bool wasPlaying = system.isPlaying;
if (!wasPaused)
system.Pause();
// ensure a sufficiently large array in which to store the particles
if (parts == null || parts.Length < particlesNeeded)
{
parts = new ParticleSystem.Particle[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
var particles2 = FindObjectsOfType<VisualEffect>() as VisualEffect[];
foreach (VisualEffect system in particles2)
{
int particlesNeeded = system.aliveParticleCount;
if (particlesNeeded <= 0)
continue;
bool wasPaused = !system.isActiveAndEnabled;
bool wasPlaying = system.isActiveAndEnabled;
if (!wasPaused)
system.Stop();
// ensure a sufficiently large array in which to store the particles
if (visualEffect == null || visualEffect.Length < particlesNeeded)
{
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
}
}
On the line(this is a wrong line and everything below it too)
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
, I need to create a similar array to the line (correct one, but for the old particle system)
parts = new ParticleSystem.Particle[particlesNeeded];
that creates array full of particles (but with VisualEffect class).
If I can fix this one, there should not be any problem with the rest.
I think that solving this problem will help literally thousands of people now and in the future, since limitation for floating origin in unity are horrible and majority of people working in unity will need floating origin for their game worlds, with VFX graph particles.
Thanks for the help.
My question has been answered here:
https://forum.unity.com/threads/floating-origin-and-visual-effect-graph.962646/#post-6270837
unity 3d How can i calculate the distance between the end and each player in a straight line approach, then sort them by distance.
my code
float closest = 1000; //add your max range here
GameObject closestObject = null;
for (int i = 0; i < MyListOfObjects.Length; i++) //list of gameObjects to search through
{
float dist = Vector3.Distance(MyListOfObjects[i].transform.position, winpont.transform.position);
if (dist < closest)
{
closest = dist;
closestObject = MyListOfObjects[i];
closestObjects[i] = MyListOfObjects[i];
//if (closestObject.gameObject.tag == "Player")
//{
// print(MyListOfObjects[i]);
//}
print(MyListOfObjects[i].name);
}
}
You can use LINQ to order the collection by distance.
For Example:
var objects = new List<GameObject>(); // Collection of objects
var player = new GameObject();
// Sort object, It will return in typeof IEnumerable<T>
var sortedCollection = objects.OrderBy(obj => Vector3.Distance(player.transform.position, obj.transform.position));
// Convert your IEnumerable<T> to array or List as you wish
var sortedArray = sortedCollection.ToArray();
I'm spawning objects from a list and so-far i got them to find a parent object that's already live in the scene.The problem is Random.Range() isn't working like I want. I want the listed Objects to spawn to a random parent, instead, they're spawning to the they're parent relative to the order of the list.
Ex. 0,1,2,3,4,5,6,7,8,9 = Bad
Ex. 8,3,1,4,6,3,7,9,5,2 = Good
lol
var theRange = Random.Range(obj1.Length,obj1.Length);
for(var i: int = 0; i < theRange; i++){
var obj2 : GameObject = obj1[i];
if(obj2.transform.childCount == 0){
objfromList.transform.parent = obj2.transform;
objfromList.transform.localPosition = Vector3(0,-2,0);
}
}
Deeply thankful
Following up on my comment, it sounds like you just want a shuffle function. Here is a simple Fisher-Yates shuffle:
void shuffle(int[] a){
for(int i = a.Length-1; i>=0; i--){
int j = Random.Range(0,i);
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
void usage(){
int[] a = {0,1,2,3,4,5}; // assumes obj1.Length = 6
shuffle(a);
for(int i = 0; i < a.Length; i++){
GameObject obj2 = obj1[a[i]];
GameObject objFromList = GetNextObject(); // dummy method grabbing next list object
objFromList.transform.parent = obj2.transform;
objFromList.transform.localPosition = Vector3(0,-2,0);
}
}
This should get you part way to what you need. If the order of obj1 isn't important you can shuffle it directly instead of using a secondary array like a in my example.
I have a class which I used to overlay rectangles on maps. But I am not able to figure out how to remove the previous overlay's to draw new rectangles if a new set of results are provided to my displayOnMap method.
To provide more insight on the draw method. It takes in PlotSetOutput as an argument which contains centers and each center contains a set of lat/long co-ordinates. Hence the logic for looping over it and creating lat/long bounds and assigning it to rectangle objects.
public class displayOnMap extends Composite {
private final VerticalPanel pWidget;
private MapWidget mapWidget;
private static Rectangle rectangle;
private RectangleOptions rectOpts;
private static final LatLng USCENTER = LatLng.newInstance(33.68,-116.17);
public displayOnMap(PlotSetOutput result) {
pWidget = new VerticalPanel();
initWidget(pWidget);
draw(result);
}
private void draw(PlotSetOutput result) {
MapOptions mapOpts = MapOptions.newInstance();
mapOpts.setZoom(4);
mapOpts.setCenter(USCENTER);
mapOpts.setMapTypeId(MapTypeId.TERRAIN);
mapWidget = new MapWidget(mapOpts);
pWidget.add(mapWidget);
mapWidget.setSize("800px", "800px");
ArrayList<Centers> listOfCenters = new ArrayList<Centers>();
List<ResultClusterPlots> finalCluster = result.getFinalcluster();
int totalNumberOfClusters = result.getTotalNumberOfClusters();
for (int i = 0; i < totalNumberOfClusters; i++) {
listOfCenters.add(i, new Centers());
}
for (int j = 0; j < finalCluster.size(); j++) {
Centers p = listOfCenters.get(finalCluster.get(j).getClusterID()-1);
LatLng ne = LatLng.newInstance(finalCluster.get(j).getLatitude()
.get(0), finalCluster.get(j).getLongitude().get(0));
LatLng sw = LatLng.newInstance(finalCluster.get(j).getLatitude()
.get(1), finalCluster.get(j).getLongitude().get(1));
p.setLatLongArr(LatLngBounds.newInstance(ne,sw));
}
for (int k = 0; k < listOfCenters.size(); k++) {
ArrayList<LatLngBounds> ltlgBound = listOfCenters.get(k).getLatLongArr();
String color = getRandomColor();
for (int l = 0; l < ltlgBound.size(); l++) {
rectOpts = RectangleOptions.newInstance();
rectOpts.setStrokeColor("#FF0000");
rectOpts.setStrokeOpacity(0.3);
rectOpts.setStrokeWeight(2);
rectOpts.setFillColor(color);
rectOpts.setFillOpacity(0.35);
rectOpts.setMap(mapWidget);
rectOpts.setBounds(ltlgBound.get(l));
rectangle = Rectangle.newInstance(rectOpts);
rectangle.setMap(mapWidget);
}
}
}
}
Output when the method (displayOnMap) is invoked for the first time. Everything works fine.
Output when the displayOnMap method is called with a second query.
I tried to do rectangle.setMap(null); pWidget.removeFromParent(); but I kept getting the same result.
I have had the same problem, the only way I could hide / delete / show the overlays was through the OverlayCompleteMapEvent.
As I understand it isn't possible to get a hook to an overlay before it is completed, once it is completed the only way to get a hook on it is handling "OverlayCompleteMapEvent" event. I used a list to store the Overlays and then I could hide/show/delete them.