/// <summary> /// Reverses the roles of vertices and faces, as when taking the dual of a polyhedron. /// </summary> public virtual void MakeDual() { if (firstExternalFaceIndex < faceFirstEdgeIndices.Length) { throw new InvalidOperationException("A dual topology cannot be derived from a topology with external faces."); } GeneralUtility.Swap(ref vertexNeighborCounts, ref faceNeighborCounts); GeneralUtility.Swap(ref vertexFirstEdgeIndices, ref faceFirstEdgeIndices); firstExternalFaceIndex = faceFirstEdgeIndices.Length; var dualEdgeData = new EdgeData[edgeData.Length]; for (int i = 0; i < edgeData.Length; ++i) { // Edges rotate clockwise to point at next faces becoming far vertices, with their // side toward far vertices becoming prev faces. dualEdgeData[i] = new EdgeData( edgeData[i].twin, // twin remains the same edgeData[edgeData[edgeData[i].twin].fNext].twin, // vNext becomes twin of vPrev, where vPrev is the fNext of twin edgeData[i].vNext, // fNext becomes what vNext had been edgeData[edgeData[i].twin].face, // far vertex becomes what had been next face edgeData[i].vertex); // prev face becomes what had been far vertex } edgeData = dualEdgeData; // Due to rotations, face data (which had been vertex data) still points to the same edges, // but vertex data (which had been face data) is now backwards, pointing to edges which // point back at the vertex; this needs to be reversed by setting first edges to their twins. for (int i = 0; i < vertexFirstEdgeIndices.Length; ++i) { vertexFirstEdgeIndices[i] = edgeData[vertexFirstEdgeIndices[i]].twin; } }
private void BubbleUp(int index) { while (index > 0) { var parentIndex = (index - 1) / 2; if (AreOrdered(_heap[parentIndex], _heap[index])) { break; } GeneralUtility.Swap(ref _heap[index], ref _heap[parentIndex]); index = parentIndex; } }
private void PickChange(Vector2 mousePosition) { GeneralUtility.DisableAndThrowOnUnassignedReference(this, partitioning, "The FaceSpatialPartitioningPicker component requires a reference to a UniversalFaceSpatialPartitioning scriptable object. Either create a saved asset using generators available in the Assets/Create/Topology menu, or create and assign one at runtime before the picker's Start() event runs."); var ray = Geometry.InverseTransformRay(transform, camera.ScreenPointToRay(mousePosition)); var face = partitioning.FindFace(ray); if (face && _currentFace != face) { var previousFace = _currentFace; _currentFace = face; OnPickChange.Invoke(previousFace, face); } }
private void PickStart(Vector2 mousePosition, int button) { GeneralUtility.DisableAndThrowOnUnassignedReference(this, partitioning, "The FaceSpatialPartitioningPicker component requires a reference to a UniversalFaceSpatialPartitioning scriptable object. Either create a saved asset using generators available in the Assets/Create/Topology menu, or create and assign one at runtime before the picker's Start() event runs."); var ray = Geometry.InverseTransformRay(transform, camera.ScreenPointToRay(mousePosition)); var startFace = partitioning.FindFace(ray); if (startFace) { _currentFace = startFace; _picking[button] = true; OnPickStart.Invoke(startFace, button); } else { _picking[button] = false; _currentFace = Topology.Face.none; } }
/// <summary> /// Resets the current grid surface with new values for the tile shape and arrangement, origin, orientation, wrapping behavior, and grid size. /// </summary> /// <param name="hexDescriptor">The descriptor structure with details about the shape and arrangement of hexagonal tiles.</param> /// <param name="origin">The origin of the plane.</param> /// <param name="orientation">The orientation of the plane.</param> /// <param name="isAxis0Wrapped">Indicates whether the first axis exhibits wrap-around behavior at the grid boundaries.</param> /// <param name="isAxis1Wrapped">Indicates whether the second axis exhibits wrap-around behavior at the grid boundaries.</param> /// <param name="size">The size of the grid, in terms of the number of tiles along the first and second axes of the surface..</param> /// <returns>A reference to the current surface.</returns> public RectangularHexGrid Reset(HexGridDescriptor hexDescriptor, Vector3 origin, Quaternion orientation, bool isAxis0Wrapped, bool isAxis1Wrapped, IntVector2 size) { midpoint = hexDescriptor.midpoint; majorCorner = hexDescriptor.majorCorner; minorCorner = hexDescriptor.minorCorner; midpointIsFirstAxis = hexDescriptor.midpointIsFirstAxis; axisStyle = hexDescriptor.axisStyle; _originIsObtuse = Vector2.Dot(midpoint, minorCorner) < Vector2.Dot(midpoint, majorCorner); if (axisStyle == HexGridAxisStyles.Straight) { _faceAxis0 = midpoint * 2f; _faceAxis1 = majorCorner + minorCorner; } else { _faceAxis0 = midpoint * 2f; if (_originIsObtuse) { _faceAxis1 = majorCorner + minorCorner + midpoint; } else { _faceAxis1 = majorCorner + minorCorner - midpoint; } } if (!midpointIsFirstAxis) { GeneralUtility.Swap(ref _faceAxis0, ref _faceAxis1); } Reset(new WrappableAxis2(_faceAxis0 * size.x, isAxis0Wrapped), new WrappableAxis2(_faceAxis1 * size.y, isAxis1Wrapped), origin, orientation); this.size = size; topology = null; Initialize(); return(this); }
private void BubbleDown(int index) { var leftChildIndex = index * 2 + 1; var rightChildIndex = leftChildIndex + 1; while (leftChildIndex < _size) { if (rightChildIndex < _size) { if (AreOrdered(_heap[index], _heap[leftChildIndex]) && AreOrdered(_heap[index], _heap[rightChildIndex])) { break; } if (AreOrdered(_heap[leftChildIndex], _heap[rightChildIndex])) { GeneralUtility.Swap(ref _heap[index], ref _heap[leftChildIndex]); index = leftChildIndex; } else { GeneralUtility.Swap(ref _heap[index], ref _heap[rightChildIndex]); index = rightChildIndex; } leftChildIndex = index * 2 + 1; rightChildIndex = leftChildIndex + 1; } else { if (AreOrdered(_heap[index], _heap[leftChildIndex])) { break; } GeneralUtility.Swap(ref _heap[index], ref _heap[leftChildIndex]); index = leftChildIndex; break; } } }
void Start() { GeneralUtility.DisableAndThrowOnUnassignedReference(this, camera, "The FaceSpatialPartitioningPicker component requires a reference to a Camera component."); _collider = GetComponent <Collider>(); }