public void AngleWithVector() { var v = new Vector3D(1, 1, 1); Assert.AreEqual(0.0f, v.Angle(v)); Assert.IsTrue(MathExtensions.IsNearlyEqual(180.0f, v.Angle(new Vector3D(-1, -1, -1)), 0.1f)); }
public GazeDataProccessed(GazeData gazeData) { if (gazeData.TrackingStatus == TrackingStatus.BothEyesTracked) { Vector3D gazeVectorRight = new Vector3D(gazeData.Right.EyePositionFromEyeTrackerMM, gazeData.Right.GazePointFromEyeTrackerMM); Vector3D gazeVectorLeft = new Vector3D(gazeData.Left.EyePositionFromEyeTrackerMM, gazeData.Left.GazePointFromEyeTrackerMM); angleAtDistance = Vector3D.Angle(gazeVectorLeft, gazeVectorRight); angleAtDistance = 180 * angleAtDistance / Math.PI; Vector3D eyeAxis = new Vector3D(gazeData.Left.EyePositionFromEyeTrackerMM, gazeData.Right.EyePositionFromEyeTrackerMM); if (Vector3D.Angle(eyeAxis, gazeVectorRight) > Vector3D.Angle(eyeAxis, gazeVectorLeft)) { typeAtDistance = "eso"; } else if (Vector3D.Angle(eyeAxis, gazeVectorRight) < Vector3D.Angle(eyeAxis, gazeVectorLeft)) { typeAtDistance = "exo"; } Vector3D gazeVectorLeftIdeal = new Vector3D(gazeData.Left.EyePositionFromEyeTrackerMM, gazeData.Right.GazePointFromEyeTrackerMM); angleAtScreen = Vector3D.Angle(gazeVectorLeft, gazeVectorLeftIdeal); angleAtScreen = 180 * angleAtScreen / Math.PI; if (Vector3D.Angle(eyeAxis, gazeVectorLeftIdeal) > Vector3D.Angle(eyeAxis, gazeVectorLeft)) { typeAtScreen = "eso"; } else if (Vector3D.Angle(eyeAxis, gazeVectorRight) < Vector3D.Angle(eyeAxis, gazeVectorLeft)) { typeAtScreen = "exo"; } } }
public void ExecuteCalculateCommand(object parameter) { var values = (object[])parameter; if (values.Count() != 0 && values[0] != null) { _XaValue = Convert.ToDouble(values[0]); _YaValue = Convert.ToDouble(values[1]); _ZaValue = Convert.ToDouble(values[2]); _XbValue = Convert.ToDouble(values[3]); _YbValue = Convert.ToDouble(values[4]); _ZbValue = Convert.ToDouble(values[5]); vector3D1 = new Vector3D(_XaValue, _YaValue, _ZaValue); vector3D2 = new Vector3D(_XbValue, _YbValue, _ZbValue); this.CrossProductText = string.Join(", ", vector3D1.CrossProduct(vector3D2).ArrayVector); this.MagnitudVectorAText = Math.Round(vector3D1.Magnitude, 4).ToString(); this.MagnitudVectorBText = Math.Round(vector3D2.Magnitude, 4).ToString(); double resultAngleAB = Math.Round(vector3D1.Angle(vector3D2), 4); this.AngleText = Math.Round(((resultAngleAB * 180) / Math.PI), 4).ToString(); } else { ts.TraceEvent(TraceEventType.Error, 1, "Something happens calculating, check values"); ts.Close(); } }
public void TestAngleMethod(int angle) { Vector3D vectorA = new Vector3D(2, 2, 3); Vector3D another = new Vector3D(4, 4, 3); double result = (vectorA.Angle(another) * 180) / Math.PI; Assert.IsTrue(Math.Round(result, 0) == angle, String.Format("Expected for '{0}': true; Actual: {1}", angle, result)); }
private string OutputInfo(Vector3D vector1, Vector3D vector2) { var output = new StringBuilder(); output.Append($"{vector1} + {vector2} = {vector1 + vector2}\n"); output.Append($"{vector1} - {vector2} = {vector1 - vector2}\n\n"); output.Append($"The angle between the vectors: {Vector3D.Angle(vector1, vector2)}\n"); output.Append($"Scalar product of vectors: {Vector3D.ScalarProduct(vector1, vector2)}"); return(output.ToString()); }
/// <summary> /// Creates a <see cref="Quaternion"/> that rotates one <see cref="Vector3D"/> onto another. A rotation axis must be supplied if <see cref="Vector3D"> Vector3Ds </see> are antiparallel. /// </summary> /// <param name="v1">The first <see cref="Vector3D"/>.</param> /// <param name="v2">The second <see cref="Vector3D"/>.</param> /// <param name="axis">Axis that will be rotated around if <see cref="Vector3D">Vector3Ds</see> are antiparallel.</param> /// <returns>A rotation <see cref="Quaternion"/>.</returns> public static Quaternion QuaternionRotateBetweenVectors(Vector3D v1, Vector3D v2, Vector3D?axis = null) { if (v1.ApproxEquals(v2, 1E-6f)) { return(Quaternion.Identity); } axis ??= Vector3D.UnitY; Vector3D rotationAxis = v1.ApproxEquals(-v2, 1E-6F) ? (Vector3D)axis : v1.CrossProduct(v2).Normalise(); float angle = v1.Angle(v2); return(QuaternionRotate(rotationAxis, angle)); }
/// <summary> /// Set label to all sharp edges to 1 and rest to 0 /// </summary> public void MarkSharpEdges(double angle = 30.0) { foreach (var he in halfedges) { if (he.IsBoundary()) { he.label = 0; continue; } if (he.opp.id < he.id) { continue; } double edgeAngle = Vector3D.Angle(he.face.GetNormal(), he.opp.face.GetNormal()); int label = edgeAngle <= angle ? 0 : 1; he.label = label; he.opp.label = label; } }
private static Cylinder CalculateCylinder(Line first, Line second, Line wallLine, double radius) { var angle = Vector3D.Angle(first.Direction, second.Direction); var distance = Math.Sin(90.0.ToRadian()) / Math.Sin(angle / 2) * radius; var minimumWallDistance = Math.Sqrt(Math.Pow(distance, 2) - Math.Pow(radius, 2)); var referencePoint = wallLine.Contains(first.BasePoint) ? first.BasePoint : first.SecondPoint; var firstSign = first.BasePoint == referencePoint ? +1 : -1; var secondSign = second.BasePoint == referencePoint ? +1 : -1; var firstPoint = first.GetPointOnLine(referencePoint, firstSign * minimumWallDistance); var secondPoint = second.GetPointOnLine(referencePoint, secondSign * minimumWallDistance); var crossLine = new Line(firstPoint, secondPoint); var directLine = new Line(referencePoint, crossLine.ClosestPoint(referencePoint)); var top = directLine.GetPointOnLine(distance); var difference = top - referencePoint; var otherPoint = referencePoint == wallLine.BasePoint ? wallLine.SecondPoint : wallLine.BasePoint; var bottom = otherPoint + difference; var basLine = new Line(top, bottom); var reverseBase = new Line(bottom, top); var correctTop = basLine.GetPointOnLine(radius); var correctBottom = reverseBase.GetPointOnLine(radius); var wallHeight = Vector3D.AbsoluteValue(wallLine.SecondPoint - wallLine.BasePoint); var sign = otherPoint == wallLine.BasePoint ? -1 : +1; var bottomPoint = firstPoint + sign * wallHeight * (wallLine.SecondPoint - wallLine.BasePoint).Normalize(); var barrier = new Plane(firstPoint, secondPoint, bottomPoint); var checker = new PointChecker(barrier, barrier.DeterminePointPosition(referencePoint)); return(new Cylinder(correctTop, correctBottom, checker, radius)); }
public void AngleWithVector() { var v = new Vector3D(1, 1, 1); Assert.AreEqual(0.0f, v.Angle(v)); Assert.IsTrue(MathExtensions.IsNearlyEqual(180.0f, v.Angle(new Vector3D(-1,-1,-1)), 0.1f)); }
// Assumes that the vertices are located in the same plane // https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf // Return null if triangulation does not succeed // can potential also delete edges (if edges of length 0 is found) public List <Face> Triangulate(bool step = false, StringWriter debug = null) { #if HMDebug if (debug != null) { debug.WriteLine("Triangulate face with debug"); } #endif Debug.Assert(!IsDestroyed()); List <Face> res = new List <Face>(); res.Add(this); var face = this; bool isVerticesLinear = IsVerticesLinear(); #if HMDebug if (debug != null) { debug.WriteLine("isVerticesLinear " + isVerticesLinear); } #endif if (isVerticesLinear) { return(TriangulateFaceOnLine()); } var halfedges = Circulate(); var normal = GetNormal(); int iterations = halfedges.Count * 2; while (halfedges.Count > 3 && iterations > 0) { iterations--; Halfedge zeroEdge = null; Halfedge degenerateEdge = null; Halfedge sharpCorner = null; double minimumAngle = 999; // find ear to clip for (int i = 0; i < halfedges.Count; i++) { var he1 = halfedges[i]; var he2 = he1.next; var dir1 = he1.GetDirection(); var dir2 = he2.GetDirection(); Vector3D crossDir = Vector3D.Cross(dir1, dir2); var angle = Vector3D.Angle(dir1, dir2); if (dir1.sqrMagnitude < face.hmesh.zeroMagnitudeTresholdSqr) { zeroEdge = he1; break; } bool isParallel = Vector3D.IsParallelDist(dir1, dir2, hmesh.zeroMagnitudeTresholdSqr); bool isSameDir = Vector3D.Dot(dir1, dir2) > 0; bool isNormalSameDir = Vector3D.Dot(crossDir, normal) > 0; if (isParallel && isSameDir == false) { degenerateEdge = he1; break; } bool intersection = false; if (isNormalSameDir && !isParallel) { for (int j = i + 2; j < i + halfedges.Count; j++) { var heJ = halfedges[j % halfedges.Count]; if (PointInTriangle(heJ.prev.vert.positionD, he1.prev.vert.positionD, he1.vert.positionD, he2.vert.positionD) || PointInTriangle(heJ.vert.positionD, he1.prev.vert.positionD, he1.vert.positionD, he2.vert.positionD)) { intersection = true; break; // break intersection test } } // clip ear if (intersection == false) { if (angle < minimumAngle) { minimumAngle = angle; sharpCorner = he1; } } } } if (zeroEdge != null) { #if HMDebug if (debug != null) { debug.WriteLine("zeroEdge " + zeroEdge); } #endif zeroEdge.Collapse(); if (face.IsDestroyed()) { Debug.LogError("Fix"); return(new List <Face>()); // Fix } halfedges = face.Circulate(); } else if (degenerateEdge != null) { // the main idea, is to cut away the degenerate edge (and collapse the degenerate face) // // // Example (4 vertices) // || // || // |\ // | \ // ---- #if HMDebug if (debug != null) { debug.WriteLine("degenerateEdge " + degenerateEdge); } #endif var he1 = degenerateEdge; var he2 = he1.next; // degenerate edges detected Halfedge next = he2.next; double thisDist = he1.GetDirection().magnitude; double nextDist = he2.GetDirection().magnitude; Vertex nextVert = he2.vert; Vertex prevVert = he1.prev.vert; if (Math.Abs(nextDist - thisDist) <= face.hmesh.zeroMagnitudeTreshold) { // cut from nextVert to prevVert } else if (nextDist > thisDist) { nextVert = he2.Split(); nextVert.positionD = prevVert.positionD; } else if (thisDist > nextDist) { prevVert = he1.Split(); prevVert.positionD = nextVert.positionD; } var cutFace = face.Cut(prevVert, nextVert); var sharedEdge = nextVert.GetSharedEdge(prevVert); sharedEdge.Collapse(); if (!cutFace.IsDestroyed()) { #if HMDebug Debug.LogWarning("Cut face survived \n" + cutFace.ExportLocalNeighbourhoodToObj()); #endif return(new List <Face>()); // Fix } halfedges = face.Circulate(); } else if (sharpCorner != null) { #if HMDebug if (debug != null) { debug.WriteLine("sharpCorner "); } #endif var he1 = sharpCorner; var he2 = he1.next; var newFace = face.Cut(he1.prev.vert, he2.vert); newFace.label = label; res.Add(newFace); if (newFace.Circulate().Count > 3) { face = newFace; } halfedges = face.Circulate(); } if (step) { return(res); } } for (int i = res.Count - 1; i >= 0; i--) { if (res[i] == null || res[i].IsDestroyed()) { res.RemoveAt(i); } } return(res); }
/// <summary> /// Export the HMesh as a number of meshes, split into a number of subregions. /// If the parameter used material is provided, the mesh only contains submeshes with geometry and the submesh index /// is added to the used material. /// Is a mesh does not contain any vertices it is skipped. /// </summary> public List <Mesh> ExportSplit(Vector3i axisSplit, List <List <int> > usedMaterials = null, double sharpEdgeAngle = 360) { var bounds = ComputeBoundsD(); bounds.extents += Vector3D.one * 0.000001; // add delta size to ensure no vertex is on bounds var resList = new List <Mesh>(); // Enumerate vertices for (int i = 0; i < vertices.Count; i++) { vertices[i].label = i; } var maxFaceLabel = 0; foreach (var face in faces) { maxFaceLabel = Mathf.Max(maxFaceLabel, face.label); } int clusterCount = 0; MarkSharpEdges(sharpEdgeAngle); var faceClusters = SeparateMeshByGeometry(out clusterCount); Debug.Log("Face clusters: " + clusterCount); var remap = new int[vertices.Count]; for (var i = 0; i < axisSplit[0]; i++) { double minX = bounds.min.x + i * (bounds.size.x / axisSplit[0]); double maxX = bounds.min.x + (i + 1) * (bounds.size.x / axisSplit[0]); for (var j = 0; j < axisSplit[1]; j++) { double minY = bounds.min.y + j * (bounds.size.y / axisSplit[1]); double maxY = bounds.min.y + (j + 1) * (bounds.size.y / axisSplit[1]); for (var k = 0; k < axisSplit[2]; k++) { double minZ = bounds.min.z + k * (bounds.size.z / axisSplit[2]); double maxZ = bounds.min.z + (k + 1) * (bounds.size.z / axisSplit[2]); // DebugExt.DrawBox(new Vector3D(minX, minY, minZ).ToVector3(), new Vector3D(maxX, maxY, maxZ).ToVector3(),Color.white, 10); var min = new Vector3D(minX, minY, minZ); var max = new Vector3D(maxX, maxY, maxZ); var res = new Mesh(); res.name = "HMesh_" + i + "," + j + "," + k; var vertexArray = new List <Vector3>(); var normalArray = new List <Vector3>(); var uv1 = new List <Vector2>(); var uv2 = new List <Vector2>(); res.subMeshCount = maxFaceLabel + 1; List <Face> facesInRegion = new List <Face>(); foreach (var face in faces) { var center = face.GetCenter(); if (Vector3D.AllLessThan(min, center) && Vector3D.AllLessEqualThan(center, max)) { facesInRegion.Add(face); } } var triangles = new List <List <int> >(); for (int ii = 0; ii <= maxFaceLabel; ii++) { triangles.Add(new List <int>()); } for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) { // clear remap for (int x = 0; x < remap.Length; x++) { remap[x] = -1; } for (var faceLabel = 0; faceLabel <= maxFaceLabel; faceLabel++) { foreach (var face in facesInRegion) { if (faceClusters[face.id] != clusterIndex) { continue; } if (face.label == faceLabel) { if (face.NoEdges() != 3) { Debug.LogError("Only triangles supported. Was " + face.NoEdges() + "-gon"); continue; } var he = face.halfedge; var first = true; while (he != face.halfedge || first) { var indexOfVertex = he.vert.label; var indexOfVertexRemapped = remap[indexOfVertex]; if (indexOfVertexRemapped == -1) { indexOfVertexRemapped = vertexArray.Count; remap[indexOfVertex] = indexOfVertexRemapped; vertexArray.Add(vertices[indexOfVertex].position); uv1.Add(vertices[indexOfVertex].uv1); uv2.Add(vertices[indexOfVertex].uv2); // compute normal Vector3D n = Vector3D.zero; int count = 0; foreach (var vertHe in he.vert.CirculateAllIngoing()) { if (faceClusters[vertHe.face.id] == clusterIndex) { double angle = Vector3D.Angle(-vertHe.GetDirection(), vertHe.next.GetDirection()); n += angle * vertHe.face.GetNormal(); count++; } } if (n.sqrMagnitude <= 0 || double.IsNaN(Vector3D.Dot(n, n))) { Debug.LogWarning("Cannot compute normal n is " + n.ToString("R") + " edges of vertex " + he.vert.Circulate().Count + " same cluster " + count + " " + he.face.ToString()); foreach (var vertHe in he.vert.CirculateAllIngoing()) { if (faceClusters[vertHe.face.id] == clusterIndex) { Debug.Log(vertHe.face.ToString()); } } n = new Vector3D(0, 1, 0); } else { n.Normalize(); } normalArray.Add(n.ToVector3()); } triangles[faceLabel].Add(indexOfVertexRemapped); he = he.next; first = false; } } } } } if (vertexArray.Count == 0) { // empty mesh - skip continue; } resList.Add(res); if (vertexArray.Count > 65000) { Debug.LogWarning("Vertex count was " + vertexArray.Count); } res.vertices = vertexArray.ToArray(); res.uv = uv1.ToArray(); res.uv2 = uv2.ToArray(); res.normals = normalArray.ToArray(); // add mesh indices // if usedMaterials exists then filter out any empty submesh List <int> materialIndices = null; if (usedMaterials != null) { materialIndices = new List <int>(); usedMaterials.Add(materialIndices); } for (int ii = 0; ii < triangles.Count; ii++) { if (materialIndices != null) { if (triangles[ii].Count > 0) { res.SetIndices(triangles[ii].ToArray(), MeshTopology.Triangles, materialIndices.Count, true); materialIndices.Add(ii); } } else { res.SetIndices(triangles[ii].ToArray(), MeshTopology.Triangles, ii, true); } } res.RecalculateBounds(); } } } return(resList); }
void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { UnityEngine.SceneManagement.SceneManager.LoadScene(0); return; } if (adapter == null) { return; } if (adapter.SensorType != sensorType) { adapter.SensorType = sensorType; } Frame frame = adapter.UpdateFrame(); if (frame != null) { if (frame.ImageData != null) { imageViewTexture = ValidateTexture(imageViewTexture, frame.ImageWidth, frame.ImageHeight, imageViewMaterial, imageViewTransform); if (imageViewTexture != null) { imageViewTexture.LoadRawTextureData(frame.ImageData); imageViewTexture.Apply(false); } } depthFilter.UpdateFilter(frame); if (depthFilter.Result != null) { depthViewTexture = ValidateTexture(depthViewTexture, frame.DepthWidth, frame.DepthHeight, depthViewMaterial, depthViewTransform); if (depthViewTexture != null) { depthViewTexture.LoadRawTextureData(depthFilter.Result); depthViewTexture.Apply(false); } } Body body = frame.GetClosestBody(); if (body != null) { imageViewStickman.UpdateStickman(adapter, frame, body, imageViewTransform, Visualization.Image); depthViewStickman.UpdateStickman(adapter, frame, body, depthViewTransform, Visualization.Depth); if (!hadBody) { hadBody = true; model1.AvatarRoot.SetActive(true); model2.AvatarRoot.SetActive(true); } model1.DoAvateering(body); model1.Bones[(int)JointType.SpineBase].Transform.position = adapter.WorldToImageSpace(body.Joints[JointType.SpineBase].WorldPosition). GetPositionOnPlane(frame.ImageWidth, frame.ImageHeight, imageViewTransform.position, imageViewTransform.rotation, imageViewTransform.localScale); model2.DoAvateering(body); model2.Bones[(int)JointType.SpineBase].Transform.position = adapter.WorldToDepthSpace(body.Joints[JointType.SpineBase].WorldPosition). GetPositionOnPlane(frame.DepthWidth, frame.DepthHeight, depthViewTransform.position, depthViewTransform.rotation, depthViewTransform.localScale); if (Vector3D.Angle(Vector3D.Up, body.Joints[JointType.Neck].WorldPosition - body.Joints[JointType.SpineBase].WorldPosition) < 10) { bodyImageSize = (imageViewStickman.jointPoints[0].position - imageViewStickman.jointPoints[4].position).magnitude; bodyDepthSize = (depthViewStickman.jointPoints[0].position - depthViewStickman.jointPoints[4].position).magnitude; float scale = bodyImageSize / model1Size; model1.AvatarRoot.transform.localScale = new Vector3(scale, scale, scale); scale = bodyDepthSize / model2Size; model2.AvatarRoot.transform.localScale = new Vector3(scale, scale, scale); } } else if (hadBody) { hadBody = false; model1.AvatarRoot.SetActive(false); model2.AvatarRoot.SetActive(false); } } }
private void Move() { if (!FreeCam.FreeCTRL) { Vector3D walkdir = Vector3D.Zero; Vector3D lookDir = FPSCamera.WObject.Forward; Vector3D walkForward = new Vector3D(lookDir.X, 0, lookDir.Z).Normalize(); Vector3D rightDir = FPSCamera.WObject.Right; Vector3D walkRight = new Vector3D(rightDir.X, 0, rightDir.Z).Normalize(); bool run = false; if (Input.IsPressed(GameInput.Key("Forward"))) { if (Input.IsPressed(GameInput.Key("Run"))) { run = true; } walkdir += walkForward; } if (Input.IsPressed(GameInput.Key("Backward"))) { walkdir -= walkForward; } if (Input.IsPressed(GameInput.Key("Right"))) { walkdir -= walkRight; } if (Input.IsPressed(GameInput.Key("Left"))) { walkdir += walkRight; } Vector3D walkDirBase = walkdir.Normalize(); float force = 0.0F; CheckGrounded(); if (Grounded) { force = run ? RunForce : WalkForce; } else { force = run ? AirRunForce : AirWalkForce; } this._Rb.Velocity += walkdir * force * Time.DeltaTime; float MaxHorizontalSpeed = 0.0F; if (Grounded) { MaxHorizontalSpeed = run ? RunMaxSpeed : WalkMaxSpeed; } else { MaxHorizontalSpeed = run ? AirRunMaxSpeed : AirWalkMaxSpeed; } if (this._Rb.Velocity.XZ.Length > MaxHorizontalSpeed) { double velY = this._Rb.Velocity.Y; this._Rb.Velocity = new Vector3D(this._Rb.Velocity.X, 0, this._Rb.Velocity.Z).Normalized *MaxHorizontalSpeed; this._Rb.Velocity += Vector3D.Up * velY; } if (this._Rb.Velocity.Y < this.FallMaxSpeed) { double fallSpeed = this._Rb.Velocity.Y; this._Rb.Velocity *= new Vector3D(1, 0, 1); this._Rb.Velocity += new Vector3D(0, fallSpeed, 0); } Vector3D flattenVel = new Vector3D(this._Rb.Velocity.X, 0, this._Rb.Velocity.Z); //slowdown if (force == 0.0F || walkDirBase == Vector3D.Zero) { Vector2D flatVel = this._Rb.Velocity.XZ; Vector3D horVel = new Vector3D(flatVel.X, 0, flatVel.Y); if (flatVel.Length < 1.0F) { this._Rb.Velocity *= Vector3D.Up; } else { this._Rb.Velocity -= horVel.Normalized * SlowFactor * Time.DeltaTime; } } else { double angleVelFwd = Vector3D.Angle(walkDirBase, _Rb.Velocity.Normalized); this._Rb.Velocity.RotateAround(Vector3D.Zero, Vector3D.Up, (float)angleVelFwd * TurnFactor * (float)Time.DeltaTime); } } }
bool PrecondFlipEdge(Halfedge h) { Face hf = h.face; if (h.opp == null) { return(false); } Face hof = h.opp.face; if (FaceLabelContrain) { if (hf.label != hof.label) { return(false); } } if (FaceNormalContrain) { var fn = hf.GetNormal(); var fon = hof.GetNormal(); if (Vector3D.Angle(fn, fon) > epsilonAngle) { return(false); } } // boundary case if (hf == null || hof == null) { return(false); } // We can only flip an edge if both incident polygons are triangles. if (hf.Circulate().Count != 3 || hof.Circulate().Count != 3) { return(false); } // non boundary vertices with a valency of less than 4(less than 3 after operation) degenerates mesh. Vertex hv = h.vert; var hov = h.opp.vert; if ((hv.Valency < 4 && !hv.IsBoundary()) || (hov.Valency < 4 && !hov.IsBoundary())) { return(false); } // Disallow flip if vertices being connected already are. Vertex hnv = h.next.vert; Vertex honv = h.opp.next.vert; if (hnv.GetSharedEdge(honv) != null) { return(false); } return(true); }