public static void AddBranchToObj(ref Obj obj, CBranch pBranch) { for (int i = 0; i < pBranch.TreePoints.Count; i++) { //for first point in branch use peak as a first point Vector3 p = i == 0 ? pBranch.tree.peak.Center : pBranch.TreePoints[i - 1].Center; //for first point set first point to connect to peak Vector3 nextP = i == 0 ? pBranch.TreePoints[0].Center : pBranch.TreePoints[i].Center; AddLineToObj(ref obj, p, nextP); } }
/// <summary> /// First finds most defined branch of pOtherTree. /// Then finds the branch on this reference tree which best matches found most defined branch. /// Returns index offset between these branches. /// </summary> private static int GetIndexOffsetBetweenBestMatchBranches(CRefTree pRefTree, CTree pOtherTree) { CBranch mostDefinedBranch = pOtherTree.GetMostDefinedBranch(); CBranch bestMatchBranch = GetBestMatchBranch(pRefTree, mostDefinedBranch); int indexOfMostDefined = pOtherTree.Branches.IndexOf(mostDefinedBranch); int indexOfBestMatch = pRefTree.Branches.IndexOf(bestMatchBranch); int indexOffset = indexOfBestMatch - indexOfMostDefined; return(indexOffset); }
/// <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)); }
/// <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> /// Is point closer than the "furthestPoint" of this or one /// of neighbouring branches /// </summary> public bool IsPointInExtent(Vector3 pPoint) { float pointDistToPeak = CUtils.Get2DDistance(pPoint, tree.peak); bool thisBranchInExtent = furthestPointDistance > pointDistToPeak; Vector3 closestPoint = GetClosestPointTo(pPoint); float distToClosestPoint = Vector3.Distance(pPoint, closestPoint); if (thisBranchInExtent && distToClosestPoint < 1) { return(true); } CBranch branch1 = GetNeigbourBranch(-1); float dist1 = branch1.furthestPointDistance; bool leftBranchInExtent = dist1 > pointDistToPeak; float distToLeftPoint = CUtils.Get2DDistance(pPoint, branch1.furthestPoint); //restrict only to points close to the furthest point. //for too large branches it was including points way too far bool leftBranchPointClose = distToLeftPoint < 1; if (leftBranchInExtent && leftBranchPointClose) { return(true); } CBranch branch2 = GetNeigbourBranch(1); float dist2 = branch2.furthestPointDistance; bool rightBranchInExtent = dist2 > pointDistToPeak; float distToRightPoint = CUtils.Get2DDistance(pPoint, branch2.furthestPoint); bool rightBranchPointClose = distToRightPoint < 1; if (rightBranchInExtent && rightBranchPointClose) { return(true); } return(false); }
/// <summary> /// Returns branch with the highest similarity with other branch /// </summary> private static CBranch GetBestMatchBranch(CRefTree pRefTree, CBranch pOtherBranch) { Vector3 offsetToRefTree = GetOffsetTo(pOtherBranch.tree, pRefTree); float scaleRatio = GetScaleRatioTo(pOtherBranch.tree, pRefTree); Matrix4x4 scaleMatrix = Matrix4x4.CreateScale(scaleRatio, scaleRatio, scaleRatio, pRefTree.peak.Center); //CDebug.WriteLine("offsetToRefTree = " + offsetToRefTree); //CDebug.WriteLine("scaleRatio = " + scaleRatio); float bestSimilarity = 0; CBranch bestMatchBranch = pRefTree.Branches[0]; foreach (CBranch b in pRefTree.Branches) { float similarity = b.GetSimilarityWith(pOtherBranch, offsetToRefTree, scaleMatrix); if (similarity > bestSimilarity) { bestSimilarity = similarity; bestMatchBranch = b; } } //CDebug.WriteLine(bestSimilarity + " GetBestMatchBranch = " + bestMatchBranch); return(bestMatchBranch); }
public CRefTree(string pFileName, string[] pSerializedLines) { DeserialiseMode currentMode = DeserialiseMode.None; fileName = pFileName; isValid = true; branches = new List <CBranch>(); List <CTreePoint> _treepointsOnBranch = new List <CTreePoint>(); //if first line is not version then it is the old version and //the file needs to be regenerated if (pSerializedLines.Length == 0 || pSerializedLines[0] != KEY_VERSION) { return; } foreach (string line in pSerializedLines) { switch (line) { case KEY_VERSION: currentMode = DeserialiseMode.Version; continue; case KEY_TREE_INDEX: currentMode = DeserialiseMode.TreeIndex; continue; case KEY_TREE_POINT_EXTENT: currentMode = DeserialiseMode.TreePointExtent; continue; case KEY_PEAK: currentMode = DeserialiseMode.Peak; continue; case KEY_BRANCHES: currentMode = DeserialiseMode.Branches; continue; case KEY_STEM: currentMode = DeserialiseMode.Stem; branches.Last().SetTreePoints(_treepointsOnBranch); _treepointsOnBranch = new List <CTreePoint>(); continue; case KEY_BOUNDING_BOX: currentMode = DeserialiseMode.BoundingBox; continue; } switch (currentMode) { case DeserialiseMode.Version: version = line; if (!IsCurrentVersion()) { CDebug.Warning($"reftree version {version} is not up to date {CURRENT_REFTREE_VERSION}. Generating new file."); return; } break; case DeserialiseMode.TreeIndex: treeIndex = int.Parse(line); break; case DeserialiseMode.TreePointExtent: treePointExtent = float.Parse(line); break; case DeserialiseMode.Peak: peak = CPeak.Deserialize(line, treePointExtent); stem = new CBranch(this, 0, 0); break; case DeserialiseMode.Branches: if (line.Contains(KEY_BRANCH)) { int branchIndex = branches.Count; if (branchIndex > 0) { branches.Last().SetTreePoints(_treepointsOnBranch); } branches.Add(new CBranch( this, branchIndex * BRANCH_ANGLE_STEP, branchIndex * BRANCH_ANGLE_STEP + BRANCH_ANGLE_STEP)); _treepointsOnBranch = new List <CTreePoint>(); } else { CTreePoint treePointOnBranch = CTreePoint.Deserialize(line, treePointExtent); _treepointsOnBranch.Add(treePointOnBranch); Points.Add(treePointOnBranch.Center); } break; case DeserialiseMode.Stem: _treepointsOnBranch.Add(CTreePoint.Deserialize(line, treePointExtent)); break; case DeserialiseMode.BoundingBox: string[] split = line.Split(null); minBB = new Vector3(float.Parse(split[0]), float.Parse(split[1]), float.Parse(split[2])); maxBB = new Vector3(float.Parse(split[3]), float.Parse(split[4]), float.Parse(split[5])); break; } } stem.SetTreePoints(_treepointsOnBranch); LoadObj(pFileName); }