/// <summary> /// Returns the Cross Product of two vectors lhs and rhs /// </summary> /// <param name="lhs">Vector, the first input vector</param> /// <param name="rhs">Vector, the second input vector</param> /// <returns>A FloatVector3 containing the cross product of lhs and V</returns> public static FloatVector3 operator ^(FloatVector3 lhs, FloatVector3 rhs) { FloatVector3 Result = new FloatVector3(); Result.X = (lhs.Y * rhs.Z - lhs.Z * rhs.Y); Result.Y = (lhs.Z * rhs.X - lhs.X * rhs.Z); Result.Z = (lhs.X * rhs.Y - lhs.Y * rhs.X); return Result; }
/// <summary> /// Divides the components of vector lhs by the respective components /// ov vector V and returns the resulting vector. /// </summary> /// <param name="lhs">FloatVector3 Dividend (Numbers to be divided)</param> /// <param name="rhs">FloatVector3 Divisor (Numbers to divide by)</param> /// <returns>A FloatVector3 quotient of lhs and V</returns> /// <remarks>To prevent divide by 0, if a 0 is in V, it will return 0 in the result</remarks> public static FloatVector3 operator /(FloatVector3 lhs, FloatVector3 rhs) { FloatVector3 result = new FloatVector3(); if (rhs.X > 0) result.X = lhs.X / rhs.X; if (rhs.Y > 0) result.Y = lhs.Y / rhs.Y; if (rhs.Z > 0) result.Z = lhs.Z / rhs.Z; return result; }
/// <summary> /// Multiplies all the scalar members of the the two vectors /// </summary> /// <param name="lhs">Left hand side</param> /// <param name="rhs">Right hand side</param> /// <returns></returns> public static float Dot(FloatVector3 lhs, FloatVector3 rhs) { return lhs.X * rhs.X + lhs.Y * rhs.Y + lhs.Z * rhs.Z; }
/// <summary> /// Multiplies the source vector by a scalar. /// </summary> /// <param name="source"></param> /// <param name="scalar"></param> /// <returns></returns> public static FloatVector3 Multiply(FloatVector3 source, float scalar) { return new FloatVector3(source.X * scalar, source.Y * scalar, source.Z * scalar); }
/// <summary> /// Subtracts the specified value /// </summary> /// <param name="vector">A FloatVector3</param> public void Subtract(FloatVector3 vector) { X -= vector.X; Y -= vector.Y; Z -= vector.Z; }
/// <summary> /// Returns the Cross Product of two vectors lhs and V /// </summary> /// <param name="lhs">Vector, the first input vector</param> /// <param name="rhs">Vector, the second input vector</param> /// <returns>A FloatVector3 containing the cross product of lhs and V</returns> public static FloatVector3 CrossProduct(FloatVector3 lhs, FloatVector3 rhs) { FloatVector3 result = new FloatVector3(); result.X = (lhs.Y * rhs.Z - lhs.Z * rhs.Y); result.Y = (lhs.Z * rhs.X - lhs.X * rhs.Z); result.Z = (lhs.X * rhs.Y - lhs.Y * rhs.X); return result; }
/// <summary> /// Subtracts all the scalar members of the the two vectors /// </summary> /// <param name="lhs">Left hand side</param> /// <param name="rhs">Right hand side</param> /// <returns></returns> public static FloatVector3 Subtract(FloatVector3 lhs, FloatVector3 rhs) { return new FloatVector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z); }
/// <summary> /// Adds the specified v /// </summary> /// <param name="vector">A FloatVector3 to add to this vector</param> public void Add(FloatVector3 vector) { X += vector.X; Y += vector.Y; Z += vector.Z; }
/// <summary> /// Adds all the scalar members of the the two vectors /// </summary> /// <param name="lhs">Left hand side</param> /// <param name="rhs">Right hand side</param> /// <returns></returns> public static FloatVector3 Add(FloatVector3 lhs, FloatVector3 rhs) { return new FloatVector3(lhs.X + rhs.X, lhs.Y + rhs.Y, lhs.Z + rhs.Z); }
/// <summary> /// Create Hillshade of values ranging from 0 to 1, or -1 for no-data regions. /// This should be a little faster since we are accessing the Data field directly instead of working /// through a value parameter. /// </summary> /// <param name="raster">The raster to create the hillshade from.</param> /// <param name="shadedRelief">An implementation of IShadedRelief describing how the hillshade should be created.</param> /// <param name="progressHandler">An implementation of IProgressHandler for progress messages</param> public static float[][] CreateHillShade(this IRaster raster, IShadedRelief shadedRelief, IProgressHandler progressHandler) { int numCols = raster.NumColumns; int numRows = raster.NumRows; double noData = raster.NoDataValue; float extrusion = shadedRelief.Extrusion; float elevationFactor = shadedRelief.ElevationFactor; float lightIntensity = shadedRelief.LightIntensity; float ambientIntensity = shadedRelief.AmbientIntensity; FloatVector3 lightDirection = shadedRelief.GetLightDirection(); float[] aff = new float[6]; // affine coefficients converted to float format for (int i = 0; i < 6; i++) { aff[i] = Convert.ToSingle(raster.Bounds.AffineCoefficients[i]); } float[][] hillshade = new float[numRows][]; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.CreatingShadedRelief, numRows); for (int row = 0; row < numRows; row++) { hillshade[row] = new float[numCols]; for (int col = 0; col < numCols; col++) { // 3D position vectors of three points to create a triangle. FloatVector3 v1 = new FloatVector3(0f, 0f, 0f); FloatVector3 v2 = new FloatVector3(0f, 0f, 0f); FloatVector3 v3 = new FloatVector3(0f, 0f, 0f); double val = raster.Value[row, col]; // Cannot compute polygon ... make the best guess if (col >= numCols - 1 || row <= 0) { if (col >= numCols - 1 && row <= 0) { v1.Z = (float)val; v2.Z = (float)val; v3.Z = (float)val; } else if (col >= numCols - 1) { v1.Z = (float)raster.Value[row, col - 1]; // 3 - 2 v2.Z = (float)raster.Value[row - 1, col]; // | / v3.Z = (float)raster.Value[row - 1, col - 1]; // 1 * } else if (row <= 0) { v1.Z = (float)raster.Value[row + 1, col]; // 3* 2 v2.Z = (float)raster.Value[row, col + 1]; // | / v3.Z = (float)val; // 1 } } else { v1.Z = (float)val; // 3 - 2 v2.Z = (float)raster.Value[row - 1, col + 1]; // | / v3.Z = (float)raster.Value[row - 1, col]; // 1* } // Test for no-data values and don't calculate hillshade in that case if (v1.Z == noData || v2.Z == noData || v3.Z == noData) { hillshade[row][col] = -1; // should never be negative otherwise. continue; } // Apply the Conversion Factor to put elevation into the same range as lat/lon v1.Z = v1.Z * elevationFactor * extrusion; v2.Z = v2.Z * elevationFactor * extrusion; v3.Z = v3.Z * elevationFactor * extrusion; // Complete the vectors using the latitude/longitude coordinates v1.X = aff[0] + aff[1] * col + aff[2] * row; v1.Y = aff[3] + aff[4] * col + aff[5] * row; v2.X = aff[0] + aff[1] * (col + 1) + aff[2] * (row + 1); v2.Y = aff[3] + aff[4] * (col + 1) + aff[5] * (row + 1); v3.X = aff[0] + aff[1] * col + aff[2] * (row + 1); v3.Y = aff[3] + aff[4] * col + aff[5] * (row + 1); // We need two direction vectors in order to obtain a cross product FloatVector3 dir2 = FloatVector3.Subtract(v2, v1); // points from 1 to 2 FloatVector3 dir3 = FloatVector3.Subtract(v3, v1); // points from 1 to 3 FloatVector3 cross = FloatVector3.CrossProduct(dir3, dir2); // right hand rule - cross direction should point into page... reflecting more if light direction is in the same direction // Normalizing this vector ensures that this vector is a pure direction and won't affect the intensity cross.Normalize(); // Hillshade now has an "intensity" modifier that should be applied to the R, G and B values of the color found at each pixel. hillshade[row][col] = FloatVector3.Dot(cross, lightDirection) * lightIntensity + ambientIntensity; } pm.CurrentValue = row; } pm.Reset(); // Setting this indicates that a hillshade has been created more recently than characteristics have been changed. shadedRelief.HasChanged = false; return hillshade; }
/// <summary> /// Creates a CoordinateF by using the X, Y and Z terms of a FloatVector /// </summary> /// <param name="floatVector"></param> public CoordinateF(FloatVector3 floatVector) { _x = floatVector.X; _y = floatVector.Y; _z = floatVector.Z; _m = float.NaN; }