public Point3D cross(Point3D p) { return new Point3D( Y * p.Z - Z * p.Y, Z * p.X - X * p.Z, X * p.Y - Y * p.X ); }
public void parallelPath(ref List<double> EastingExp, ref List<double> NorthingExp, double displacement) { /////////////////////////////////////////////////////////////////////////////////////////////////////// //find a parallel path to the path stored in the polygonMath object //strategy: // consider the segments before and after the current ith point // find two points on these two segments that are equidistance from ith point // Form a line between these two points // The midpoint of this line and the original point form a bisector of the adjacent line // Move along this Bisector, outward, from the point by the desired epansion distance // take care with three edge vertices that are in a perfect line //////////////////////////////////////////////////////////////////////////////////////////////////////// Point3D s1 = new Point3D(); Point3D s2 = new Point3D(); Point3D u1 = new Point3D(); Point3D u2 = new Point3D(); double magP=0.0, magM=0.0; //take care of the interior points -- start-end points are special cases for (int i = 0; i < numLatLonPoints; i++) { if (i < numLatLonPoints - 1) //exclude last point fro below test { //note: X to the North, Y to the east and Z is down (right hand rule) double delXP = Northing[i + 1] - Northing[i]; double delYP = Easting[i + 1] - Easting[i]; magP = Math.Sqrt(delXP * delXP + delYP * delYP); //vector along segment s2 = new Point3D(delXP, delYP, 0.0); //unit vector orthogonal to and to the left of i->i+1 segment u2 = s2.unit(magP, s2.cross(new Point3D(0.0, 0.0, 1.0))); } if (i > 0) //exclude first point from below test { //test to see if the i-1->i point segment has zero length double delXM = Northing[i] - Northing[i-1]; double delYM = Easting[i] - Easting[i-1]; magM = Math.Sqrt(delXM * delXM + delYM * delYM); //vector along segment s1 = new Point3D(delXM, delYM, 0.0); //unit vector orthogonal to and to the left of ith segment u1 = s1.unit(magM, s1.cross(new Point3D(0.0, 0.0, 1.0))); } //handle the special cases for the first and last if (i == 0 ) //first point { NorthingExp.Add(Northing[i] + displacement * u2.X); EastingExp.Add(Easting[i] + displacement * u2.Y); continue; } else if ( i == (numLatLonPoints - 1)) //last point { NorthingExp.Add(Northing[i] + displacement * u1.X); EastingExp.Add(Easting[i] + displacement * u1.Y); continue; } //compute theta -- signed angle between unit vectors double sinTheta = u1.cross(u2).Z; //sign indicates the direction of the turn (to right or to left) double cosTheta = u1.dot(u2); //should be positve if the abs(angle change) is < 90 deg //gives an angle between +/- 90 deg double theta = Math.Atan2(sinTheta, cosTheta); //force the angle to be between 0-180 deg; //if (theta < 0) theta += Math.PI / 2.0; //two cases depending on the angle between the two neighbor segments //parallel path always placed the left of the input path //TODO -- need to offer an option of right or left or centered parallel paths if (sinTheta > 0) { //compute point on the parallel path -- partallel path segments are parallel to input path segments NorthingExp.Add(Northing[i] + displacement * ((u1.X + u2.X) / 2.0) / Math.Cos(theta / 2.0 ) ); EastingExp.Add(Easting[i] + displacement * ((u1.Y + u2.Y) / 2.0) / Math.Cos(theta / 2.0 ) ); } else { //compute point on the parallel path -- partallel path segments are parallel to input path segments double beta = Math.PI - theta; //also restricted to 0-180 deg NorthingExp.Add(Northing[i] + displacement * ((u1.X + u2.X) / 2.0) / Math.Cos(theta / 2.0)); EastingExp.Add(Easting[i] + displacement * ((u1.Y + u2.Y) / 2.0) / Math.Cos(theta / 2.0)); } } }
public Point3D unit(double magnitude, Point3D p) { return new Point3D( p.X/magnitude, p.Y/magnitude, p.Z/magnitude); }
public double dot(Point3D p) { return X * p.X + Y * p.Y + Z * p.Z; }