//returns a list of the segments of the path and then the segment on the other shape which ended the path, also ends when it reaches the start public Tuple <List <CSGsegment>, CSGsegment> ridePathUntilIntersection(CSGshape shapeToIntersect, List <CSGsegment> externalSegments, bool isMovingForward, CSGsegment first, bool isStart = false) { var retr = new Tuple <List <CSGsegment>, CSGsegment>(); var curr = this; var retrList = new List <CSGsegment>(); retr.first = retrList; retr.second = null; while (curr != first || isStart) { //Debug.Log(curr.Letter); isStart = false; retrList.Add(curr); if (externalSegments.Contains(curr))//slow linear search { externalSegments.Remove(curr); } var intersection = curr.getClosestIntersectingSegment(shapeToIntersect, isMovingForward); if (intersection == null) { curr = curr.next(isMovingForward); } else { retr.second = intersection; return(retr); } } return(retr); }
//returns null for no intersection public CSGsegment getClosestIntersectingSegment(CSGshape shape, bool isMovingForward) { var candidates = new List <CSGsegment>(); foreach (var i in shape.segments) { if (i.doesIntersect(this)) { candidates.Add(i); } } float currBestDist = float.PositiveInfinity; CSGsegment currBest = null; foreach (var i in candidates) { var point = i.intersectionPoint(this); var dist = (this.getPoint(isMovingForward) - point).magnitude; if (dist < currBestDist) { currBestDist = dist; currBest = i; } } return(currBest); }
Vector2[] collisionHullToVector2(CSGshape h) { var foo = new Vector2[h.segments.Count]; int c = 0; foreach (var i in h.segments) { foo[c] = i.start; c++; } return(foo); }
//external segments must ALWAYS be in order private List <CSGsegment> getExternalSegments(CSGshape other) { var retr = new List <CSGsegment>(); foreach (var i in this.segments) { if (!other.isPointInside(i.start)) { retr.Add(i); } } return(retr); }
// Update is called once per frame void Update() { foreach (var i in segments) { Debug.DrawLine(i.start, i.end); } if (Input.GetMouseButtonDown(0)) { var item = Instantiate(redX); objs.Add(item); Vector2 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); item.transform.position = pos; baseShape.Add(pos); } if (Input.GetMouseButtonDown(1)) { var item = Instantiate(blueX); objs.Add(item); Vector2 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); item.transform.position = pos; notShape.Add(pos); } if (Input.GetKeyDown(KeyCode.Space)) { bool none; var retr = CSGshape.not(new CSGshape(baseShape), new CSGshape(notShape), false, out none); foreach (var i in objs) { Destroy(i); } baseShape.Clear(); notShape.Clear(); segments.Clear(); foreach (var j in retr) { foreach (var i in j.externalHull.segments) { var item = Instantiate(redX); objs.Add(item); item.transform.position = i.start; baseShape.Add(i.start); segments.Add(i); //Debug.DrawLine(i.start,i.end); /*item = Instantiate(redX); * item.transform.position = i.end; * baseShape.Add(i.end);*/ } } } }
private void ShapeOp(CSGshape other, bool isNot) { List <CollisionHull> hulls = new List <CollisionHull>(); bool isShapeUsedUp = false; foreach (var coll in colliders) { if (!isShapeUsedUp || isNot == false) { var result = CSGshape.not(coll.externalHull, other, isNot, out isShapeUsedUp, coll.holes); hulls.AddRange(result); } } if (!isShapeUsedUp && !isNot) { var foo = new CollisionHull(); foo.externalHull = other; hulls.Add(foo); } colliders = hulls; }
// Update is called once per frame void Update() { Draw(); if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1)) { try { doNotRender.Clear(); Vector2 center = Camera.main.ScreenToWorldPoint(Input.mousePosition); List <Vector2[]> newShapes = new List <Vector2[]>(); List <List <CSGshape> > shapeHoles = new List <List <CSGshape> >(); List <Vector2> square = getCircle(center, 1, 20); //List<CollisionHull> shapesSoFar = new List<CollisionHull>();//#garbagelife //Debug.Log("shapesofarleng:" + shapesSoFar.Count); bool isShapesUsedUp = false; //prevents applying positive and to multiple for (int path = 0; path < baseCollider.pathCount; path++) { if (!isShapesUsedUp || Input.GetMouseButtonDown(0)) { var b = new CSGshape(new List <Vector2>(baseCollider.GetPath(path))); //List<Vector2> square = getCircle();//getSquare(center); { var retr = CSGshape.not(b, new CSGshape(square), Input.GetMouseButtonDown(0), out isShapesUsedUp, null); //retr = CSGshape.prune(shapesSoFar,retr); //shapesSoFar.AddRange(retr); foreach (var returnVal in retr) { newShapes.Add(collisionHullToVector2(returnVal.externalHull)); doNotRender.Add(false); if (returnVal.holes != null) { newShapes.AddRange(returnVal.holes.Select(a => collisionHullToVector2(a))); for (var i = 0; i < returnVal.holes.Count; i++) { doNotRender.Add(true); } } //shapeHoles.Add(returnVal.holes); } } } else { newShapes.Add(baseCollider.GetPath(path)); doNotRender.Add(false); } } if (!isShapesUsedUp && Input.GetMouseButtonDown(1)) { newShapes.Add(square.ToArray()); doNotRender.Add(false); } if (newShapes.Count != doNotRender.Count) { throw new Exception("F**K"); } baseCollider.pathCount = newShapes.Count(); int counter = 0; foreach (var i in newShapes) { baseCollider.SetPath(counter, i); counter++; } } catch (NotImplementedException e)//(Exception e) { //Debug.Log("EXCEPTION:" + e.ToString()); } } }
//collision hull.hull or whatever is null if nothing is left public static List <CollisionHull> not(CSGshape shape, CSGshape other, bool isNot, out bool usedFlag, List <CSGshape> holes = null) { //start with a point on me thats not in the other shape //List<CSGshape> retr = new List<CSGshape>(); List <CollisionHull> hulls = new List <CollisionHull>(); List <CSGsegment> externalSegments = shape.getExternalSegments(other); usedFlag = !isNot; if (other.segments.TrueForAll(i => !shape.doesIntersect(i)) && !isNot) { var foo = new CollisionHull(); foo.externalHull = shape; foo.holes = holes; /*var bar = new CollisionHull(); * bar.externalHull = other;*/ hulls.Add(foo); //hulls.Add(bar); usedFlag = false; return(hulls); } else if (externalSegments.Count == 0) //other completely surrounds this { if (isNot) { return(hulls); } else { hulls.Add(new CollisionHull()); hulls[0].externalHull = other; return(hulls); } } else if (externalSegments.Count == shape.segments.Count && other.segments.TrueForAll(a => shape.isPointInside(a.start))) //this completely surrounds other { if (isNot) { var foo = new List <CSGshape>(); foo.Add(other); if (holes != null) { foo.AddRange(holes); } foo = andAll(foo); var hull = new CollisionHull(); hull.externalHull = shape; hull.holes.Add(other); hulls.Add(hull); } else { hulls.Add(new CollisionHull()); hulls[0].externalHull = shape; } return(hulls); //throw new NotImplementedException(); /*float closestDist = float.PositiveInfinity; * CSGsegment closestItem = null; * CSGsegment closestInnerItem = null; * if (!other.isClockwise()) * { * other.antiRotate(); * } * foreach (var i in shape.segments) * { * foreach (var j in other.segments) * { * var dist = (i.end - j.start).magnitude; * if (dist < closestDist) * { * closestItem = i; * closestInnerItem = j; * closestDist = dist; * } * } * } * var enter = new CSGsegment(closestItem.end, closestInnerItem.start); * var exit = new CSGsegment(closestInnerItem.start, closestItem.end); * var oldnext = closestItem.endSegment; * var oldinnernext = closestInnerItem.startSegment; * oldnext.startSegment = exit; * closestItem.endSegment = enter; * enter.endSegment = closestInnerItem; * exit.endSegment = oldnext; * oldinnernext.endSegment = exit; * enter.startSegment = closestItem; * closestInnerItem.startSegment = enter; * exit.startSegment = oldinnernext; * * CSGsegment curr = enter; * List<Vector2> newPoints = new List<Vector2>(); * do * { * newPoints.Add(curr.getPoint(true)); * curr = curr.next(true); * } while (curr!=enter); * retr.Add(new CSGshape(newPoints)); * return retr;*/ } else { while (externalSegments.Count > 0) { List <Vector2> newPoints = new List <Vector2>(); bool isMovingForward = true; var first = externalSegments[0];//better to remove at start or end? look this up var curr = first; var isStart = true; externalSegments.RemoveAt(0); int counter = 0; while (true) { if (counter > 100) //remove this? { throw new Exception("Linerider exceeded 100 steps"); //break; } counter++; var partialPath = curr.ridePathUntilIntersection(other, externalSegments, isMovingForward, first, isStart); foreach (var i in partialPath.first) { newPoints.Add(i.getPoint(isMovingForward)); } if (partialPath.second == null) { break; } var intersectionPoint = partialPath.first[partialPath.first.Count - 1].intersectionPoint(partialPath.second); isMovingForward = shape.getDirection(partialPath.second, isNot, intersectionPoint); //toggle this to add instead of subtract isStart = false; //now we must enter this shape, so test the two points var exitPoint = partialPath.second.getPoint(!isMovingForward); //!isMovingForward so we get end instead of start var entrancePoint = intersectionPoint + smallDelta * (exitPoint - intersectionPoint).normalized; if (isMovingForward) { curr = new CSGsegment(entrancePoint, exitPoint); } else { curr = new CSGsegment(exitPoint, entrancePoint); } curr.startSegment = partialPath.second.startSegment; curr.endSegment = partialPath.second.endSegment; ////////////////////////now inside this partialPath = curr.ridePathUntilIntersection(shape, externalSegments, isMovingForward, null); //null because it can't end inside foreach (var i in partialPath.first) { newPoints.Add(i.getPoint(isMovingForward)); } intersectionPoint = partialPath.first[partialPath.first.Count - 1].intersectionPoint(partialPath.second); isMovingForward = other.getDirection(partialPath.second, false, intersectionPoint); //now we gotta leave this shape exitPoint = partialPath.second.getPoint(!isMovingForward); //!isMovingForward so we get end instead of start entrancePoint = intersectionPoint + smallDelta * (exitPoint - intersectionPoint).normalized; if (isMovingForward) { curr = new CSGsegment(entrancePoint, exitPoint); } else { curr = new CSGsegment(exitPoint, entrancePoint); } curr.startSegment = partialPath.second.startSegment; curr.endSegment = partialPath.second.endSegment; } var foo = new CollisionHull(); var newShape = new CSGshape(newPoints); foo.externalHull = newShape; hulls.Add(foo); } return(hulls); } }
public void AddShape(CSGshape other) { ShapeOp(other, false); }
public void RemoveShape(CSGshape other) { ShapeOp(other, true); }