public void RemoveLastControlPoint() { int IdxToRemove = CtrlPts.Count - 2; BezCtrlPt CPToRemove = CtrlPts[IdxToRemove]; BezCtrlPt PrevCP = CtrlPts[IdxToRemove - 1]; //This isnt quite right but it'll do //I hope it doesn't cause a memory leak //DO we have to remove the Section and Segments and the gameobjects? int PrevCtrlPtId = -1; int NxtCtrlPtId = -1; try { PrevCtrlPtId = CPToRemove.CtrlPtId - 1; NxtCtrlPtId = CPToRemove.CtrlPtId + 1; } catch (Exception e) { Debug.Log(e.Message); } //not needed ? //if(Road.Instance.IsCircular) Path.RemoveRange(Path.Count - 20, 20); Path.RemoveRange(PrevCP.SegStartIdx, PrevCP.SegCount); CtrlPts.Remove(CPToRemove); PrevCP.SegCount = 0; PrevCP.Select(); SetCtrlPtIds(); SetSegStartIds(); DrawLine(); }
public BezierLine Decode() { BezierLine Bez = BezierLine.Instance; Bez.LineId = 0; Bez.Path.Clear(); Bez.CtrlPts.Clear(); if (Path != null) //in case we are loading a blank track { foreach (BezCtrlPtSerial BCPS in CtrlPts) { BezCtrlPt BCP = BCPS.Decode(); Bez.CtrlPts.Add(BCP); } foreach (Vector3Serial PS in Path) { Bez.Path.Add(PS.V3); } } else { Bez.Init(); } //blank track - put in the 2 dummies return(Bez); }
public void Encode(BezCtrlPt CtrlPt) { CtrlPtId = CtrlPt.CtrlPtId; LineId = CtrlPt.Line.LineId; Pos = new Vector3Serial(CtrlPt.Pos); BankAngle = CtrlPt.BankAngle; SegStartIdx = CtrlPt.SegStartIdx; SegCount = CtrlPt.SegCount; }
public void TakePlanViewScreenshot() { UnityEngine.Object o = Resources.Load("prefabs/ScreenshotCam"); goPlanCam = (GameObject)GameObject.Instantiate(o); Camera PlanCam = goPlanCam.GetComponent <Camera>(); PlanCam.orthographic = true; //find the major axis (two Ctrlpts c1 and c2 furthest apart) float dist = 0; BezCtrlPt c1 = new BezCtrlPt(Bez, Vector3.zero), c2 = new BezCtrlPt(Bez, Vector3.zero); foreach (BezCtrlPt p1 in Bez.CtrlPts) { foreach (BezCtrlPt p2 in Bez.CtrlPts) { float thisdist = Mathf.Pow(p1.Pos.x - p2.Pos.x, 2) + Mathf.Pow(p1.Pos.z - p2.Pos.z, 2); if (thisdist > dist) { dist = thisdist; c1 = p1; c2 = p2; } } } Vector3 c1Pos = new Vector3(c1.Pos.x, 500, c1.Pos.z); Vector3 c2Pos = new Vector3(c2.Pos.x, 500, c2.Pos.z); PlanCam.transform.position = (c1Pos + c2Pos) / 2; PlanCam.transform.LookAt(c1Pos); PlanCam.transform.Rotate(Vector3.up, 90); float _distFwd = 0, _distBwd = 0; foreach (BezCtrlPt p1 in Bez.CtrlPts) { Vector3 RelPos = PlanCam.transform.InverseTransformPoint(new Vector3(p1.Pos.x, 500, p1.Pos.z)); if (RelPos.z > _distFwd) { _distFwd = RelPos.z; } if (RelPos.z < _distBwd) { _distBwd = RelPos.z; } } PlanCam.transform.Translate(0, 0, (_distFwd + _distBwd) / 2, Space.Self); PlanCam.transform.Rotate(Vector3.right, 90, Space.Self); PlanCam.orthographicSize = Mathf.Pow(dist, 0.5f) * (float)Screen.height / (float)Screen.width / 2 * 1.1f; //_canvas.SetActive(false); goPlanCam.GetComponent <ScreenshotCam>().goCanvas = _canvas; goPlanCam.GetComponent <ScreenshotCam>().Grab = true; Bez.SetWidth(10); Rd.goRoad.SetActive(false); foreach (GameObject t in GameObject.FindGameObjectsWithTag("Terrain")) { t.GetComponent <Terrain>().enabled = false; } //Debug.Break(); }
/// <summary> /// Divides the Current Section in half /// </summary> public void InsertSection() { int CurrIdx = BezCtrlPt.Current.CtrlPtId; int newSectnIdx = CurrIdx + 1; iRoadSectn CurrSectn = Rd.Sectns[CurrIdx]; int CurrSectnSegStartId = BezCtrlPt.Current.SegStartIdx; int CurrSectnSegCount = BezCtrlPt.Current.SegCount; int CurrSectnNewSegCount = CurrSectnSegCount / 2; int NewSectnSegStartId = CurrSectnSegStartId + CurrSectnNewSegCount; int NewSectnSegCount = CurrSectnSegCount - CurrSectnNewSegCount; int NxtSectnStartId = Bez.CtrlPts[newSectnIdx].SegStartIdx; //Insert Bezier Control Point Vector3 NewPos = Bez.Path[NewSectnSegStartId]; BezCtrlPt NewCtrlPt = new BezCtrlPt(Bez, NewPos); NewCtrlPt.BankAngle = BezCtrlPt.Current.BankAngle; Bez.CtrlPts.Insert(newSectnIdx, NewCtrlPt); Bez.SetCtrlPtIds(); //We dont have to move the path points from the old CtrlPt to the new one BezCtrlPt.Current.SegCount = CurrSectnNewSegCount; NewCtrlPt.SegCount = NewSectnSegCount; Bez.SetSegStartIds(); NewCtrlPt.CreateRoadMarker(); Bez.Interp(newSectnIdx - 1); Bez.Interp(newSectnIdx); Bez.Interp(newSectnIdx + 1); Bez.DrawLine(); Bez.AlignAllRoadMarkers(); //Insert Section iRoadSectn NewSectn = new RoadSectn(); NewSectn.Chargeable = false; NewSectn.Idx = newSectnIdx; NewSectn.LFenceType = CurrSectn.LFenceType; NewSectn.RFenceType = CurrSectn.RFenceType; NewSectn.SetMaterial(CurrSectn.Segments[0].roadMaterial); NewSectn.CreateGameObjects(); NewSectn.name = "RoadSection" + (newSectnIdx); NewSectn.goSectn.name = "RoadSection" + (newSectnIdx); Road.Instance.Sectns.Insert(newSectnIdx, NewSectn); // Section1 comes after RoadMarker1 Rd.OrganiseObjectsUsingBezierCtrlPtsAndPath(); /* * XSecCalculator.CalcXSecs(newSectnIdx-1, RoadWidth); * XSecCalculator.CalcXSecs(newSectnIdx, RoadWidth); * XSecCalculator.CalcXSecs(newSectnIdx+1, RoadWidth); * * CurrSectn.CalcFenceVerts(); * NewSectn.CalcFenceVerts(); * BuildQueue.Enqueue(newSectnIdx-1); * BuildQueue.Enqueue(newSectnIdx); */ }
public BezCtrlPt Decode() { BezCtrlPt BCP = new BezCtrlPt(BezierLine.Instance, Pos.V3); //!!!!!!!Bugbugbug bug -fixed I think BCP.BankAngle = BankAngle; BCP.CtrlPtId = CtrlPtId; BCP.SegStartIdx = SegStartIdx; BCP.SegCount = SegCount; return(BCP); }
/// <summary> /// This gets called on a new game. It doesn't get called when you load a saved game /// </summary> public void Init() { Path.Clear(); CtrlPts.Clear(); //Add 2 control points - this is the minimum to get it working for (int i = 0; i < 2; i++) { BezCtrlPt BCP = new BezCtrlPt(this, Vector3.zero); CtrlPts.Add(BCP); } BezCtrlPt.Current = CtrlPts[0]; SetCtrlPtIds(); }
public void Select() { if (goRdMkr == null) { return; } RoadMarker RM = goRdMkr.gameObject.GetComponent <RoadMarker>(); if (!RM.Selected) { RM.Select(); } Current = this; RM = null; }
public void AddControlPoint(Vector3 Pt, float BankAngle, int segCount) { BezCtrlPt BCP = new BezCtrlPt(this, Pt); BCP.BankAngle = BankAngle; CtrlPts[CtrlPts.Count - 2].SegCount = segCount; //set the SegCount of the previous CtrlPt CtrlPts.Insert(CtrlPts.Count - 1, BCP); SetCtrlPtIds(); SetSegStartIds(); CtrlPts[CtrlPts.Count - 1].Pos = Pt; //cos the last control point is a dummy and is in the same place if (BCP.CtrlPtId == 1) { CtrlPts[0].Pos = Pt; //cos the first one is a dummy too } if (BCP.CtrlPtId > 1) { AddPathPoints(segCount); } }
/// <summary> /// Inserts a control point just after the selected one /// </summary> public void InsertControlPoint(int idx) { Vector3 InsertPos = Path[(idx - 1) * 20 + 10]; BezCtrlPt InsertedCP = new BezCtrlPt(this, InsertPos); InsertPathPoints(idx); //CtrlPt 3 is Path 40 CtrlPts.Insert(idx + 1, InsertedCP); //this adds an element just before idx+1 SetCtrlPtIds(); InsertedCP.CreateRoadMarker(); //Rename all the Roadmarkers after the inserted one for (int idxAdj = idx + 2; idxAdj < CtrlPts.Count; idxAdj++) { GameObject goRM = CtrlPts[idxAdj].goRdMkr; if (goRM != null) { RoadMarker RM = goRM.GetComponent <RoadMarker>(); RM.name = "RoadMarker" + idxAdj; RM.Index = idxAdj; } } //dunno why it ended up with the wrong parent CtrlPts[idx + 2].goRdMkr.transform.SetParent(Rd.Sectns[idx + 2].goSectn.transform); }
private void ReindexSectns(int StartSectnID) { //Bez.Path List <Vector3> PrevPaths = Bez.Path.GetRange(0, Bez.CtrlPts[StartSectnID].SegStartIdx); Bez.Path.RemoveRange(0, Bez.CtrlPts[StartSectnID].SegStartIdx); Bez.Path.AddRange(PrevPaths); //BezCtrlPts //remove the extra cp at starts and the two extra at the end Bez.CtrlPts.RemoveAt(0); Bez.CtrlPts.RemoveAt(Bez.CtrlPts.Count - 1); Bez.CtrlPts.RemoveAt(Bez.CtrlPts.Count - 1); //Copy the bit before the StartIdx List <BezCtrlPt> Prevs = Bez.CtrlPts.Where(c => c.CtrlPtId < StartSectnID).ToList(); //Paste it at the end Bez.CtrlPts.AddRange(Prevs); Bez.CtrlPts.RemoveRange(0, StartSectnID - 1); //Add the 3 extra CtrlPts BezCtrlPt p0 = new BezCtrlPt(Bez, Bez.CtrlPts.Last().Pos); Bez.CtrlPts.Insert(0, p0); BezCtrlPt p1 = new BezCtrlPt(Bez, Bez.CtrlPts[1].Pos); Bez.CtrlPts.Add(p1); BezCtrlPt p2 = new BezCtrlPt(Bez, Bez.CtrlPts[2].Pos); Bez.CtrlPts.Add(p2); Bez.CtrlPts[0].SegStartIdx = 0; Bez.SetCtrlPtIds(); //Road Sections iRoadSectn LastSctn = Rd.Sectns.Last(); Rd.Sectns.Remove(LastSctn); List <iRoadSectn> PrevSctns = Rd.Sectns.Where(s => s.Idx > 0 && s.Idx < StartSectnID).ToList(); Rd.Sectns.AddRange(PrevSctns); Rd.Sectns.RemoveRange(1, StartSectnID - 1); Rd.Sectns.Add(LastSctn); Rd.SetSectionIds(); for (int SectnID = 1; SectnID < Rd.Sectns.Count - 1; SectnID++) { Rd.Sectns[SectnID].goSectn.transform.SetSiblingIndex(SectnID); } //Rename RoadMarkers foreach (BezCtrlPt Ctl in Bez.CtrlPts) { if (Ctl.goRdMkr != null) { GameObject goRdMkr = Ctl.goRdMkr; RoadMarker RoadMarker = goRdMkr.gameObject.GetComponent <RoadMarker>(); RoadMarker.name = "RoadMarker" + Ctl.CtrlPtId; RoadMarker.Index = Ctl.CtrlPtId; goRdMkr.transform.SetParent(Road.Instance.Sectns[Ctl.CtrlPtId].goSectn.transform); } } //Reindex Segments List <RoadSegment> PrevSegs = Rd.Segments.Where(s => s.SectnIdx < StartSectnID).ToList(); //Rd.XSecs.Join(PrevSegs, x => x.Idx, i => i.Idx, (r) => new XSec); var px = (from x in Rd.XSecs join s in PrevSegs on x.Idx equals s.Idx select x); List <XSec> PrevXSecs = px.Cast <XSec>().ToList(); Rd.Segments.AddRange(PrevSegs); Rd.Segments.RemoveRange(0, PrevSegs.Count); for (int i = 0; i < Rd.Segments.Count; i++) { Rd.Segments[i].Idx = i; Rd.Segments[i].goSeg.name = "RoadSeg" + i; } foreach (iRoadSectn Sec in Rd.Sectns) { foreach (RoadSegment seg in Sec.Segments) { seg.SectnIdx = Sec.Idx; } } Bez.SetSegStartIds(); //Reindex XSecs Rd.XSecs.AddRange(PrevXSecs); Rd.XSecs.RemoveRange(0, PrevXSecs.Count); for (int i = 0; i < Rd.XSecs.Count; i++) { Rd.XSecs[i].Idx = i; } }
public Vector3 LimitSlope(Vector3 Pt, float MaxSlope) { if (CtrlPts.Count == 2) { return(Pt); //Because the first click can be anywhere } BezCtrlPt PrevCtrlPt = CtrlPts[CtrlPts.Count - 2]; Vector3 Pt1 = PrevCtrlPt.Pos; Vector3 Pt2 = Pt; float HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); //If point is too close move it further away if (HorizDist < 20) { Vector3 NewPt_3d = Pt1 + Vector3.Normalize(Pt2 - Pt1) * 20f; Pt2 = NewPt_3d; HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); } //if point is too high lower it float VertDist = Pt2.y - Pt1.y; float Slope = 0; if (HorizDist > 0) { Slope = VertDist / HorizDist; } if (Slope > MaxSlope) { //Debug.Log("Lowering cos too steep"); Slope = MaxSlope; float NewVertDist = Slope * HorizDist; Pt2.y = Pt1.y + NewVertDist; } //Dont allow the angle less than 30 degrees float angle = 180; if (CtrlPts.Count > 3) { angle = Angle(CtrlPts[CtrlPts.Count - 3].Pos, PrevCtrlPt.Pos, Pt2); if (Mathf.Abs(angle) < 45) { //Debug.Log("Widening angle cos its too acute"); float RotAngle; if (angle > 0) { RotAngle = 45; } else { RotAngle = -45; } Quaternion Rot = Quaternion.Euler(0, RotAngle - angle, 0); Vector3 NewPt_3d = VectGeom.RotateAroundPoint(Pt2, Pt1, Rot); Pt2 = NewPt_3d; angle = RotAngle; } } //if hairpins are too sharp and too close together, spread them out if (HorizDist * Mathf.Abs(angle) < 1500) { //Debug.Log("Moving CtrlPt away from hairpin"); Vector3 NewPt_3d = Pt1 + Vector3.Normalize(Pt2 - Pt1) * 1500 / Mathf.Abs(angle); Pt2 = NewPt_3d; HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); } if (Slope > 0 && Mathf.Abs(angle) / Slope < 270) { //Debug.Log("Flattening steep hairpin"); Slope = Mathf.Abs(angle) / 270; float NewVertDist = Slope * HorizDist; Pt2.y = Pt1.y + NewVertDist; } return(Pt2); //Debug.Log("Dist = " + HorizDist.ToString()); //Debug.Log("Slope = " + Slope.ToString()); //Debug.Log("Angle = " + angle.ToString()); //Typical values // Dist 10 - 30 // Slope < 0.3 }