public void AddLiveNode(Node newNode) { OffsetShapeLog.AddLine("New live node " + _liveNodeIndex); liveNodes.Add(newNode); newNode.id = _liveNodeIndex; _liveNodeIndex++; }
public void DrawDebug(Color col) { OffsetShapeLog.DrawLine(_nodes[0].position, _nodes[1].position, col); OffsetShapeLog.DrawLine(_nodes[1].position, _nodes[2].position, col); OffsetShapeLog.DrawLine(_nodes[2].position, _nodes[0].position, col); Vector3 center = Utils.ToV3((_nodes[0].position + _nodes[1].position + _nodes[2].position) / 3f); OffsetShapeLog.DrawDirection(center, _tangentV3, "tangent", col); OffsetShapeLog.DrawLabel(_centre, "\nTriangle ID " + id); // Vector3 p0 = JMath.ToV3(_nodes[0].position); // Vector3 p1 = JMath.ToV3(_nodes[1].position); // Vector3 p2 = JMath.ToV3(_nodes[2].position); // // Debug.DrawLine(p0, p1, col); // Debug.DrawLine(p1, p2, col); // Debug.DrawLine(p2, p0, col); //// // // Color a = new Color(col.r, col.g, col.b, 0.25f); // Vector3 v0 = p0 + Vector3.up * _nodes[0].height * 20; // Vector3 v1 = p1 + Vector3.up * _nodes[1].height * 20; // Vector3 v2 = p2 + Vector3.up * _nodes[2].height * 20; // // Debug.DrawLine(positions[0], positions[1], col); // Debug.DrawLine(positions[1], positions[2], col); // Debug.DrawLine(positions[2], positions[0], col); // GizmoLabel.Label("Node" + _nodes[0].id, v0); // GizmoLabel.Label("Node" + _nodes[1].id, v1); // GizmoLabel.Label("Node" + _nodes[2].id, v2); }
public void InsertLiveNode(int index, Node newNode) { OffsetShapeLog.AddLine("New live node " + _liveNodeIndex); liveNodes.Insert(index, newNode); newNode.id = _liveNodeIndex; _liveNodeIndex++; }
public void AddTriangle(SkeletonTri newTriangle) { OffsetShapeLog.AddLine("Add Triangle: " + newTriangle[0].id + " " + newTriangle[1].id + " " + newTriangle[2].id); newTriangle.id = _triIndex; _triIndex++; _tris.Add(newTriangle); }
private void CalculateUVs(SkeletonTri tri) { int baseIndex = FindBaseIndex(tri); OffsetShapeLog.DrawLine(tri.centre, tri.positions[baseIndex], Color.red); Vector2 baseUV = Vector2.zero; OffsetShapeLog.AddLine("============"); OffsetShapeLog.AddLine("triangle uv node find! ", tri.id, " base node id ", tri[baseIndex].id, " tangent ", tri.tangentV3); OffsetShapeLog.AddLine("============"); foreach (UVNode uvnode in _uvnodes) { OffsetShapeLog.AddLine("uvnode! ", uvnode.node.id, uvnode.tangent); if (uvnode.node != tri[baseIndex]) { continue; } if (!uvnode.TangentCheck(tri.tangentV3)) { continue; } baseUV = uvnode.uv; } OffsetShapeLog.AddLine("!!!!!!!!!!!!"); OffsetShapeLog.DrawLabel(tri.centre, baseUV.ToString()); int indexB = (baseIndex + 1) % 3; int indexC = (baseIndex + 2) % 3; Vector3 p0 = tri.positions[baseIndex]; Vector3 p1 = tri.positions[indexB]; Vector3 p2 = tri.positions[indexC]; Vector3 vA = p1 - p0; Vector3 vB = p2 - p0; Vector3 right = tri.tangentV3; Vector3 up = Vector3.Cross(right, tri.normal); Vector3 upVA = Vector3.Project(vA, up); Vector3 rightVA = Vector3.Project(vA, right); Vector3 upVB = Vector3.Project(vB, up); Vector3 rightVB = Vector3.Project(vB, right); float apexUVAX = rightVA.magnitude * Mathf.Sign(Vector3.Dot(right, rightVA)); float apexUVAY = upVA.magnitude * Mathf.Sign(Vector3.Dot(up, upVA)); Vector2 apexUVA = baseUV + new Vector2(apexUVAX, apexUVAY); float apexUVBX = rightVB.magnitude * Mathf.Sign(Vector3.Dot(right, rightVB)); float apexUVBY = upVB.magnitude * Mathf.Sign(Vector3.Dot(up, upVB)); Vector2 apexUVB = baseUV + new Vector2(apexUVBX, apexUVBY); _uvnodes.Add(new UVNode(tri[indexB], apexUVA, right)); _uvnodes.Add(new UVNode(tri[indexC], apexUVB, right)); Vector2[] uvs = new Vector2[3]; uvs[baseIndex] = baseUV; uvs[indexB] = apexUVA; uvs[indexC] = apexUVB; tri.uvs = uvs; }
public void DrawDebug(Color col) { Vector2 center = Vector2.zero; for (int i = 0; i < size; i++) { int ib = (i + 1) % size; OffsetShapeLog.DrawLine(_nodes[i].position, _nodes[ib].position, col); center += _nodes[i].position; } center /= size; OffsetShapeLog.DrawEdge(_liveEdge, Color.magenta); OffsetShapeLog.DrawDirection(Utils.ToV3(center), _tangent, "tangent", col); }
public void ReplaceNode(Node oldNode, Node newNode) { OffsetShapeLog.AddLine("ReplaceNode: ", oldNode.id, newNode.id); if (oldNode == newNode) { return; } if (_nodeA == oldNode) { _nodeA = newNode; } if (_nodeB == oldNode) { _nodeB = newNode; } UpdateValues(); }
public Node AddStaticNode(Node newNode) { int staticNodeCount = nodes.Count; for (int s = 0; s < staticNodeCount; s++) { if ((nodes[s].position - newNode.position).sqrMagnitude < (Mathf.Epsilon * Mathf.Epsilon)) { return(nodes[s]); } } OffsetShapeLog.AddLine("New static node " + _staticNodeIndex); nodes.Add(newNode); newNode.id = _staticNodeIndex; _staticNodeIndex++; return(newNode); }
public SplitEvent CreateSplitEvent(Shape data, Node node, Edge edge, Vector2 point, float eventPercent, Vector2 calculationPoint) { OffsetShapeLog.AddLine("Split event detected"); SplitEvent splitEvent = new SplitEvent(); splitEvent.node = node; splitEvent.edge = edge; OffsetShapeLog.AddLine(eventPercent.ToString("P")); OffsetShapeLog.AddLine("node " + node.id); OffsetShapeLog.AddLine("splits edge " + edge); Vector2 a = node.previousPosition; Vector2 b = node.position; // Vector2 x = point;//intersectionInfo.Point0; // float movementMag = nodeMovement.magnitude; // float intersectionMag = (x - a).magnitude; // float eventPercent = intersectionMag / movementMag; Vector2 actualIntersectionPoint = Vector2.Lerp(a, b, eventPercent);//translate the point to the real movement point splitEvent.point = actualIntersectionPoint; splitEvent.percent = eventPercent; splitEvent.height = node.height; splitEvent.nodeMovementStart = node.previousPosition; //movementSegment.P0; splitEvent.nodeMovementEnd = node.position; //calculationPoint;//movementSegment.P1; Edge[] edges = Utils.GetABEdge(data, node); if (edges[0] == null || edges[1] == null) { return(null); } splitEvent.nodeEdgeA = edges[0]; splitEvent.nodeEdgeB = edges[1]; if (splitEvent.ContainsNode(splitEvent.nodeEdgeA.GetOtherNode(node))) { OffsetShapeLog.AddLine("Split event collapses shape"); } if (splitEvent.ContainsNode(splitEvent.nodeEdgeB.GetOtherNode(node))) { OffsetShapeLog.AddLine("Split event collapses shape"); } // AddEvent(splitEvent); return(splitEvent); }
public void Draw() { OffsetShapeLog.enabled = true; OffsetShapeLog.DrawShapeNodes(_core.shape); int triCount = nodeTris.Count; for (int t = 0; t < triCount; t += 3) { Node a = nodeTris[t]; Node b = nodeTris[t + 1]; Node c = nodeTris[t + 2]; Debug.DrawLine(Utils.ToV3(a.position), Utils.ToV3(b.position), Color.yellow); Debug.DrawLine(Utils.ToV3(b.position), Utils.ToV3(c.position), Color.yellow); Debug.DrawLine(Utils.ToV3(c.position), Utils.ToV3(a.position), Color.yellow); } }
public void SplitEvent(SplitEvent sEvent) { if (_substitutions.ContainsKey(sEvent.node)) { OffsetShapeLog.AddLine(sEvent.node + " is replaced with " + _substitutions[sEvent.node]); sEvent.node = _substitutions[sEvent.node];//replce any modified node values } if (sEvent.edge.Contains(sEvent.node))//edge splitting itself { return; } if (_collapsedEdges.ContainsKey(sEvent.edge)) { CollapseNodes(new List <Node> { sEvent.node, _collapsedEdges[sEvent.edge] }, sEvent.point, sEvent.height, sEvent); OffsetShapeLog.AddLine("Split event falls on edge collapse."); return;//if the edge we were splitting already collaped - merge it } if (_splitEdges.ContainsKey(sEvent.edge)) { SplitEvent previousSplit = _splitEdges[sEvent.edge]; float sqrMagA = Vector2.SqrMagnitude(sEvent.edge.nodeA.position - sEvent.point); float sqrMagB = Vector2.SqrMagnitude(previousSplit.edge.nodeA.position - previousSplit.point); if (sqrMagA < sqrMagB) { OffsetShapeLog.AddLine(sEvent.edge.ToString() + " is replaced with " + previousSplit.newLiveEdgeA.ToString()); sEvent.edge = previousSplit.newLiveEdgeA; } else { OffsetShapeLog.AddLine(sEvent.edge.ToString() + " is replaced with " + previousSplit.newLiveEdgeB.ToString()); sEvent.edge = previousSplit.newLiveEdgeB; } } SplitEdge(sEvent); }
private bool ShapeIntersection(Vector2[] points) { int pointCount = points.Length; for (int i = 0; i < pointCount; i++) { int ib = (i + 1) % pointCount; for (int j = 0; j < pointCount; j++) { if (i == j) { continue; } if (ib == j) { continue; } int jb = (j + 1) % pointCount; if (i == jb) { continue; } if (ib == jb) { continue; } Vector2 intersection; if (Utils.Intersects(points[i], points[ib], points[j], points[jb], out intersection)) { OffsetShapeLog.DrawLine(JMath.ToV3(points[i]), JMath.ToV3(points[ib]), Color.magenta); OffsetShapeLog.DrawLine(JMath.ToV3(points[j]), JMath.ToV3(points[jb]), Color.yellow); OffsetShapeLog.DrawLine(JMath.ToV3(intersection), JMath.ToV3(intersection) + Vector3.up * 10, Color.red); return(true); } } } return(false); }
public void Build(SkeletonData data) { System.Collections.Generic.List <SkeletonTri> allTris = new System.Collections.Generic.List <SkeletonTri>(data.mesh.GetTriangles()); System.Collections.Generic.List <SkeletonTri> startTris = new System.Collections.Generic.List <SkeletonTri>(); int triCount = allTris.Count; for (int t = 0; t < triCount; t++) { SkeletonTri tri = allTris[t]; if (tri.hasStartEdge) { allTris.RemoveAt(t); triCount--; t--; startTris.Add(tri); } } while (startTris.Count > 0) { SkeletonTri tri = startTris[0]; startTris.RemoveAt(0); CalculateUVs(tri); } while (allTris.Count > 0) { SkeletonTri tri = allTris[0]; allTris.RemoveAt(0); CalculateUVs(tri); } foreach (UVNode uvnode in _uvnodes) { OffsetShapeLog.DrawLabel(uvnode.node.position, "\n\n" + uvnode.uv); } }
private void AddFace(Edge liveEdge, Node staticNodeA, Node staticNodeB) { OffsetShapeLog.DrawEdge(liveEdge, Color.red); OffsetShapeLog.DrawLabel(liveEdge.nodeA.position, "new face"); SkeletonFace face = new SkeletonFace(liveEdge, staticNodeA, staticNodeB); _faces.Add(face); if (!_edgeDic.ContainsKey(liveEdge.nodeA)) { _edgeDic.Add(liveEdge.nodeA, new List <SkeletonFace>()); _edgeDic[liveEdge.nodeA].Add(face); } else { _edgeDic[liveEdge.nodeA].Add(face); } if (!_edgeDic.ContainsKey(liveEdge.nodeB)) { _edgeDic.Add(liveEdge.nodeB, new List <SkeletonFace>()); _edgeDic[liveEdge.nodeB].Add(face); } else { _edgeDic[liveEdge.nodeB].Add(face); } if (!_nodeDic.ContainsKey(liveEdge)) { _nodeDic.Add(liveEdge, face); } else { _nodeDic[liveEdge] = face; } }
// public void CollapseEdge(Edge edge, Vector2 toPoint, float height) // { // List<Node> nodes = new List<Node>(); // nodes.Add(edge.nodeA); // nodes.Add(edge.nodeB); // CollapseNodes(nodes, toPoint, height); // } public void MergeEvent(MergedEvent mEvent) { OffsetShapeLog.AddLine("Complex merge event gynastics ahead"); CollapseNodes(mEvent.mergeNodes, mEvent.point, mEvent.height, mEvent); int splitCount = mEvent.splitEvents.Count; OffsetShapeLog.AddLine("Do the splits - in percent order"); float currentPercent = -1; for (int s = 0; s < splitCount; s++) { float minimumPercent = 1; SplitEvent candidate = null; for (int so = 0; so < splitCount; so++) { SplitEvent sEvent = mEvent.splitEvents[so]; // OffsetShapeLog.AddLine(sEvent.ToString()); // OffsetShapeLog.AddLine(sEvent.percent, currentPercent); if (sEvent.percent > currentPercent) { // OffsetShapeLog.AddLine(sEvent.percent, minimumPercent); if (sEvent.percent < minimumPercent) { minimumPercent = sEvent.percent; candidate = sEvent; } } } if (candidate != null) { SplitEvent(candidate); currentPercent = candidate.percent; } // mEvent.splitEvents[s].point = mEvent.point; } }
public MergedEvent CreateMergeEvent(Node[] nodes, Vector2 atPoint, float eventPercent, Vector2 calculationPoint) { OffsetShapeLog.AddLine("Merge event detected"); OffsetShapeLog.Add(nodes); MergedEvent mergeEvent = new MergedEvent(); mergeEvent.mergeNodes.AddRange(nodes); mergeEvent.point = atPoint; float height = 0; // float eventPercent = 1; foreach (Node node in nodes) { height += node.height; // float pointDistance = Vector2.Distance(atPoint, node.previousPosition); // float pointPercent = pointDistance / node.distance; // eventPercent = Mathf.Min(eventPercent, pointPercent); } mergeEvent.height = height / nodes.Length; mergeEvent.percent = eventPercent; // AddEvent(mergeEvent); return(mergeEvent); }
public void OffsetPoly(float direction) { if (!_init) { return; } float amount = _shape.shrinkLength * SHINK_MULTIPLIER * Mathf.Sign(direction); int liveEdgeCount = _shape.liveEdges.Count; int liveNodeCount = _shape.liveNodes.Count; if (liveNodeCount == 0 || liveEdgeCount == 0)//nothing more to calculate { OffsetShapeLog.AddLine("Skeleton Complete"); _complete = true; if (OnCompleteEvent != null) { OnCompleteEvent(); } return; } bool earlyTermination = false; float directionSign = Mathf.Sign(direction); float maxOffsetSign = Mathf.Sign(maxOffset); float useMaxOffset = (directionSign == maxOffsetSign) ? maxOffset : -maxOffset; for (int l = 0; l < liveNodeCount; l++) { Node node = _shape.liveNodes[l]; // if(l==0)Debug.Log(node.height+" "+amount+" "+useMaxOffset); if (useMaxOffset > 0) { if (node.height + amount >= useMaxOffset)//terminate nodes that have reached a defined maximum { amount = useMaxOffset - node.height; earlyTermination = true; } } else if (useMaxOffset < 0) { if (node.height + amount <= useMaxOffset)//terminate nodes that have reached a defined maximum { amount = useMaxOffset - node.height; earlyTermination = true; } } } float maxMovement = 0; liveNodeCount = _shape.liveNodes.Count; float[] angleNodeMovements = new float[liveNodeCount]; for (int l = 0; l < _shape.liveNodes.Count; l++) { // Debug.Log(l); Node node = _shape.liveNodes[l];//TODO out of range error angleNodeMovements[l] = amount / Mathf.Sin(node.angle * 0.5f * Mathf.Deg2Rad); if (Mathf.Abs(angleNodeMovements[l]) > Mathf.Abs(maxMovement) && Mathf.Abs(angleNodeMovements[l]) > 0) { maxMovement = angleNodeMovements[l]; if (node.angle > 350) { Edge[] edges = Utils.GetABEdge(shape, node); if (edges[0] == null || edges[1] == null) { continue; } float shortestLength = (edges[0].length + edges[1].length) * 0.5f; // Debug.Log(Mathf.Abs(shortestLength / amount)); maxMovement /= Mathf.Abs(shortestLength / amount); } // Debug.Log(node.id+" "+node.angle); } } float angleScale = amount / maxMovement; if (angleScale == Mathf.Infinity) { angleScale = 1; } OffsetShapeLog.AddLine(angleScale); for (int l = 0; l < _shape.liveNodes.Count; l++) { Node node = _shape.liveNodes[l]; if (node.direction.magnitude < Mathf.Epsilon)//directionless node { _shape.liveNodes.Remove(node); liveNodeCount--; l--; continue; } node.MoveForward(angleNodeMovements[l] * angleScale, amount * angleScale); } Vector2[] edgeMovements = new Vector2[liveEdgeCount]; if (calculateInteractions) { //Event log will collect all events and sort them for us for use once we're happy everything has been processed EventLog eventLog = new EventLog(); EventLog.pointAccuracy = pointAccuracy; EventLog.percentAccuracy = percentAccuracy; //flip events for (int e = 0; e < liveEdgeCount; e++)//TODO check laters { Edge edge = _shape.liveEdges[e]; edge.DebugDraw(Color.cyan); edge.UpdateValues();//update the edge values to reflect the new node positions Node nodeA = edge.nodeA; Node nodeB = edge.nodeB; edgeMovements[e] = (nodeA.movement + nodeB.movement) * 0.5f; Vector2 intersectionPoint; if (Utils.Intersects(edge.nodeA.previousPosition, edge.nodeA.position, edge.nodeB.previousPosition, edge.nodeB.position, out intersectionPoint)) { eventLog.AddEvent(eventLog.CreateFlipEvent(edge, intersectionPoint)); } } // //split events for (int n = 0; n < _shape.liveNodeCount; n++) { Node node = _shape.liveNodes[n]; int nodeID = node.id; //find connecting nodes of splitting node Node nodeA = null, nodeB = null; for (int e = 0; e < liveEdgeCount; e++) { Edge edge = _shape.liveEdges[e]; if (edge.Contains(node)) { if (edge.nodeA == node) { nodeB = edge.nodeB; } if (edge.nodeB == node) { nodeA = edge.nodeA; } } } for (int e = 0; e < liveEdgeCount; e++) { Edge edge = _shape.liveEdges[e]; if (edge.Contains(node)) { continue; //nodes can't split their own edges - carry on! } if (nodeA != null && edge.Contains(nodeA)) { continue; //nodes can't split adjacent edges - carry on! } if (nodeB != null && edge.Contains(nodeB)) { continue; //nodes can't split adjacent edges - carry on! } if (currentSplits.ContainsKey(nodeID)) //previous splits should never intersect - ingore { if (currentSplits[nodeID].Contains(edge.nodeA.id)) { continue; } if (currentSplits[nodeID].Contains(edge.nodeB.id)) { continue; } } // if(!isPartOfShape(node, edge)) continue; Vector2 edgeMovement = edgeMovements[e]; Vector2 nodeMovement = node.direction * node.distance - edgeMovement; //simulate collision by moving the point by the vectors of both the point and the edge, //note: collisions are simpler if only one body is moving so we're going to add the edge vector onto the point vector, making the edge remain stationary Vector2 calculationPoint = node.previousPosition + nodeMovement; //calculate the point vector by adding the edge one to it Vector2 edgePosA = edge.nodeA.previousPosition; Vector2 edgePosB = edge.nodeB.previousPosition; // float intersectionalDot = Vector2.Dot(edgeMovement.normalized, node.direction.normalized); // OffsetShapeLog.DrawLine(node.previousPosition, calculationPoint,new Color(1,0,0,0.4f)); // OffsetShapeLog.DrawLine(edgePosA, edgePosB, new Color(1, 0, 1, 0.4f)); Vector2 intersectionPoint; float percent = 0; bool intersects = false; // if (intersectionalDot < -10.75f) // { // Debug.DrawLine(Utils.ToV3(node.previousPosition), Utils.ToV3(calculationPoint), Color.red); // intersects = Utils.Intersects(node.previousPosition, calculationPoint, edgePosA, edgePosB, out intersectionPoint); // if (intersects) // { // Debug.DrawLine(Utils.ToV3(calculationPoint), Utils.ToV3(calculationPoint) + Vector3.up * 5, Color.magenta); // } // Vector2 a = node.previousPosition; // Vector2 b = node.position; // float movementMag = nodeMovement.magnitude; // float intersectionMag = (intersectionPoint - a).magnitude; // percent = intersectionMag / movementMag; // intersectionPoint = Vector2.Lerp(a, b, percent);//translate the point to the real movement point // } // else // { bool dbi = false;//node.id == 14; intersects = Utils.SweepIntersects2(edge.nodeA.previousPosition, edge.nodeB.previousPosition, edge.nodeA.position, edge.nodeB.position, node.previousPosition, node.position, out intersectionPoint, out percent, 0.1f, dbi); calculationPoint = node.position; // } // if(Utils.Intersects(node.previousPosition, calculationPoint, edgePosA, edgePosB, out intersectionPoint)) // if (Utils.SweepIntersects(edge.nodeA.previousPosition , edge.nodeB.previousPosition, edge.nodeA.position, edge.nodeB.position, node.previousPosition, node.position, out intersectionPoint, out percent)) if (intersects) { for (int be = 0; be < shape.baseEdges.Count; be++) { Edge baseEdge = shape.edges[be]; if (Utils.FastLineIntersection(node.previousPosition, node.position, baseEdge.positionA, baseEdge.positionB)) { intersects = false; } if (Utils.FastLineIntersection(edge.nodeA.position, edge.nodeB.position, baseEdge.positionA, baseEdge.positionB)) { intersects = false; } } } if (intersects) { OffsetShapeLog.AddLine("Split event detected"); SplitEvent splitEvent = new SplitEvent(); splitEvent.node = node; splitEvent.edge = edge; OffsetShapeLog.AddLine("node " + node.id); OffsetShapeLog.AddLine("splits edge " + edge.ToString()); OffsetShapeLog.DrawLine(node.previousPosition, calculationPoint, Color.red); OffsetShapeLog.DrawLine(edgePosA, edgePosB, Color.magenta); // Vector2 a = node.previousPosition; // Vector2 b = node.position; // Vector2 x = intersectionPoint;//intersectionInfo.Point0; // float movementMag = nodeMovement.magnitude; // float intersectionMag = (x - a).magnitude; // float percent = intersectionMag / movementMag; OffsetShapeLog.AddLine("at percent " + percent); // Vector2 actualIntersectionPoint = Vector2.Lerp(a, b, percent);//translate the point to the real movement point float newLengthA = (intersectionPoint - edge.positionA).magnitude; float newLengthB = (intersectionPoint - edge.positionB).magnitude; OffsetShapeLog.AddLine("line a length ", newLengthA); OffsetShapeLog.AddLine("line b length ", newLengthB); SplitEvent sEvent = eventLog.CreateSplitEvent(_shape, node, edge, intersectionPoint, percent, calculationPoint); if (sEvent == null) { continue; } if (newLengthA > pointAccuracy && newLengthB > pointAccuracy) { eventLog.AddEvent(sEvent);//can split - split point not close to either edge nodes } else { Node[] nodes = null; if (newLengthA < pointAccuracy && newLengthB < pointAccuracy) { nodes = new[] { node, edge.nodeA, edge.nodeB } } ; //point will split the edge into two edges that can't exist - collapse all nodes else if (newLengthA < pointAccuracy) { nodes = new[] { node, edge.nodeA } } ; //split point close to node a - collapse split node into edge.nodea else if (newLengthB < pointAccuracy) { nodes = new[] { node, edge.nodeB } } ; //split point close to node b - collapse split node into edge.nodeb if (nodes != null) { MergedEvent mEvent = eventLog.CreateMergeEvent(nodes, intersectionPoint, percent, calculationPoint); mEvent.Merge(sEvent); eventLog.AddEvent(mEvent); } } } } } currentSplits.Clear(); int eventCount = eventLog.count; OffsetShapeLog.AddLine("event count: ", eventCount); if (eventCount > 0) { float percent = eventLog.percent; earlyTermination = false; foreach (Node node in _shape.liveNodes) { node.MoveBack(percent);//move all nodes back to the position of the event } foreach (Edge edge in _shape.liveEdges) { edge.UpdateValues();//update all edges to reflect this } foreach (Node node in _shape.liveNodes) { if (_shape.formingEdges.ContainsKey(node)) { _shape.formingEdges[node].UpdateValues(); } } for (int e = 0; e < eventCount; e++) { IEvent sevent = eventLog[e]; sevent.DrawDebug(); OffsetShapeLog.AddLine(string.Format("Event {0} of type {4} at {1} percent and {2},{3}", e, sevent.percent, sevent.point.x, sevent.point.y, sevent.GetType())); switch (sevent.GetType().ToString()) { case "BuildR2.ShapeOffset.FlipEvent": FlipEvent fEvent = (FlipEvent)sevent; OffsetShapeLog.AddLine(fEvent.ToString()); if (OnFlipEvent != null) { OnFlipEvent(fEvent); } // CollapseEdge(fEvent.edge, fEvent.point, fEvent.height); break; case "BuildR2.ShapeOffset.SplitEvent": SplitEvent sEvent = (SplitEvent)sevent; OffsetShapeLog.AddLine(sevent.ToString()); if (OnSplitEvent != null) { OnSplitEvent(sEvent); } // SplitEdge(sEvent); break; case "BuildR2.ShapeOffset.MergedEvent": MergedEvent mEvent = (MergedEvent)sevent; OffsetShapeLog.AddLine(mEvent.ToString()); if (OnMergedEvent != null) { OnMergedEvent(mEvent); } // MergeEvent(mEvent); break; } } } else { if (!earlyTermination) { float percent = 1.0f - percentAccuracy; earlyTermination = false; foreach (Node node in _shape.liveNodes) { node.MoveBack(percent);//move all nodes back to the position of the event } foreach (Edge edge in _shape.liveEdges) { edge.UpdateValues();//update all edges to reflect this } } foreach (Node node in _shape.liveNodes) { if (_shape.formingEdges.ContainsKey(node)) { _shape.formingEdges[node].UpdateValues(); } } } } if (earlyTermination) { _complete = true; _shape.TerminateAllNodes(); if (OnCompleteEvent != null) { OnCompleteEvent(); } return; } else { //recalculate node directions foreach (Node node in _shape.liveNodes) { Utils.CalculateNodeDirAng(_shape, node); } } }
public override void Log() { OffsetShapeLog.AddLine("Merge event "); base.Log(); }
private void CollapseNodes(List <Node> nodes, Vector2 toPoint, float height, BaseEvent evt) { if (nodes.Count < 2) { return; } OffsetShapeLog.AddLine("Collapse Nodes:"); foreach (Node node in nodes) { OffsetShapeLog.Add(node.id + " "); } OffsetShapeLog.AddLine("to point: ", toPoint); Node newStaticNode = (evt.newStaticNode == null) ? new Node(toPoint, height) : evt.newStaticNode;//new static node to mark point of collapse evt.newStaticNode = newStaticNode; _core.shape.AddStaticNode(newStaticNode);//add static node to node array int liveEdgeCount = _core.shape.liveEdges.Count; List <Edge> liveEdges = new List <Edge>(); // Node newLiveNode = new Node(toPoint, nodes[0].height);//new live node to continue shape forming int nodeCount = nodes.Count; for (int n = 0; n < nodeCount; n++) { nodes[n].position = toPoint; } for (int e = 0; e < liveEdgeCount; e++) { Edge edge = _core.shape.liveEdges[e]; if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB)) { continue; } edge.UpdateValues(); if (edge.length < pointAccuracy)//when the edge reaches 0 length it has flipped and should be collapsed { OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, pointAccuracy); OffsetShapeLog.AddLine("Remove edge ", edge.ToString()); _core.shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero _collapsedEdges.Add(edge, newStaticNode); liveEdgeCount--; e--; if (!nodes.Contains(edge.nodeA)) { nodes.Add(edge.nodeA); } if (!nodes.Contains(edge.nodeB)) { nodes.Add(edge.nodeB); } } } OffsetShapeLog.AddLine("find live node edges"); Dictionary <Node, int> nodeOccurances = new Dictionary <Node, int>();//check parallel collapses for (int e = 0; e < liveEdgeCount; e++) { Edge edge = _core.shape.liveEdges[e]; if (!edge.Contains(nodes)) { continue; //unaffected edge } if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB)) //edge is completely affected by the merge and has collapsed { OffsetShapeLog.AddLine("Remove collapsed edge ", edge.ToString()); _core.shape.liveEdges.Remove(edge);//remove collapsed edge _collapsedEdges.Add(edge, newStaticNode); liveEdgeCount--; e--; continue; } if (nodes.Contains(edge.nodeA))// || newLiveNode == edge.nodeA) { // edge.ReplaceNode(edge.nodeA, newLiveNode);//replace old live node reference to new one //TODO liveEdges.Add(edge); OffsetShapeLog.AddLine("Live edges: ", edge); if (nodeOccurances.ContainsKey(edge.nodeB)) { nodeOccurances[edge.nodeB]++; } else { nodeOccurances.Add(edge.nodeB, 1); } continue; } if (nodes.Contains(edge.nodeB))// || newLiveNode == edge.nodeB) { // edge.ReplaceNode(edge.nodeB, newLiveNode);//replace old live node reference to new one //TODO liveEdges.Add(edge); OffsetShapeLog.AddLine("Live edges: ", edge); if (nodeOccurances.ContainsKey(edge.nodeA)) { nodeOccurances[edge.nodeA]++; } else { nodeOccurances.Add(edge.nodeA, 1); } } } int affectedLiveEdges = liveEdges.Count; foreach (KeyValuePair <Node, int> kv in nodeOccurances) { OffsetShapeLog.AddLine("node occured: ", kv.Key.id, kv.Value); if (kv.Value > 1) { Node pinchedNode = kv.Key; OffsetShapeLog.AddLine("Pinched node: ", pinchedNode.id); pinchedNode.position = toPoint; for (int a = 0; a < affectedLiveEdges; a++) { shape.formingEdges[kv.Key].ReplaceNode(kv.Key, newStaticNode); if (liveEdges[a].Contains(kv.Key))//any live edges that contains the node should be culled - it has collapsed { Edge edge = liveEdges[a]; OffsetShapeLog.AddLine("Collapsed Edge: ", edge); liveEdges.Remove(edge); _core.shape.liveEdges.Remove(edge);//remove collapsed edge affectedLiveEdges--; a--; } } Utils.RetireFormingEdge(shape, kv.Key, newStaticNode); _core.shape.liveNodes.Remove(kv.Key); } } // for (int n = 0; n < nodeCount; n++) // { // Node node = nodes[n]; // Utils.RetireFormingEdge(_core.shape, node, newStaticNode); // _core.shape.liveNodes.Remove(node); //// _substitutions.Add(node, newLiveNode); TODO EEK! // } OffsetShapeLog.AddLine("Live edges: ", liveEdges.Count); if (affectedLiveEdges > 0)//deal with left live edges after the collapse - calculate the angle the new node needs to move into { float[] angles = new float[affectedLiveEdges]; int smallestAngleIndex = 0;//keep this for when we need to loop the angle comparison float smallestAngle = Mathf.Infinity; for (int a = 0; a < affectedLiveEdges; a++) { Node from = liveEdges[a].GetEdgeNode(nodes); Node to = liveEdges[a].GetOtherNode(from); Vector2 dir = (to.position - from.position).normalized; float angle = Utils.SignAngle(dir); angles[a] = angle; OffsetShapeLog.AddLine(liveEdges[a], angle); if (angle < smallestAngle) { smallestAngle = angle; smallestAngleIndex = a; } } Edge startEdge = null; for (int a = 0; a < affectedLiveEdges; a++) { if (nodes.Contains(liveEdges[a].nodeA)) { startEdge = liveEdges[a]; break; } } if (startEdge != null) { Edge[] orderedEdges = new Edge[affectedLiveEdges]; orderedEdges[0] = startEdge; Edge currentEdge = startEdge; float currentAngle = angles[liveEdges.IndexOf(currentEdge)]; int orderIndex = 1; OffsetShapeLog.AddLine("order edges by angle"); OffsetShapeLog.AddLine(0, startEdge); while (orderIndex < affectedLiveEdges) { Edge candidate = null; float candidateAngle = Mathf.Infinity; for (int a = 0; a < affectedLiveEdges; a++) { Edge nextEdge = liveEdges[a]; if (currentEdge == nextEdge) { continue; } float nextAngle = angles[liveEdges.IndexOf(nextEdge)]; if (nextAngle > currentAngle) { if (nextAngle < candidateAngle) { candidateAngle = nextAngle; candidate = nextEdge; } } } if (candidate == null) { candidate = liveEdges[smallestAngleIndex]; } if (candidate != null) { OffsetShapeLog.AddLine(orderIndex, candidate); orderedEdges[orderIndex] = candidate; orderIndex++; currentEdge = candidate; currentAngle = angles[liveEdges.IndexOf(currentEdge)]; } } OffsetShapeLog.AddLine("affected Live Edge count" + affectedLiveEdges); List <Node> newLiveNodes = new List <Node>(); if (affectedLiveEdges % 2 != 0) { // Debug.LogError("affected Live Edge count uneven: "+ affectedLiveEdges); // Debug.LogError(""); return; } for (int o = 0; o < affectedLiveEdges; o += 2) { Edge splitEdgeA = orderedEdges[o]; Edge splitEdgeB = orderedEdges[o + 1]; OffsetShapeLog.AddLine("split Edge A", splitEdgeA); OffsetShapeLog.AddLine("split Edge B", splitEdgeB); Node newLiveNode = new Node(toPoint, nodes[0].height); //new live node to continue shape forming _core.shape.AddLiveNode(newLiveNode); //new live node from collapse newLiveNodes.Add(newLiveNode); if (nodes.Contains(splitEdgeA.nodeA)) { splitEdgeA.ReplaceNode(splitEdgeA.nodeA, newLiveNode);//replace old live node reference to new one } else { splitEdgeA.ReplaceNode(splitEdgeA.nodeB, newLiveNode);//replace old live node reference to new one } if (nodes.Contains(splitEdgeB.nodeA)) { splitEdgeB.ReplaceNode(splitEdgeB.nodeA, newLiveNode);//replace old live node reference to new one } else { splitEdgeB.ReplaceNode(splitEdgeB.nodeB, newLiveNode);//replace old live node reference to new one } Node x = splitEdgeA.GetOtherNode(newLiveNode); Node y = splitEdgeB.GetOtherNode(newLiveNode); Utils.CalculateNodeDirAng(newLiveNode, x, y); //recalculate node angle Utils.NewFormingEdge(_core.shape, newStaticNode, newLiveNode); //add new forming edge } int newLiveNodeCount = newLiveNodes.Count; for (int l = 0; l < newLiveNodeCount; l++) { Node lNode = newLiveNodes[l]; if (!_core.currentSplits.ContainsKey(lNode.id)) { _core.currentSplits.Add(lNode.id, new List <int>()); } for (int lb = 0; lb < newLiveNodeCount; lb++) { if (l == lb) { continue; } Node lbNode = newLiveNodes[lb]; _core.currentSplits[lNode.id].Add(lbNode.id); } } } // Edge edgeA = null, edgeB = null; // liveEdgeCount = _core.shape.liveEdges.Count; // for (int e = 0; e < liveEdgeCount; e++)//find the two edges left from the collapse // { // Edge edge = _core.shape.liveEdges[e]; // if (!_core.shape.liveEdges.Contains(edge)) continue;//not a live edge // if (edge.nodeA == newLiveNode) edgeA = edge; // if (edge.nodeB == newLiveNode) edgeB = edge; // } // // if (edgeA != null && edgeB != null)//if there is a live edge // { // Node x = edgeA.GetOtherNode(newLiveNode); // Node y = edgeB.GetOtherNode(newLiveNode); // Utils.CalculateNodeDirAng(newLiveNode, x, y);//recalculate node angle // Utils.NewFormingEdge(_core.shape, newStaticNode, newLiveNode);//add new forming edge // } // else // { // OffsetShapeLog.AddLine("New live node has not been calculted ", newLiveNode.id); // } } for (int n = 0; n < nodeCount; n++) { Node node = nodes[n]; Utils.RetireFormingEdge(_core.shape, node, newStaticNode); _core.shape.liveNodes.Remove(node); // _substitutions.Add(node, newLiveNode); TODO EEK! } Utils.CheckParrallel(_core.shape); }
private void Merge(SplitEvent e) { // bool proximity = Vector2.Distance(e.point, point) < EventLog._pointAccuracy; OffsetShapeLog.AddLine("merging split event", e); // if (proximity) // { // splitEvents.Add(e); // int splitCount = splitEvents.Count; // for(int s = 0; s < splitCount; s++) // { // if(Vector2.Distance(splitEvents[s].point, point) < EventLog._pointAccuracy) // { // if (!mergeNodes.Contains(splitEvents[s].node)) // mergeNodes.Add(splitEvents[s].node); //// if (!mergeNodes.Contains(splitEvents[s].edge.nodeA)) //// mergeNodes.Add(splitEvents[s].edge.nodeA); //// if (!mergeNodes.Contains(splitEvents[s].edge.nodeB)) //// mergeNodes.Add(splitEvents[s].edge.nodeB); // } // } // point = e.point; // percent = Mathf.Min(percent, e.percent); // } // else // { int splitCount = splitEvents.Count; bool addSplit = true; for (int s = 0; s < splitCount; s++) { SplitEvent os = splitEvents[s]; OffsetShapeLog.AddLine("checking against split event node", os.node); if (os.node == e.node) { addSplit = false; OffsetShapeLog.AddLine("new merged split conflicts with internal splits - disolving into collapsing node"); splitEvents.RemoveAt(s); if (!mergeNodes.Contains(e.node)) { mergeNodes.Add(e.node); } if (!mergeNodes.Contains(os.node)) { mergeNodes.Add(os.node); } if (e.edge.nodeA == os.edge.nodeA || e.edge.nodeA == os.edge.nodeB && !mergeNodes.Contains(e.edge.nodeA)) { mergeNodes.Add(e.edge.nodeA); } if (e.edge.nodeB == os.edge.nodeA || e.edge.nodeB == os.edge.nodeB && !mergeNodes.Contains(e.edge.nodeB)) { mergeNodes.Add(e.edge.nodeB); } point = e.point; percent = Mathf.Min(percent, e.percent); s--; splitCount--; } } if (!addSplit) { return; } point = e.point; splitEvents.Add(e); percent = Mathf.Min(percent, e.percent); // } }
public void SplitEdge(SplitEvent e) { OffsetShapeLog.AddLine("Split event"); OffsetShapeLog.AddLine("by node ", e.node.id); OffsetShapeLog.AddLine(e.edge.ToString()); //nodes float realHeight = e.node.height; Node nodeStatic = (e.newStaticNode == null) ? new Node(e.point, realHeight) : e.newStaticNode; e.newStaticNode = nodeStatic; Node nodeOldA = e.edge.nodeA; Node nodeOldB = e.edge.nodeB; Edge[] edges = Utils.GetABEdge(shape, e.node); if (edges[0] == null || edges[1] == null) { //TODO work out what to really do here. return; } Edge byEdgeA = edges[0]; Edge byEdgeB = edges[1]; Node byNodeA = byEdgeA.GetOtherNode(e.node); Node byNodeB = byEdgeB.GetOtherNode(e.node); OffsetShapeLog.AddLine("by node a", byNodeA.id); OffsetShapeLog.AddLine("by node b", byNodeB.id); if (byNodeA == null || byNodeB == null) { return; } int insertionIndex = _core.shape.LiveIndex(e.node); _core.shape.AddStaticNode(nodeStatic); _core.shape.liveNodes.Remove(e.node); //discard the old edge OffsetShapeLog.AddLine("Discard old edge ", e.edge.ToString()); _core.shape.liveEdges.Remove(e.edge);// if (!_splitEdges.ContainsKey(e.edge)) { _splitEdges.Add(e.edge, e); } Utils.RetireFormingEdge(_core.shape, e.node, nodeStatic); Node newLiveNodeA = null; Node newLiveNodeB = null; //node a if (!e.edge.Contains(byNodeA)) { newLiveNodeA = new Node(e.point, realHeight); e.newLiveNodeA = newLiveNodeA; //calculate new node directions Utils.CalculateNodeDirAng(newLiveNodeA, byNodeA, nodeOldA); _core.shape.InsertLiveNode(insertionIndex, newLiveNodeA); byEdgeA.ReplaceNode(e.node, newLiveNodeA); //create the two new edges from the split Edge newEdgeA = new Edge(nodeOldA, newLiveNodeA); _core.shape.liveEdges.Add(newEdgeA); e.newLiveEdgeA = newEdgeA; Edge formingEdgeA = Utils.NewFormingEdge(_core.shape, nodeStatic, newLiveNodeA); OffsetShapeLog.AddLine("new live node a"); OffsetShapeLog.AddLine(newLiveNodeA.id); OffsetShapeLog.AddLine("new edges - old edge - forming edge a"); OffsetShapeLog.AddLine(newEdgeA.ToString()); OffsetShapeLog.AddLine(byEdgeA.ToString()); OffsetShapeLog.AddLine(formingEdgeA.ToString()); } else { Utils.RetireFormingEdge(_core.shape, byNodeA, nodeStatic); _core.shape.liveNodes.Remove(byNodeA); } //node b if (!e.edge.Contains(byNodeB)) { newLiveNodeB = new Node(e.point, realHeight); e.newLiveNodeB = newLiveNodeB; Utils.CalculateNodeDirAng(newLiveNodeB, nodeOldB, byNodeB); _core.shape.InsertLiveNode(insertionIndex, newLiveNodeB); byEdgeB.ReplaceNode(e.node, newLiveNodeB); Edge newEdgeB = new Edge(newLiveNodeB, nodeOldB); _core.shape.liveEdges.Add(newEdgeB); e.newLiveEdgeB = newEdgeB; Edge formingEdgeB = Utils.NewFormingEdge(_core.shape, nodeStatic, newLiveNodeB); OffsetShapeLog.AddLine("new live node b"); OffsetShapeLog.AddLine(newLiveNodeB.id); OffsetShapeLog.AddLine("new edges - old edge - forming edge b"); OffsetShapeLog.AddLine(byEdgeB.ToString()); OffsetShapeLog.AddLine(newEdgeB.ToString()); OffsetShapeLog.AddLine(formingEdgeB.ToString()); } else { Utils.RetireFormingEdge(_core.shape, byNodeB, nodeStatic); _core.shape.liveNodes.Remove(byNodeB); } if (newLiveNodeA != null && newLiveNodeB != null) { if (!_core.currentSplits.ContainsKey(newLiveNodeA.id)) { _core.currentSplits.Add(newLiveNodeA.id, new List <int>()); } _core.currentSplits[newLiveNodeA.id].Add(newLiveNodeB.id); if (!_core.currentSplits.ContainsKey(newLiveNodeB.id)) { _core.currentSplits.Add(newLiveNodeB.id, new List <int>()); } _core.currentSplits[newLiveNodeB.id].Add(newLiveNodeA.id); } }
public void AddEvent(IEvent newEvent) { OffsetShapeLog.AddLine("AddEvent", newEvent); if (newEvent == null) { return; } // OffsetShapeLog.AddLine(newEvent.percent); // OffsetShapeLog.AddLine(newEvent.percent > 1.0f - Mathf.Epsilon); // if (newEvent.percent > 0.99999f) return; //percent accuracy... OffsetShapeLog.AddLine("AddEvent"); OffsetShapeLog.AddLine("current number of events: " + _events.Count); bool lowerPercent = _percent > newEvent.percent; bool closePercent = Mathf.Abs(_percent - newEvent.percent) < percentAccuracy; OffsetShapeLog.AddLine(lowerPercent + " " + closePercent + " " + _percent + " " + newEvent.percent); if (!lowerPercent && !closePercent)//if this event is later than the currently logged events, ignore { _discardedEvents.Add(newEvent); _allEvents.Add(newEvent); _allPoints.Add(newEvent.point); return; } if (lowerPercent && !closePercent)//if this event is sooner then clear the list and log these earlier events { _discardedEvents.AddRange(_events); _events.Clear(); } Vector2 point = newEvent.point; IEvent pEvent = null; if (closePercent) { pEvent = CheckPoints(newEvent); } if (pEvent != null) { OffsetShapeLog.AddLine("Merge existing event"); pEvent.Log(); OffsetShapeLog.AddLine("Merge existing event"); OffsetShapeLog.AddLine(pEvent); OffsetShapeLog.AddLine("With new event"); OffsetShapeLog.AddLine(newEvent); OffsetShapeLog.AddLine("Merged Outcome"); IEvent mergedEvent = MergeEvent(pEvent, newEvent); OffsetShapeLog.AddLine(mergedEvent); OffsetShapeLog.AddLine("percent set ", _percent, mergedEvent.percent); _percent = mergedEvent.percent; _allPoints.Add(point); _allEvents.Add(mergedEvent); int discardedListCount = _discardedEvents.Count; for (int a = 0; a < discardedListCount; a++) { IEvent e = _discardedEvents[a]; if (mergedEvent.ContainsNodes(e.affectedNodes) && !_events.Contains(e)) { float sqrDist = Vector2.SqrMagnitude(e.point - mergedEvent.point); if (sqrDist < _sqrPointAccuracy) { _events.Add(e); mergedEvent.affectedNodes.AddRange(e.affectedNodes); a = 0;//restart to pick up other straglers } } } } else { OffsetShapeLog.AddLine("Add new event"); newEvent.Log(); _events.Add(newEvent); _allPoints.Add(point); _allEvents.Add(newEvent); OffsetShapeLog.AddLine("percent set ", _percent, newEvent.percent); _percent = Mathf.Min(_percent, newEvent.percent); } }
/// <summary> /// Merge the two specified events /// </summary> /// <param name="eventA"></param> /// <param name="eventB"></param> /// <returns></returns> private MergedEvent MergeEvent(IEvent eventA, IEvent eventB) { OffsetShapeLog.AddLine(_events.Count); eventA.Log(); eventB.Log(); if (eventA.GetType() == typeof(MergedEvent)) { if (eventA == eventB) { return((MergedEvent)eventA); } MergedEvent mergeEvent = (MergedEvent)eventA; mergeEvent.Merge(eventB); _events.Remove(eventB); if (!_events.Contains(eventA)) { _events.Add(eventA); } OffsetShapeLog.AddLine("Event B merged into A"); return(mergeEvent); } if (eventB.GetType() == typeof(MergedEvent)) { if (eventA == eventB) { return((MergedEvent)eventB); } MergedEvent mergeEvent = (MergedEvent)eventB; mergeEvent.Merge(eventA); _events.Remove(eventA); if (!_events.Contains(eventB)) { _events.Add(eventB); } OffsetShapeLog.AddLine("Event A merged into B"); return(mergeEvent); } OffsetShapeLog.AddLine(_events.Count); //create the merge event and merge into it the two events MergedEvent mergedEvent = new MergedEvent(); OffsetShapeLog.Add("merge percent ", mergedEvent.percent); mergedEvent.Merge(eventA); OffsetShapeLog.Add("merge percent ", mergedEvent.percent); mergedEvent.Merge(eventB); OffsetShapeLog.Add("merge percent ", mergedEvent.percent); eventA.Log(); eventB.Log(); mergedEvent.Log(); _events.Remove(eventA); _events.Remove(eventB); if (_allEvents.Contains(eventA)) { _allPoints.RemoveAt(_allEvents.IndexOf(eventA)); } _allEvents.Remove(eventA); if (_allEvents.Contains(eventB)) { _allPoints.RemoveAt(_allEvents.IndexOf(eventB)); } _allEvents.Remove(eventB); OffsetShapeLog.AddLine("Current Events"); foreach (IEvent evt in _events) { evt.Log(); } OffsetShapeLog.AddLine(_events.Count); if (!_events.Contains(mergedEvent)) { _events.Add(mergedEvent); } OffsetShapeLog.AddLine(_events.Count); return(mergedEvent); }
private void CollapseNodes(List <Node> nodes, Vector2 toPoint, float height) { Shape _shape = _core.shape; int nodeCount = nodes.Count; float minHeight = nodes[0].height; float maxHeight = nodes[0].height; for (int n = 1; n < nodeCount; n++) { minHeight = Mathf.Min(minHeight, nodes[n].height); maxHeight = Mathf.Min(maxHeight, nodes[n].height); } Node survivor = nodes[0]; survivor.position = toPoint; survivor.height = maxHeight; int liveEdgeCount = _shape.liveEdges.Count; for (int e = 0; e < liveEdgeCount; e++) { Edge edge = _shape.liveEdges[e]; if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB)) { continue; } edge.UpdateValues(); if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB)) { OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, _core.pointAccuracy); OffsetShapeLog.AddLine("Remove edge ", edge.ToString()); _shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero liveEdgeCount--; e--; continue; // if (!nodes.Contains(edge.nodeA)) // nodes.Add(edge.nodeA); // if (!nodes.Contains(edge.nodeB)) // nodes.Add(edge.nodeB); } //else affected edge if (nodes.Contains(edge.nodeA)) { edge.ReplaceNode(edge.nodeA, survivor); } if (nodes.Contains(edge.nodeB)) { edge.ReplaceNode(edge.nodeB, survivor); } } // OffsetShapeLog.AddLine("Collapse Nodes:"); // foreach (Node node in nodes) // OffsetShapeLog.Add(node.id + " "); // OffsetShapeLog.AddLine("to point: ", toPoint); // // Node newStaticNode = new Node(toPoint, height);//new static node to mark point of collapse // // _shape.AddStaticNode(newStaticNode);//add static node to node array // // OffsetShapeLog.AddLine("new static node added ", newStaticNode.id); // // // Node newLiveNode = new Node(toPoint, height);//new live node to continue shape forming // // for (int n = 0; n < nodeCount; n++) // { // nodes[n].position = toPoint; // nodes[n].height = maxHeight; // } // // Edge collapsedEdge = null; // for (int e = 0; e < liveEdgeCount; e++) // { // Edge edge = _shape.liveEdges[e]; // if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB)) continue; // edge.UpdateValues(); // if (edge.length < _core.pointAccuracy)//when the edge reaches 0 length it has flipped and should be collapsed // { // OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, _core.pointAccuracy); // // _shape.mesh.CollapseEdge(edge, newLiveNode, newStaticNode); // OffsetShapeLog.AddLine("Remove edge ", edge.ToString()); // collapsedEdge = edge; // _shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero // liveEdgeCount--; // e--; // if (!nodes.Contains(edge.nodeA)) // nodes.Add(edge.nodeA); // if (!nodes.Contains(edge.nodeB)) // nodes.Add(edge.nodeB); // } // } // OffsetShapeLog.AddLine("find live node edges"); // for (int e = 0; e < liveEdgeCount; e++) // { // Edge edge = _shape.liveEdges[e]; // if (!edge.Contains(nodes)) continue; // if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB)) // { // OffsetShapeLog.AddLine("Remove collapsed edge ", edge.ToString()); // _shape.liveEdges.Remove(edge);//remove collapsed edge - likely from parallel // liveEdgeCount--; // e--; // continue; // } // if (nodes.Contains(edge.nodeA) || newLiveNode == edge.nodeA) // { // OffsetShapeLog.AddLine("replace node a"); // edge.ReplaceNode(edge.nodeA, newLiveNode);//replace old live node reference to new one // liveEdges.Add(edge); // continue; // } // if (nodes.Contains(edge.nodeB) || newLiveNode == edge.nodeB) // { // OffsetShapeLog.AddLine("replace node b"); // edge.ReplaceNode(edge.nodeB, newLiveNode);//replace old live node reference to new one // liveEdges.Add(edge); // } // } for (int n = 0; n < nodeCount; n++) { Node node = nodes[n]; if (node == survivor) { continue; } // Utils.RetireFormingEdge(_shape, node, newStaticNode); _shape.liveNodes.Remove(node); } Utils.CheckParrallel(_shape); // OffsetShapeLog.AddLine("Live edges: ", liveEdges.Count); // if (liveEdges.Count > 0)//deal with left live edges after the collapse // { // _shape.AddLiveNode(newLiveNode);//new live node from collapse // Edge edgeA = null, edgeB = null; // liveEdgeCount = _shape.liveEdges.Count; // for (int e = 0; e < liveEdgeCount; e++)//find the two edges left from the collapse // { // Edge edge = _shape.liveEdges[e]; // if (!_shape.liveEdges.Contains(edge)) continue; // if (edge.nodeA == newLiveNode) edgeA = edge; // if (edge.nodeB == newLiveNode) edgeB = edge; // } // // if (edgeA != null && edgeB != null)//if there is a live edge // { // Node x = edgeA.GetOtherNode(newLiveNode); // Node y = edgeB.GetOtherNode(newLiveNode); // Utils.CalculateNodeDirAng(newLiveNode, x, y);//recalculate node angle // Utils.NewFormingEdge(_shape, newStaticNode, newLiveNode);//add new forming edge // } // else // { // OffsetShapeLog.AddLine("New live node has not been calculated ", newLiveNode.id); // } // } // foreach (Node node in nodes) // _data.mesh.ReplaceNode(node, newStaticNode); }
private IEvent CheckPoints(IEvent evnt) { Vector2 point = evnt.point; int pointCount = _allPoints.Count; if (pointCount == 0) { return(null); } //find if this event has nodes that are affected by another event and elect such an event for merging int eventCount = _events.Count; for (int e = 0; e < eventCount; e++) { IEvent aevnt = _events[e]; if (aevnt == evnt) { continue; } if (aevnt.ContainsNodes(evnt.affectedNodes)) { float percentDiff = Mathf.Abs(evnt.percent - aevnt.percent); if (percentDiff > percentAccuracy) { continue; } float sqrMag = Vector2.SqrMagnitude(evnt.point - aevnt.point); OffsetShapeLog.AddLine("SQR MAG ", sqrMag, _sqrPointAccuracy); if (sqrMag < _sqrPointAccuracy) { return(aevnt); } } } //find any events that are close to this one physically. //this could be any logged event //as the subject event exists in the main _event list float lowestMag = Mathf.Infinity; int lowestMagIndex = -1; for (int p = 0; p < pointCount; p++) { float sqrMag = Vector2.SqrMagnitude(point - _allPoints[p]); if (sqrMag < lowestMag) { lowestMag = sqrMag; lowestMagIndex = p; } } if (lowestMagIndex != -1 && lowestMag < _sqrPointAccuracy) { float percentDiff = Mathf.Abs(evnt.percent - _allEvents[lowestMagIndex].percent); if (percentDiff <= percentAccuracy) { return(_allEvents[lowestMagIndex]); } } return(null); }
public void SplitEdge(SplitEvent e) { OffsetShapeLog.AddLine("Split event"); OffsetShapeLog.AddLine("by node ", e.node.id); OffsetShapeLog.AddLine(e.edge.ToString()); //nodes Node nodeStatic = new Node(e.point, e.height); Node newLiveNodeA = new Node(e.point, e.height); Node newLiveNodeB = new Node(e.point, e.height); e.newLiveNodeA = newLiveNodeA; e.newLiveNodeB = newLiveNodeB; e.newStaticNode = nodeStatic; Node nodeOldA = e.edge.nodeA; Node nodeOldB = e.edge.nodeB; Edge byEdgeA = e.nodeEdgeA; Edge byEdgeB = e.nodeEdgeB; if (byEdgeA == null || byEdgeB == null) { //TODO work out what to really do here. return; } Node byNodeA = byEdgeA.GetOtherNode(e.node); Node byNodeB = byEdgeB.GetOtherNode(e.node); OffsetShapeLog.AddLine("by node a", byNodeA.id); OffsetShapeLog.AddLine("by node b", byNodeB.id); if (byNodeA == null || byNodeB == null) { return; } //calculate new node directions Utils.CalculateNodeDirAng(newLiveNodeA, byNodeA, nodeOldA); Utils.CalculateNodeDirAng(newLiveNodeB, nodeOldB, byNodeB); _shape.AddLiveNode(newLiveNodeA); _shape.AddLiveNode(newLiveNodeB); _shape.AddStaticNode(nodeStatic); _shape.liveNodes.Remove(e.node); //discard the old edge OffsetShapeLog.AddLine("Discard old edge ", e.edge.ToString()); _shape.liveEdges.Remove(e.edge);// byEdgeA.ReplaceNode(e.node, newLiveNodeA); byEdgeB.ReplaceNode(e.node, newLiveNodeB); //create the two new edges from the split Edge newEdgeA = new Edge(nodeOldA, newLiveNodeA); _shape.liveEdges.Add(newEdgeA); e.newLiveEdgeA = newEdgeA; Edge newEdgeB = new Edge(newLiveNodeB, nodeOldB); _shape.liveEdges.Add(newEdgeB); e.newLiveEdgeB = newEdgeB; //forming edges Utils.RetireFormingEdge(_shape, e.node, nodeStatic); Edge formingEdgeA = Utils.NewFormingEdge(_shape, nodeStatic, newLiveNodeA); Edge formingEdgeB = Utils.NewFormingEdge(_shape, nodeStatic, newLiveNodeB); // int aIndex = data.liveNodes.IndexOf(nodeLiveA); // int bIndex = data.liveNodes.IndexOf(nodeLiveB); newLiveNodeA.MoveForward(0.1f, 1); newLiveNodeB.MoveForward(0.1f, 1); if (!currentSplits.ContainsKey(newLiveNodeA.id)) { currentSplits.Add(newLiveNodeA.id, new List <int>()); } currentSplits[newLiveNodeA.id].Add(newLiveNodeB.id); if (!currentSplits.ContainsKey(newLiveNodeB.id)) { currentSplits.Add(newLiveNodeB.id, new List <int>()); } currentSplits[newLiveNodeB.id].Add(newLiveNodeA.id); // _shape.mesh.SplitEdge(e); OffsetShapeLog.AddLine("new live nodes"); OffsetShapeLog.AddLine(newLiveNodeA.id); OffsetShapeLog.AddLine(newLiveNodeB.id); OffsetShapeLog.AddLine("new edges - old edge - forming edge a"); OffsetShapeLog.AddLine(newEdgeA.ToString()); OffsetShapeLog.AddLine(byEdgeA.ToString()); OffsetShapeLog.AddLine(formingEdgeA.ToString()); OffsetShapeLog.AddLine("new edges - old edge - forming edge b"); OffsetShapeLog.AddLine(byEdgeB.ToString()); OffsetShapeLog.AddLine(newEdgeB.ToString()); OffsetShapeLog.AddLine(formingEdgeB.ToString()); Utils.CheckParrallel(_shape); }
public void Draw() { OffsetShapeLog.enabled = true; OffsetShapeLog.DrawShapeNodes(_core.shape); }
public void Init(Vector2[] points, bool[] gables = null) { OffsetShapeLog.AddLine("Init"); if (ShapeIntersection(points)) { _error = true; OffsetShapeLog.AddLine("Shape intersection"); if (OnErrorEvent != null) { OnErrorEvent("Provided shape interescts with itself."); } return; } _shape = new Shape(points); int pointCount = points.Length; if (pointCount == 0) { Debug.LogError("no points sent!"); return; } //bounds used to ensure no crazy values created _bounds = new Rect(points[0].x, points[0].y, 0, 0); //Initialise the data points for (int p = 0; p < pointCount; p++) { Vector2 point = points[p]; if (point.x < _bounds.xMin) { _bounds.xMin = point.x; } if (point.x > _bounds.xMax) { _bounds.xMax = point.x; } if (point.y < _bounds.yMin) { _bounds.yMin = point.y; } if (point.y > _bounds.yMax) { _bounds.yMax = point.y; } Node outer = new Node(points[p], 0);//create outer node points that outline the shape outer.startNode = true; _shape.AddStaticNode(outer); Node live = new Node(points[p], 0);//create live inner nodes that will sweep inwards _shape.AddLiveNode(live); Utils.NewFormingEdge(_shape, outer, live); } // float boundsMargin = BOUNDS_MARGIN; _bounds.xMin -= BOUNDS_MARGIN; _bounds.xMax += BOUNDS_MARGIN; _bounds.yMin -= BOUNDS_MARGIN; _bounds.yMax += BOUNDS_MARGIN; float smallestLength = Mathf.Infinity; //create edges from previous points //calculate node directions for (int p = 0; p < pointCount; p++) { int indexA = p; int indexX = (p + 1) % pointCount; //next index int indexY = (p - 1 + pointCount) % pointCount; //previous Node a = _shape.StaticNode(indexA); Node x = _shape.StaticNode(indexX); Node y = _shape.StaticNode(indexY); Node la = _shape.liveNodes[indexA]; Node lb = _shape.liveNodes[indexX]; Edge outerEdge = new Edge(a, x);//outer edge - will not move _shape.baseEdges.Add(outerEdge); _shape.edges.Add(outerEdge); if (outerEdge.sqrMagnitude < smallestLength) { smallestLength = outerEdge.sqrMagnitude; } // if (gables != null) // { // bool leftIsGabled = gables[indexY]; // bool rightIsGabled = gables[indexA]; // // if (!leftIsGabled && !rightIsGabled) // { // Utils.CalculateNodeDirAng(la, x, y);//assign the direction of the node for shrinkage // Edge liveEdge = new Edge(la, lb);//create the live edge that will be sweeping inwards // _shape.liveEdges.Add(liveEdge); // } // else if (leftIsGabled && !rightIsGabled) // { // Utils.CalculateNodeDirAng(la, x, y);//assign the direction of the node for shrinkage // Node l = _shape.liveNodes[indexX]; // Edge liveEdge = new Edge(la, lb);//create the live edge that will be sweeping inwards // _shape.liveEdges.Add(liveEdge); // } // } // else // { Utils.CalculateNodeDirAng(la, x, y); //assign the direction of the node for shrinkage Edge liveEdge = new Edge(la, lb); //create the live edge that will be sweeping inwards _shape.liveEdges.Add(liveEdge); // } // a.startTangent = ((a.position - y.position).normalized + (x.position - a.position).normalized).normalized; } _shape.shrinkLength = Mathf.Sqrt(smallestLength); OffsetShapeLog.AddLine("shrink length " + _shape.shrinkLength); _complete = false; _error = false; _init = true; }
/// <summary> /// Remove any live edges that are now parallel and will no longer serve a purpose /// </summary> /// <param name="data"></param> public static void CheckParrallel(Shape data) { int liveEdgeCount = data.liveEdges.Count; for (int a = 0; a < liveEdgeCount; a++) { for (int b = 0; b < liveEdgeCount; b++) { if (a == b) { continue; } Edge edgeA = data.liveEdges[a]; Edge edgeB = data.liveEdges[b]; Vector2 dirA = edgeA.direction; Vector2 dirB = edgeB.direction; if (ParallelLines(dirA, dirB)) { Node nodeAA = edgeA.nodeA; Node nodeAB = edgeA.nodeB; Node nodeBA = edgeB.nodeA; Node nodeBB = edgeB.nodeB; bool connectedA = nodeAA == nodeBA || nodeAA == nodeBB; bool connectedB = nodeAB == nodeBA || nodeAB == nodeBB; if (connectedA && connectedB)//connected parallel lines serve no purpose { OffsetShapeLog.AddLine("Parallel Lines!"); OffsetShapeLog.AddLine(edgeA.ToString()); OffsetShapeLog.AddLine(edgeB.ToString()); OffsetShapeLog.DrawEdge(edgeA, new Color(1, 1, 0, 0.8f)); OffsetShapeLog.DrawEdge(edgeB, new Color(1, 0, 1, 0.8f)); OffsetShapeLog.LabelNode(nodeAA); OffsetShapeLog.LabelNode(nodeAB); OffsetShapeLog.LabelNode(nodeBA); OffsetShapeLog.LabelNode(nodeBB); Node newStaticNodeA = new Node(nodeAA.position, nodeAA.height); Node newStaticNodeB = new Node(nodeAB.position, nodeAB.height); data.liveEdges.Remove(edgeA); data.liveEdges.Remove(edgeB); data.liveNodes.Remove(nodeAA); data.liveNodes.Remove(nodeAB); newStaticNodeA = data.AddStaticNode(newStaticNodeA); newStaticNodeB = data.AddStaticNode(newStaticNodeB); data.edges.Add(edgeA); data.edges.Add(edgeB); RetireFormingEdge(data, nodeAA, newStaticNodeA); RetireFormingEdge(data, nodeAB, newStaticNodeB); NewFormingEdge(data, newStaticNodeA, nodeAA); NewFormingEdge(data, newStaticNodeB, nodeAB); CalculateNodeDirAng(data, nodeAA); CalculateNodeDirAng(data, nodeAB); a = 0; b = 0; liveEdgeCount = data.liveEdges.Count; } // else // { // OffsetShapeLog.AddLine("Parallel Lines but!"); // OffsetShapeLog.AddLine(edgeA.ToString()); // OffsetShapeLog.AddLine(edgeB.ToString()); // } } } } }
public void DebugDrawMovement(Color col) { OffsetShapeLog.DrawLine(previousPosition, position, col); OffsetShapeLog.DrawLabel(position, "Node " + id); }