/// <summary> /// True = everything ok /// </summary> public static bool CheckProblems() { Reset(); CheckPath("Forest", CParameterSetter.GetStringSettings(ESettings.forestFileFullName), true); //if(!CRxpParser.IsRxp) //{ // CheckPath("Reftree", CParameterSetter.GetStringSettings(ESettings.reftreeFolderPath), false); //} CheckPath("Output", CParameterSetter.GetStringSettings(ESettings.outputFolderPath), false); if (CParameterSetter.GetBoolSettings(ESettings.useCheckTreeFile)) { CheckPath("Checktree", CParameterSetter.GetStringSettings(ESettings.checkTreeFilePath), true); } CheckRange(); CheckExport(); if (CShpController.exportShape) { if (CParameterSetter.GetBoolSettings(ESettings.calculateDBH)) { CheckDBH(); } if (CParameterSetter.GetBoolSettings(ESettings.calculateAGB)) { CheckAGB(); } CheckTreeRadius(); } bool hasProblems = problems.Count > 0; if (hasProblems) { CDebug.WriteProblems(problems); problems.Clear(); } return(!hasProblems); }
/// <summary> /// Calculates similarity between this reference tree and given tree /// Returns [0,1]. 1 = best match /// </summary> public static STreeSimilarity GetSimilarityWith(CRefTree pRefTree, CTree pOtherTree) { Vector3 offsetToRefTree = GetOffsetTo(pOtherTree, pRefTree); float scaleRatio = GetScaleRatioTo(pOtherTree, pRefTree); Matrix4x4 scaleMatrix = Matrix4x4.CreateScale(scaleRatio, scaleRatio, scaleRatio, pRefTree.peak.Center); int indexOffset = GetIndexOffsetBetweenBestMatchBranches(pRefTree, pOtherTree); float similarity = 0; int definedSimilarityCount = 0; foreach (CBranch otherBranch in pOtherTree.Branches) { int indexOfOtherBranch = pOtherTree.Branches.IndexOf(otherBranch); //int offsetBranchIndex = (indexOfOtherBranch + indexOffset) % branches.Count; int offsetBranchIndex = indexOfOtherBranch + indexOffset; if (offsetBranchIndex < 0) { offsetBranchIndex = pRefTree.Branches.Count + offsetBranchIndex; } CBranch refBranch = pRefTree.Branches[offsetBranchIndex % pRefTree.Branches.Count]; float similarityWithOtherBranch = refBranch.GetSimilarityWith(otherBranch, offsetToRefTree, scaleMatrix); if (similarityWithOtherBranch >= 0) { similarity += similarityWithOtherBranch; definedSimilarityCount++; } } //CDebug.WriteLine("\n---------------\nsimilarity of \n" + pRefTree + "\nwith \n" + pOtherTree); if (definedSimilarityCount == 0) { CDebug.WriteLine("Error. no similarity defined"); return(new STreeSimilarity(0, 0)); } similarity /= definedSimilarityCount; //CDebug.WriteLine("similarity = " + similarity + ". defined = " + definedSimilarityCount + "\n--------"); return(new STreeSimilarity(similarity, indexOffset * CTree.BRANCH_ANGLE_STEP)); }
private void AddPoint(Tuple <EClass, Vector3> pParsedLine) { Vector3 point = pParsedLine.Item2; switch (pParsedLine.Item1) { case EClass.Undefined: case EClass.Unassigned: unassigned.Add(point); break; case EClass.Ground: ground.Add(point); break; case EClass.Vege: vege.Add(point); break; case EClass.Building: building.Add(point); break; default: CDebug.Warning($"point class {pParsedLine.Item1} not recognized"); return; } float height = point.Z; if (height < lowestHeight) { lowestHeight = height; } if (height > highestHeight) { highestHeight = height; } }
/// <summary> /// Calculates similarity with other branch. /// Range = [0,1]. 1 = Best match. /// </summary> public float GetSimilarityWith(CBranch pOtherBranch, Vector3 offsetToThisTree, Matrix4x4 scaleMatrix) { if (pOtherBranch.TreePoints.Count == 0) { if (TreePoints.Count == 0) { return(1); } //situation when other branch has no points. //this can mean that data in this part of tree are just missing therefore it should return(UNDEFINED_SIMILARITY); } float similarity = 0; //CreateRotationY rotates point counter-clockwise => -pAngleOffset //rotation has to be calculated in each branch float angleOffsetRadians = CUtils.ToRadians(-(angleFrom - pOtherBranch.angleFrom)); Matrix4x4 rotationMatrix = Matrix4x4.CreateRotationY(angleOffsetRadians, tree.peak.Center); foreach (CTreePoint p in pOtherBranch.TreePoints) { Vector3 movedPoint = p.Center + offsetToThisTree; Vector3 scaledPoint = Vector3.Transform(movedPoint, scaleMatrix); Vector3 rotatedPoint = Vector3.Transform(scaledPoint, rotationMatrix); const int branchToleranceMultiply = 2; if (Contains(rotatedPoint, branchToleranceMultiply)) { similarity += 1f / pOtherBranch.TreePoints.Count; } } if (similarity - 1 > 0.1f) //similarity can be > 1 due to float imprecision { CDebug.Error("Similarity rounding error too big. " + similarity); } similarity = Math.Min(1, similarity); return(similarity); }
/// <summary> /// Add points from given class to the output and main output /// </summary> private static void AddPointsTo(ref StringBuilder pOutput, EClass pClass, ref DateTime start) { List <Vector3> points = CProjectData.Points.GetPoints(pClass); string res; DateTime lastDebug = DateTime.Now; for (int i = 0; i < points.Count; i++) { if (CProjectData.backgroundWorker.CancellationPending) { return; } CDebug.Progress(i, points.Count, DEBUG_FREQUENCY, ref lastDebug, start, "Export las (ground points)"); Vector3 p = points[i]; CVector3D globalP = CUtils.GetGlobalPosition(p); res = GetPointLine(globalP, 1, 0, GetClassColor(pClass)) + newLine; pOutput.Append(res); } //mainOutput.Append(pOutput); }
public override void FillMissingHeight(EFillMethod pMethod, int pParam) { if (IsDetail && Equals(192, 177)) { CDebug.WriteLine(); } if (heightFilled) { return; } float?maxNeighbour = GetMaxHeightFromNeigbourhood(); float?height = GetHeight(); if ((height == null || maxNeighbour == null) || maxNeighbour > height && maxNeighbour - height > 0.3f) { heightFilled = false; } else { heightFilled = true; return; } if (MaxFilledHeight != null) { return; } switch (pMethod) { case EFillMethod.FromNeighbourhood: //MaxFilledHeight = GetAverageHeightFromNeighbourhood(pKernelMultiplier); MaxFilledHeight = GetKRankHeightFromNeigbourhood(pParam); break; } }
public static void SetValues() { if (configs.Count == 0) { return; } CDebug.WriteLine("SetValues from config"); SSequenceConfig currentConfig = configs[currentConfigIndex]; CParameterSetter.SetParameter(ESettings.forestFileFullName, currentConfig.path); int treeHeight = currentConfig.treeHeight; CParameterSetter.SetParameter(ESettings.autoAverageTreeHeight, treeHeight <= 0); if (treeHeight > 0) { CParameterSetter.SetParameter(ESettings.avgTreeHeigh, treeHeight); } CParameterSetter.SetParameter(ESettings.treeExtent, currentConfig.treeExtent); CParameterSetter.SetParameter(ESettings.treeExtentMultiply, currentConfig.treeExtentMultiply); }
internal static string ProcessForestFolder() { //string forestFolder = CParameterSetter.GetStringSettings(ESettings.forestFolderPath); DirectoryInfo forestFolder = new DirectoryInfo(CParameterSetter.GetStringSettings(ESettings.forestFolderPath)); if (!forestFolder.Exists) { CDebug.Error("forestFolderPath not set"); return(""); } string outputFilePath = forestFolder.FullName + $"\\{forestFolder.Name}_merged.laz"; //merge all LAS and LAX files in the folder into 1 file string merge = "lasmerge -i " + forestFolder.FullName + "\\*.las " + forestFolder.FullName + "\\*.laz " + " -o " + outputFilePath; CCmdController.RunLasToolsCmd(merge, outputFilePath); return(outputFilePath); }
public void AddPointInField(Vector3 pPoint, bool pLogErrorInAnalytics = true) { if (CDebug.IsDebugPoint(pPoint)) { //CDebug.WriteLine(""); } Tuple <int, int> index = GetIndexInArray(pPoint); if (!IsWithinBounds(index)) { CDebug.Error($"point {pPoint} is OOB {index}", pLogErrorInAnalytics); index = GetIndexInArray(pPoint); return; } TypeField field = array[index.Item1, index.Item2]; if (field.IsPointOutOfField(pPoint)) { CDebug.Error($"point {pPoint} is too far from center {field.Center}"); index = GetIndexInArray(pPoint); field.IsPointOutOfField(pPoint); } if (pPoint.Z > MaxHeight) { MaxHeight = pPoint.Z; } if (pPoint.Z < MinHeight) { MinHeight = pPoint.Z; } pointsCount++; sumZ += pPoint.Z; array[index.Item1, index.Item2].AddPoint(pPoint); }
private void SetValues(Vector3 pScaleFactor, Vector3 pOffset, CVector3D pMin, CVector3D pMax) { ScaleFactor = pScaleFactor; Offset = pOffset; //Offset.Z = 0; //given Z offset will not be used Min_orig = pMin; CVector3D minDouble = Min_orig - Offset; Min = (Vector3)minDouble; Max_orig = pMax; CVector3D maxDouble = Max_orig - Offset; Max = (Vector3)maxDouble; if (Min == Vector3.Zero && Max == Vector3.Zero) { CDebug.Error("Invalid header. Creating default header."); const int defaultArraySize = 15; Min = new Vector3(-defaultArraySize, -defaultArraySize, 0); Max = new Vector3(defaultArraySize, defaultArraySize, 0); Offset = Vector3.Zero; } }
internal static void TransformArrayIndexToBitmapIndex(ref Tuple <int, int> pArrayIndex, CHeaderInfo pArrayHeader, float pStepSize, Bitmap pMap) { float xPercent = pArrayIndex.Item1 * pStepSize / pArrayHeader.Width; float yPercent = pArrayIndex.Item2 * pStepSize / pArrayHeader.Height; yPercent = 1 - yPercent; //bitmap has different orientation than our array if (xPercent < 0 || xPercent > 1 || yPercent < 0 || yPercent > 1) { CDebug.Error($"wrong transformation! x = {xPercent}, y = {yPercent}"); xPercent = 0; yPercent = 0; } int bitmapXindex = (int)((pMap.Width - 1) * xPercent); int bitmapYindex = (int)((pMap.Height - 1) * yPercent); //array is oriented from bot to top, bitmap top to bot bitmapYindex = pMap.Height - bitmapYindex - 1; pArrayIndex = new Tuple <int, int>(bitmapXindex, bitmapYindex); }
protected override void OnProcess() { string filePath = GetRefTreeFilePath(fileName, fileName + ".reftree"); CDebug.WriteLine("\nfilePath = " + filePath); if (File.Exists(filePath)) { if (!IsCurrentVersion()) { File.Delete(filePath); CDebug.Warning($"deleting old .reftree file ({filePath})"); } else { CDebug.Error(".reftree file already exists ({filePath})"); } //return; } DateTime processStartTime = DateTime.Now; CDebug.WriteLine("Serialization"); List <string> serializedTree = Serialize(); version = CURRENT_REFTREE_VERSION; using (StreamWriter file = new StreamWriter(filePath, false)) { foreach (string line in serializedTree) { file.WriteLine(line); } } CDebug.Duration("Serialized", processStartTime); CDebug.WriteLine("saved to: " + filePath); }
private static string GetPreprocessedFilePath() { DateTime getPreprocessedFilePathStart = DateTime.Now; DateTime start = DateTime.Now; CDebug.Progress(1, 3, 1, ref start, getPreprocessedFilePathStart, "classifyFilePath", true); string classifyFilePath = CPreprocessController.GetClassifiedFilePath(); if (CRxpParser.IsRxp) { return(classifyFilePath); } /////// lassplit ////////// CDebug.Step(EProgramStep.Pre_Split); CDebug.Progress(2, 3, 1, ref start, getPreprocessedFilePathStart, "splitFilePath", true); //split mode = NONE => split file is same as classified file string splitFilePath = classifyFilePath; switch ((ESplitMode)CParameterSetter.GetIntSettings(ESettings.currentSplitMode)) { case ESplitMode.Manual: splitFilePath = CPreprocessController.LasSplit(classifyFilePath); break; case ESplitMode.Shapefile: splitFilePath = CPreprocessController.LasClip(classifyFilePath); break; } return(splitFilePath); }
private static string GetFileExportPath(string pFileName, string pFolder) { string fileName = pFileName.Length > 0 ? pFileName : DEFAULT_FILENAME; string chosenFileName = fileName; string extension = ".Obj"; string path = pFolder; if (!Directory.Exists(path)) { CDebug.Error("Given folder does not exist! " + pFolder); path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\output\\"; } string fullPath = path + chosenFileName + extension; int fileIndex = 0; while (File.Exists(fullPath)) { chosenFileName = fileName + "_" + fileIndex; fullPath = path + chosenFileName + extension; fileIndex++; } return(fullPath); }
public List <Vector3> GetPoints(EClass pClass) { switch (pClass) { case EClass.Unassigned: //points has been filtered out in fields only if (CTreeManager.GetDetectMethod() == EDetectionMethod.Balls) { return(ballArray.GetPoints()); } return(unassigned); case EClass.Balls: return(ballPoints); case EClass.BallsMainPoints: return(ballsMainPoints); case EClass.BallsCenters: return(ballsCenters); case EClass.BallsSurface: return(ballsSurface); case EClass.Ground: return(ground); case EClass.Vege: return(vege); case EClass.Building: return(building); } CDebug.Error($"Points of class {pClass} not defined"); return(null); }
private void ProcessUnassignedPoints() { DateTime debugStart = DateTime.Now; DateTime previousDebugStart = DateTime.Now; for (int i = 0; i < unassigned.Count; i++) { if (CProjectData.backgroundWorker.CancellationPending) { return; } CDebug.Progress(i, unassigned.Count, 100000, ref previousDebugStart, debugStart, "ProcessUnassignedPoints"); if (CProjectData.backgroundWorker.CancellationPending) { return; } Vector3 point = unassigned[i]; unassignedArray.AddPointInField(point); if (CTreeManager.GetDetectMethod() == EDetectionMethod.Balls) { ballArray.AddPointInField(point); } } if (CTreeManager.GetDetectMethod() == EDetectionMethod.Balls) { //unassignedArray.FillArray(); //doesnt make sense const bool filterBasedOnheight = false; //balls are expected to be in this height above ground if (filterBasedOnheight) { ballArray.FilterPointsAtHeight(1.8f, 2.7f); } //add filtered points to detail array List <Vector3> filteredPoints = ballArray.GetPoints(); foreach (Vector3 point in filteredPoints) { if (CProjectData.backgroundWorker.CancellationPending) { return; } ballDetailArray.AddPointInField(point); } List <CBallField> ballFields = new List <CBallField>(); //vege.Sort((b, a) => a.Z.CompareTo(b.Z)); //sort descending by height List <CBallField> sortedFields = ballDetailArray.fields; //sortedFields.Sort((a, b) => a.indexInField.Item1.CompareTo(b.indexInField.Item1)); //sortedFields.Sort((a, b) => a.indexInField.Item2.CompareTo(b.indexInField.Item2)); sortedFields.OrderBy(a => a.indexInField.Item1).ThenBy(a => a.indexInField.Item2); //List<Vector3> mainPoints = new List<Vector3>(); debugStart = DateTime.Now; previousDebugStart = DateTime.Now; //process for (int i = 0; i < sortedFields.Count; i++) { if (CProjectData.backgroundWorker.CancellationPending) { return; } CDebug.Progress(i, sortedFields.Count, 100000, ref previousDebugStart, debugStart, "Detecting balls"); CBallField field = (CBallField)sortedFields[i]; field.Detect(); if (field.ball != null && field.ball.isValid) { ballFields.Add(field); ballsMainPoints.AddRange(field.ball.GetMainPoints(true)); ballsCenters.Add(field.ball.center); ballsCenters.AddRange(CUtils.GetPointCross(field.ball.center)); //return; ballsSurface.AddRange(field.ball.GetSurfacePoints()); } } foreach (CBallField field in ballFields) { ballPoints.AddRange(field.points); } } }
private static void AddTreesToBitmap(CVegeArray pArray, Bitmap pBitmap, bool pTreePostition, bool pTreeBorder) { List <CTree> allTrees = new List <CTree>(); allTrees.AddRange(CTreeManager.Trees); allTrees.AddRange(CTreeManager.InvalidTrees); foreach (CTree tree in allTrees) { try { CVegeField fieldWithTree = pArray.GetFieldContainingPoint(tree.peak.Center); if (fieldWithTree == null) { CDebug.Error($"tree {tree.treeIndex} field = null"); continue; } int x = fieldWithTree.indexInField.Item1; int y = fieldWithTree.indexInField.Item2; if (IsOOB(x, y, pBitmap)) { CDebug.Error($"{x},{y} is OOB {pBitmap.Width}x{pBitmap.Height}"); continue; } //draw branch extents if (pTreeBorder && tree.isValid) { List <Vector3> furthestPoints = tree.GetFurthestPoints(); // new List<Vector3>(); //foreach(CBranch branch in tree.Branches) //{ // furthestPoints.Add(branch.furthestPoint); //} for (int i = 0; i < furthestPoints.Count; i++) { Vector3 furthestPoint = furthestPoints[i]; Vector3 nextFurthestPoint = furthestPoints[(i + 1) % furthestPoints.Count]; CVegeField fieldWithFP1 = pArray.GetFieldContainingPoint(furthestPoint); CVegeField fieldWithFP2 = pArray.GetFieldContainingPoint(nextFurthestPoint); if (fieldWithFP1 == null || fieldWithFP2 == null) { CDebug.Error($"futhest points {furthestPoint} + {nextFurthestPoint} - no field assigned"); continue; } int x1 = fieldWithFP1.indexInField.Item1; int y1 = fieldWithFP1.indexInField.Item2; int x2 = fieldWithFP2.indexInField.Item1; int y2 = fieldWithFP2.indexInField.Item2; using (Graphics g = Graphics.FromImage(pBitmap)) { g.DrawLine(treeBorderPen, x1, y1, x2, y2); } } foreach (CBranch branch in tree.Branches) { CVegeField fieldWithBranch = pArray.GetFieldContainingPoint(branch.furthestPoint); if (fieldWithBranch == null) { CDebug.Error($"branch {branch} is OOB"); continue; } int _x = fieldWithBranch.indexInField.Item1; int _y = fieldWithBranch.indexInField.Item2; using (Graphics g = Graphics.FromImage(pBitmap)) { g.DrawLine(branchPen, x, y, _x, _y); } } } //mark tree position if (pTreePostition) { DrawTreeOnBitmap(pBitmap, tree, x, y); bool isAtBufferZone = CTreeMath.IsAtBufferZone(tree); if (exportMain && !isAtBufferZone) { //Tuple<int, int> posInMain = CGroundArray.GetPositionInArray( // tree.peak.Center, CProjectData.mainHeader.TopLeftCorner, mainMapStepSize); //CUtils.TransformArrayIndexToBitmapIndex(ref posInMain, // CProjectData.mainHeader, mainMapStepSize, mainMap); Tuple <int, int> posInMain = GetIndexInMainBitmap(tree.peak.Center); x = posInMain.Item1; y = posInMain.Item2; if (posInMain == null) { continue; } Color color = mainMap.GetPixel(x, y); if (!IsTreeColoured(color)) { DrawTreeOnBitmap(mainMap, tree, x, y); } } } } catch (Exception e) { CDebug.Error(e.Message); } } }
public static void ProcessParsedLines(List <Tuple <EClass, Vector3> > parsedLines) { CAnalytics.loadedPoints = parsedLines.Count; CProjectData.Points.AddPointsFromLines(parsedLines); CObjPartition.AddGroundArrayObj(); if (CParameterSetter.GetBoolSettings(ESettings.exportPoints)) { CObjPartition.AddPoints(EClass.Unassigned); CObjPartition.AddPoints(EClass.Ground); CObjPartition.AddPoints(EClass.Vege); CObjPartition.AddPoints(EClass.Building); } CDebug.Count("Trees", CTreeManager.Trees.Count); CTreeManager.CheckAllTrees(); CDebug.Step(EProgramStep.ValidateTrees1); //dont move invalid trees to invalid list yet, some invalid trees will be merged CTreeManager.ValidateTrees(false, false); //export before merge if (CProjectData.exportBeforeMerge) { CTreeManager.AssignMaterials(); //call before export CObjPartition.AddTrees(true); CObjPartition.AddTrees(false); CObjPartition.ExportPartition("_noMerge"); CObjPartition.Init(); //CObjPartition.AddArray(); } CAnalytics.firstDetectedTrees = CTreeManager.Trees.Count; CDebug.Step(EProgramStep.MergeNotTrees1); CTreeManager.TryMergeNotTrees(); CDebug.Step(EProgramStep.MergeTrees1); //try merge all (even valid) EDetectionMethod detectionMethod = CTreeManager.GetDetectMethod(); if ((detectionMethod == EDetectionMethod.AddFactor || detectionMethod == EDetectionMethod.Detection2D ) && CProjectData.tryMergeTrees) { CTreeManager.TryMergeAllTrees(false); } CAnalytics.afterFirstMergedTrees = CTreeManager.Trees.Count; //validate restrictive bool cathegorize = false; if (detectionMethod == EDetectionMethod.Detection2D) { cathegorize = true; } CDebug.Step(EProgramStep.ValidateTrees2); CTreeManager.ValidateTrees(cathegorize, true); CDebug.Step(EProgramStep.MergeTrees2); if (detectionMethod == EDetectionMethod.AddFactor) { //merge only invalid if (CProjectData.tryMergeTrees2) { CTreeManager.TryMergeAllTrees(true); } } //try merging not-trees again after trees were merged CDebug.Step(EProgramStep.MergeNotTrees2); CTreeManager.TryMergeNotTrees(); CDebug.Step(EProgramStep.ValidateTrees3); if (detectionMethod == EDetectionMethod.AddFactor) { //validate restrictive //cathegorize invalid trees CTreeManager.ValidateTrees(true, true, true); } //todo: just debug //CTreeManager.CheckAllTrees(); CAnalytics.detectedTrees = CTreeManager.Trees.Count; CAnalytics.invalidTrees = CTreeManager.InvalidTrees.Count; CAnalytics.invalidTreesAtBorder = CTreeManager.GetInvalidTreesAtBorderCount(); CAnalytics.inputAverageTreeHeight = CTreeManager.AVERAGE_TREE_HEIGHT; CAnalytics.averageTreeHeight = CTreeManager.GetAverageTreeHeight(); CAnalytics.maxTreeHeight = CTreeManager.MaxTreeHeight; CAnalytics.minTreeHeight = CTreeManager.GetMinTreeHeight(); CDebug.Count("Trees", CTreeManager.Trees.Count); CDebug.Count("InvalidTrees", CTreeManager.InvalidTrees.Count); //CProjectData.array.DebugDetectedTrees(); CTreeManager.AssignMaterials(); CDebug.Step(EProgramStep.AssignReftrees); CReftreeManager.AssignRefTrees(); if (CParameterSetter.GetBoolSettings(ESettings.exportRefTrees)) //no reason to export when no refTrees were assigned { //CRefTreeManager.ExportTrees(); CObjPartition.AddRefTrees(); } CObjPartition.AddTrees(true); if (CParameterSetter.GetBoolSettings(ESettings.exportInvalidTrees)) { CObjPartition.AddTrees(false); } }
public static void Write(bool pToFile) { string output = " - ANALYTICS - " + newLine2; output += $"treeExtent = {CParameterSetter.GetFloatSettings(ESettings.treeExtent)} " + newLine; output += $"treeExtentMultiply = {CParameterSetter.GetFloatSettings(ESettings.treeExtentMultiply)} " + newLine2; output += $"loadedPoints = {loadedPoints} " + newLine; output += $"vegePoints = {vegePoints} " + newLine; output += $"groundPoints = {groundPoints} " + newLine; output += $"unassignedPoints = {unassignedPoints} " + newLine; output += $"buildingPoints = {buildingPoints} " + newLine; output += $"filteredPoints = {filteredPoints}" + newLine2; output += $"arrayWidth = {arrayWidth} m" + newLine; output += $"arrayHeight = {arrayHeight} m" + newLine2; output += $"firstDetectedTrees = {firstDetectedTrees} " + newLine; output += $"firstMergedCount = {GetFirstMergedCount()} " + newLine; output += $"secondMergedCount = {GetSecondMergedCount()} " + newLine; output += $"detectedTrees = {detectedTrees} " + newLine; output += $"trees density = 1 per {GetTreesDensity():0.00} m\xB2 " + newLine; output += $"invalidTrees = {invalidTrees} ({invalidTreesAtBorder} of them at border)\n" + newLine; output += $"inputAverageTreeHeight = {inputAverageTreeHeight} " + newLine; output += $"averageTreeHeight = {averageTreeHeight} " + newLine; output += $"maxTreeHeight = {maxTreeHeight} " + newLine; output += $"minTreeHeight = {minTreeHeight}" + newLine2; output += $"loadedReftrees = {loadedReftrees} " + newLine; output += $"averageReftreeSimilarity = {averageReftreeSimilarity} " + newLine2; output += "Duration" + newLine; output += $"load reftrees = {loadReftreesDuration} " + newLine; output += $"fill missing ground = {fillAllHeightsDuration} " + newLine; output += $"add vege points = {processVegePointsDuration} " + newLine; output += $"first merge = {firstMergeDuration} " + newLine; output += $"second merge = {secondMergeDuration} " + newLine; output += $"reftree assignment = {reftreeAssignDuration} " + newLine; output += $"bitmap export = {bitmapExportDuration} " + newLine; output += $"las export = {lasExportDuration} " + newLine; output += $"-------------------" + newLine; output += $"total = {totalDuration} " + newLine; if (CParameterSetter.GetBoolSettings(ESettings.useCheckTreeFile)) { output += "Checktree" + newLine; output += $"loadedCheckTrees = {loadedCheckTrees} " + newLine; output += $"assignedCheckTrees = {assignedCheckTrees} " + newLine; output += $"invalidCheckTrees = {invalidCheckTrees} " + newLine; } output += $"\nERRORS" + newLine; int counter = 0; const int MAX_ERROR_DEBUG = 100; foreach (string error in errors) { output += $"- {error} " + newLine; counter++; if (counter > MAX_ERROR_DEBUG) { break; } } //before WriteToFile (it can fail there too) errors.Clear(); //reset, so errors dont stack with previous error CDebug.WriteLine(output); if (pToFile) { WriteToFile(output); //ExportCsv(ECsvAnalytics.InputParams); //ExportCsv(ECsvAnalytics.ComputationTime); ExportCsv(ECsvAnalytics.Summary); //probably enough } }
/// <summary> /// Merges all trees, whose peak has good AddFactor to another tree /// </summary> private static void MergeGoodAddFactorTrees(bool pOnlyInvalid) { DateTime mergeStart = DateTime.Now; DateTime previousMergeStart = DateTime.Now; int iteration = 0; int maxIterations = Trees.Count; for (int i = Trees.Count - 1; i >= 0; i--) { if (CProjectData.backgroundWorker.CancellationPending) { return; } if (i >= Trees.Count) { //CDebug.WriteLine("Tree was deleted"); continue; } CTree treeToMerge = Trees[i]; if (treeToMerge.treeIndex == 48 || treeToMerge.treeIndex == 1001) { CDebug.WriteLine(""); } if (pOnlyInvalid && !treeToMerge.isValid && treeToMerge.IsAtBorder()) { //CDebug.Warning(treeToMerge + " is at border"); continue; } //dont merge tree if it is local maximum //if some tree is very close (in neighbouring detail field) //merge it with the highest one if (detectMethod == EDetectionMethod.AddFactor2D) { if (treeToMerge.Equals(22)) { CDebug.WriteLine(); } if (treeToMerge.IsLocalMaximum()) { continue; } CTreeField f = CProjectData.Points.treeDetailArray.GetFieldContainingPoint(treeToMerge.peak.Center); List <CTree> treesInHood = f.GetDetectedTreesFromNeighbourhood(); foreach (CTree tree in treesInHood) { if (tree.Equals(treeToMerge)) { continue; } MergeTrees(tree, treeToMerge); break; } continue; } List <CTree> possibleTrees = GetPossibleTreesToMergeWith(treeToMerge, EPossibleTreesMethod.ClosestHigher); Vector3 pPoint = treeToMerge.peak.Center; float bestAddPointFactor = 0; CTree selectedTree = null; foreach (CTree possibleTree in possibleTrees) { bool isFar = false; bool isSimilarHeight = false; if (possibleTree.isValid && treeToMerge.isValid) { float mergeFactor = GetMergeValidFacor(treeToMerge, possibleTree); if (mergeFactor > 0.9f) { selectedTree = possibleTree; break; } } if (pOnlyInvalid && possibleTree.isValid && treeToMerge.isValid) { continue; } if (treeToMerge.isValid) { //treeToMerge is always lower float possibleTreeHeight = possibleTree.GetTreeHeight(); float treeToMergeHeight = treeToMerge.GetTreeHeight(); const float maxPeaksDistance = 1; float peaksDist = CUtils.Get2DDistance(treeToMerge.peak, possibleTree.peak); if (peaksDist > maxPeaksDistance) { isFar = true; } const float maxPeakHeightDiff = 1; if (possibleTreeHeight - treeToMergeHeight < maxPeakHeightDiff) { isSimilarHeight = true; } } float addPointFactor = possibleTree.GetAddPointFactor(pPoint, treeToMerge); float requiredFactor = 0.5f; if (isFar) { requiredFactor += 0.1f; } if (isSimilarHeight) { requiredFactor += 0.1f; } if (pOnlyInvalid) { requiredFactor -= 0.2f; } if (addPointFactor > requiredFactor && addPointFactor > bestAddPointFactor) { selectedTree = possibleTree; bestAddPointFactor = addPointFactor; if (bestAddPointFactor > 0.9f) { break; } } } if (selectedTree != null) { float dist = CUtils.Get2DDistance(treeToMerge.peak.Center, selectedTree.peak.Center); treeToMerge = MergeTrees(ref treeToMerge, ref selectedTree, pOnlyInvalid); } CDebug.Progress(iteration, maxIterations, 50, ref previousMergeStart, mergeStart, "merge"); iteration++; } }
private static EProcessResult ProcessTile(string pTilePath, int pTileIndex) { //has to reinit first for the correct progress output CDebug.ReInit(); DateTime startTime = DateTime.Now; currentTileIndex = pTileIndex; List <Tuple <EClass, Vector3> > parsedLines; if (CRxpParser.IsRxp) { CRxpInfo rxpInfo = CRxpParser.ParseFile(pTilePath); parsedLines = rxpInfo.ParsedLines; //for now we expect only one tile in rxp processing CProjectData.currentTileHeader = rxpInfo.Header; CProjectData.mainHeader = rxpInfo.Header; } else { string[] lines = CProgramLoader.GetFileLines(pTilePath); bool linesOk = lines != null && lines.Length > 0 && !string.IsNullOrEmpty(lines[0]); if (linesOk && CHeaderInfo.HasHeader(lines[0])) { //todo: where to init header? CProjectData.currentTileHeader = new CHeaderInfo(lines); } else { const string noHeaderMsg = "Processed tile has no header"; CDebug.Error(noHeaderMsg); throw new Exception(noHeaderMsg); } parsedLines = CProgramLoader.ParseLines(lines, true); } //has to be called after currentTileHeader is assigned CProjectData.ReInit(pTileIndex); //has to reinit after each tile is processed CTreeManager.Reinit(); if (CProjectData.backgroundWorker.CancellationPending) { return(EProcessResult.Cancelled); } CProgramLoader.ProcessParsedLines(parsedLines); if (CProjectData.backgroundWorker.CancellationPending) { return(EProcessResult.Cancelled); } CTreeManager.DebugTrees(); CDebug.Step(EProgramStep.Export3D); CObjPartition.ExportPartition("", "tile" + pTileIndex); if (CProjectData.backgroundWorker.CancellationPending) { return(EProcessResult.Cancelled); } //has to be called after ExportPartition where final folder location is determined try { CDebug.Step(EProgramStep.Bitmap); CBitmapExporter.Export(pTileIndex); } catch (Exception e) { CDebug.Error("exception: " + e.Message); } CAnalytics.totalDuration = CAnalytics.GetDuration(startTime); CDebug.Duration("total time", startTime); CDebug.Step(EProgramStep.Dart); CDartTxt.ExportTile(); CDebug.Step(EProgramStep.Shp); CShpController.ExportCurrent(); CDebug.Step(EProgramStep.Las); CLasExporter.ExportTile(); CDebug.Step(EProgramStep.Analytics); CAnalytics.Write(true); return(EProcessResult.Done); }
public static CTree SelectBestPossibleTree(List <CTree> pPossibleTrees, Vector3 pPoint, bool pRestrictive) { CTree selectedTree = null; float bestAddPointFactor = 0; const int max_possible_trees = 3; //in most cases the point is not added to further trees int processCount = Math.Min(max_possible_trees, pPossibleTrees.Count); processCount = pPossibleTrees.Count; for (int i = 0; i < processCount; i++) { CTree tree = pPossibleTrees[i]; if (DEBUG) { CDebug.WriteLine("- try add to : " + tree.ToString(CTree.EDebug.Peak)); } CTree treeAtTheField = CProjectData.Points.treeDetailArray.GetFieldContainingPoint(pPoint).GetSingleDetectedTree(); if (treeAtTheField != null && treeAtTheField.Equals(tree)) { selectedTree = tree; break; } if (detectMethod == EDetectionMethod.Detection2D) { bool canBeAdded = tree.CanAdd(pPoint, pRestrictive); if (canBeAdded) { //todo: what if point can be added to more trees? //maybe should be re-processed later selectedTree = tree; if (selectedTree.treeIndex == 12) { //CDebug.WriteLine(""); } if (i == max_possible_trees - 1) { //this shouldnt happend too often maxPossibleTreesAssignment++; //CDebug.WriteLine("possibleTrees.IndexOf(t) = " + i); } break; } } else if (detectMethod == EDetectionMethod.AddFactor) { float addPointFactor = tree.GetAddPointFactor(pPoint); if (addPointFactor > 0.5f) { if (addPointFactor > bestAddPointFactor) { selectedTree = tree; bestAddPointFactor = addPointFactor; } } } else if (detectMethod == EDetectionMethod.AddFactor2D) { float addPointFactor = tree.GetAddPointFactor(pPoint); if (addPointFactor > 0.5f) { if (addPointFactor > bestAddPointFactor) { selectedTree = tree; bestAddPointFactor = addPointFactor; } } /*else { * CTreeField f = CProjectData.Points.treeDetailArray.GetFieldContainingPoint(pPoint); * if(f.GetSingleDetectedTree() != null) * { * selectedTree = f.GetSingleDetectedTree(); * } * }*/ //this joins too many trees together //else if(tree.CanAdd(pPoint)) //{ // selectedTree = tree; //} } } return(selectedTree); }
/// <summary> /// Mergind method for Detection2D /// </summary> private static void Merge2DTrees() { return; for (int i = Trees.Count - 1; i >= 0; i--) { CTree treeToMerge = Trees[i]; if (treeToMerge.Equals(173)) { CDebug.WriteLine(); } //if(treeToMerge.IsLocalMaximum()) //{ // continue; //} List <CTree> possibleTrees = GetPossibleTreesToMergeWith(treeToMerge, EPossibleTreesMethod.ClosestHigher); for (int t = 0; t < possibleTrees.Count; t++) { //merge trees if the target tree can be reached from the treeToMerge //and they are of different heights CTree tree = possibleTrees[t]; float maxRadius = CTreeRadiusCalculator.GetTreeRadius(tree); float treeAvgExtent = tree.GetAverageExtent(); float maxDist = Math.Max(maxRadius, treeAvgExtent); float treeDist = CUtils.Get2DDistance(treeToMerge, tree); if (treeDist > maxDist) { continue; } /*float heightDiff = tree.GetTreeHeight() - treeToMerge.GetTreeHeight(); * if(heightDiff < 2) * { * continue; * }*/ bool pathContainsTree = false; /* * CTreeField closeField = tree.GetClosestField(treeToMerge.peak.Center); * bool pathContainsTree = * CProjectData.Points.treeDetailArray.PathContainsTree( * treeToMerge.peak.Center, closeField.Center, tree, 1, 1); * * if(!pathContainsTree) * { * pathContainsTree = * CProjectData.Points.treeDetailArray.PathContainsTree( * treeToMerge.peak.Center, tree.peak.Center, tree, 1, 1); * }*/ bool canAdd = tree.CanAdd(treeToMerge.peak.Center, false); if (pathContainsTree || canAdd) { treeToMerge = MergeTrees(ref treeToMerge, ref tree, true); break; } } /*List<CField> fields = treeToMerge.peakDetailField.GetFieldsInDistance(5); * foreach(CField field in fields) * { * CTreeField treeField = (CTreeField)field; * CTree detectedTree = treeField.GetSingleDetectedTree(); * if(detectedTree != null && !detectedTree.Equals(treeToMerge)) * { * float heightDiff = detectedTree.GetTreeHeight() - treeToMerge.GetTreeHeight(); * if(heightDiff > 2) * { * treeToMerge = MergeTrees(ref treeToMerge, ref detectedTree, true); * break; * } * } * }*/ } }
public static void OnException() { CDebug.Step(EProgramStep.Exception); }
public static void Debug() { CDebug.WriteLine(minInputX + "," + minInputY + " - " + maxInputX + "," + maxInputY); }
public static EProcessResult Start() { CSequenceController.SetValues(); DateTime startTime = DateTime.Now; CProjectData.Init(); CTreeManager.Init(); CAnalytics.Init(); CDartTxt.Init(); CLasExporter.Init(); CBiomassController.Init( CParameterSetter.GetStringSettings(ESettings.dbh), CParameterSetter.GetStringSettings(ESettings.agb)); CTreeRadiusCalculator.Init(); CShpController.Init(); CReftreeManager.Init(); Thread.CurrentThread.CurrentCulture = new CultureInfo("en"); //GENERAL CProjectData.useMaterial = true; CObjExporter.simplePointsObj = false; CMaterialManager.Init(); string[] workerResult = new string[2]; workerResult[0] = "this string"; workerResult[1] = "some other string"; CProjectData.backgroundWorker.ReportProgress(10, workerResult); try { List <string> tiledFiles = CProgramLoader.GetTiledPreprocessedFilePaths(); tilesCount = tiledFiles.Count; int startTile = CParameterSetter.GetIntSettings(ESettings.startIndex); if (startTile < 0 || startTile >= tiledFiles.Count) { throw new Exception($"Parameter startTile = {startTile}, tiledFiles.Count = {tiledFiles.Count}"); } for (int i = startTile; i < tiledFiles.Count; i++) { string tiledFilePath = tiledFiles[i]; EProcessResult tileProcess = ProcessTile(tiledFilePath, i); if (CProjectData.backgroundWorker.CancellationPending) { break; } } } catch (Exception e) { CDebug.Error( $"{Environment.NewLine}exception: {e.Message} {Environment.NewLine}{Environment.NewLine}" + $"StackTrace: {e.StackTrace}{Environment.NewLine}"); OnException(); return(EProcessResult.Exception); } if (CProjectData.backgroundWorker.CancellationPending) { CDebug.Step(EProgramStep.Cancelled); return(EProcessResult.Cancelled); } CDebug.Step(EProgramStep.ExportMainFiles); //TODO: implement this in super class for all controllers //dont create the main file if not needed if (tilesCount > 1) { CDartTxt.ExportMain(); CLasExporter.ExportMain(); CShpController.ExportMain(); } CBitmapExporter.ExportMain(); CDebug.Step(EProgramStep.Done); if (CSequenceController.IsLastSequence()) { CSequenceController.OnLastSequenceEnd(); return(EProcessResult.Done); } CSequenceController.currentConfigIndex++; return(Start()); }
public void AddPoint(Vector3 pPoint) { if (CTreeManager.DEBUG) { CDebug.WriteLine("--- AddPoint " + pPoint.ToString("#+0.00#;-0.00") + " to " + this); } RefreshFurthestPoint(pPoint); OnAddPoint(pPoint); int insertAtIndex = 0; //find appropriate insert at index if (TreePoints.Count > 0) { for (int i = TreePoints.Count - 1; i >= -1; i--) { insertAtIndex = i + 1; if (insertAtIndex == 0) { break; } CTreePoint pointOnBranch = TreePoints[i]; if (pointOnBranch.Includes(pPoint)) { pointOnBranch.AddPoint(pPoint); //boundaries of points are changed, check if the order has to be changed if (i > 0) { CTreePoint previousPoint = TreePoints[i - 1]; //if(previousPoint.Contains(pointOnBranch.Center)) if (pointOnBranch.Z > previousPoint.Z) { TreePoints.RemoveAt(i); TreePoints.Insert(i - 1, pointOnBranch); } } if (i < TreePoints.Count - 1) { CTreePoint nextPoint = TreePoints[i + 1]; if (pointOnBranch.Z < nextPoint.Z) { TreePoints.RemoveAt(i); TreePoints.Insert(i + 1, pointOnBranch); } } CheckAddedPoint(); return; } if (pPoint.Z < pointOnBranch.Z) { if (i == TreePoints.Count - 1 || TreePoints[i + 1].Z <= pPoint.Z) { break; } } } } CTreePoint newPoint = new CTreePoint(pPoint, tree.treePointExtent); TreePoints.Insert(insertAtIndex, newPoint); CheckAddedPoint(); if (CTreeManager.DEBUG) { CDebug.WriteLine("---- new point"); } }
public static void Export(int pTileIndex) { if (!exportBitmap) { return; } //init for each tile treeMarkerSize = GetTreeBrushSize(false); DateTime bitmapStart = DateTime.Now; CVegeArray array = CProjectData.Points.vegeDetailArray; Bitmap bitmap = new Bitmap(array.arrayXRange, array.arrayYRange); int maxValue = 0; for (int x = 0; x < array.arrayXRange; x++) { for (int y = 0; y < array.arrayYRange; y++) { CVegeField element = array.GetField(x, y); int? colorVal = element.GetColorValue(); //from detailed array if (colorVal == null) { continue; } int colorVaInt = (int)colorVal; if (colorVaInt > maxValue) { maxValue = colorVaInt; } int rVal = colorVaInt; //highlight buffer zone bool isAtBufferZone = CTreeMath.IsAtBufferZone(element.Center); if (isAtBufferZone) { rVal = Math.Min(rVal + 30, 255); } Color color = Color.FromArgb(rVal, colorVaInt, colorVaInt); //CDebug.WriteLine($"{x},{y} = {color}"); bitmap.SetPixel(x, y, color); if (exportMain && !isAtBufferZone) { Tuple <int, int> posInMain = GetIndexInMainBitmap(element.Center); if (posInMain == null) { continue; } if (color.R > 255) { CDebug.Error("color.R = " + color.R); } mainMap.SetPixel(posInMain.Item1, posInMain.Item2, color); } } } //StretchColorRange(ref bitmap, maxValue); //FilterBitmap(ref bitmap, GetKernelSize(array.stepSize, .2f), EFilter.Max); if (exportHeightmap) { ExportBitmap(bitmap, "heightmap", pTileIndex); } int bitmapsCount = 3; bool useCheckTree = CParameterSetter.GetBoolSettings(ESettings.useCheckTreeFile); if (useCheckTree) { bitmapsCount++; } CDebug.Progress(1, bitmapsCount, 1, ref bitmapStart, bitmapStart, "bitmap: "); if (exportPositions) { Bitmap bitmapTreePos = new Bitmap(bitmap); AddTreesToBitmap(array, bitmapTreePos, true, false); ExportBitmap(bitmapTreePos, "tree_positions", pTileIndex); if (useCheckTree) { Bitmap bitmapChecktree = new Bitmap(bitmapTreePos); ExportBitmap(bitmapChecktree, "tree_check", pTileIndex); CDebug.Progress(bitmapsCount - 1, bitmapsCount, 1, ref bitmapStart, bitmapStart, "bitmap: "); } } CDebug.Progress(2, bitmapsCount, 1, ref bitmapStart, bitmapStart, "bitmap: "); if (exportBorders) { Bitmap bitmapTreeBorder = new Bitmap(bitmap); AddTreesToBitmap(array, bitmapTreeBorder, true, true); ExportBitmap(bitmapTreeBorder, "tree_borders", pTileIndex); } CDebug.Progress(bitmapsCount, bitmapsCount, 1, ref bitmapStart, bitmapStart, "bitmap: "); CAnalytics.bitmapExportDuration = CAnalytics.GetDuration(bitmapStart); CDebug.Duration("bitmap export", bitmapStart); }
private static void FilterBitmap(ref Bitmap pBitmap, int pKernelSize, EFilter pFilter) { Bitmap copyBitmap = new Bitmap(pBitmap); for (int x = 0; x < pBitmap.Width; x++) { for (int y = 0; y < pBitmap.Height; y++) { Color color = pBitmap.GetPixel(x, y); if (pFilter == EFilter.ColorOrMax || pFilter == EFilter.ColorOrBlur) { if (IsTreeColoured(color)) { continue; } } int origVal = color.R; if (origVal > 0) { continue; } int definedCount = 0; int valueSum = 0; int maxValue = 0; int minValue = 0; for (int i = -pKernelSize; i < pKernelSize; i++) { for (int j = -pKernelSize; j < pKernelSize; j++) { int _x = x + i; int _y = y + j; if (IsOOB(_x, _y, pBitmap)) { continue; } int val = pBitmap.GetPixel(_x, _y).R; if (val > 0) { valueSum += val; definedCount++; if (val > maxValue) { maxValue = val; } if (val < minValue) { minValue = val; } } } } int newVal = 0; switch (pFilter) { case EFilter.Blur: case EFilter.ColorOrBlur: newVal = definedCount > 0 ? valueSum / definedCount : 0; break; case EFilter.Max: case EFilter.ColorOrMax: newVal = maxValue; break; case EFilter.Min: newVal = minValue; break; } Color newColor = Color.FromArgb(newVal, newVal, newVal); if (newColor.R > 255) { CDebug.Error("color.R = " + newColor.R); } copyBitmap.SetPixel(x, y, newColor); } } pBitmap = copyBitmap; }
/// <summary> /// Calculates rigid transformations between all permutations of pSetA and pSetB /// and returns the best one (having the smallest offset). /// This is done due to the expected indexing in function CalculateRigidTransform /// </summary> public static CRigidTransform GetRigidTransform(List <Vector3> pSetA, List <Vector3> pSetB) { CDebug.WriteLine($"GetRigidTransform from set : {CDebug.GetString(pSetA)} to {CDebug.GetString(pSetB)}"); if (pSetA.Count != pSetB.Count) { CDebug.Error("Sets copunt dont match"); return(null); } IEnumerable <IEnumerable <Vector3> > setApermutations = pSetA.Permute(); List <CRigidTransform> rigTransforms = new List <CRigidTransform>(); foreach (var permutation in setApermutations) { CRigidTransform rigTransform = CalculateRigidTransform(permutation.ToList(), pSetB); rigTransforms.Add(rigTransform); //CDebug.WriteLine($"{rigTransform}"); if (rigTransform.offset < MAX_OFFSET) { break; } } CRigidTransform minOffsetRigTransform = rigTransforms.Aggregate( (curMin, x) => x.offset < curMin.offset ? x : curMin); CDebug.WriteLine($"Selected {minOffsetRigTransform}", true, true); return(minOffsetRigTransform); }