コード例 #1
0
        public void deleteRoad(Road r)
        {
            removeRoad(r);
            Node nstart, nend;

            findNodeAt(r.curve.At(0f), out nstart);
            findNodeAt(r.curve.At(1f), out nend);

            Node[] affectedNides = { nstart, nend };
            foreach (Node n in affectedNides.ToList())
            {
                if (n.connection.Count == 0)
                {
                    Destroy(allnodes[Algebra.approximate(n.position)].gameObject);
                    allnodes.Remove(Algebra.approximate(n.position));
                }
                else
                {
                    /*
                     * if (n.connection.Count == 2){
                     *  if (Geometry.sameMotherCurveUponIntersect(n.connection[0].First.curve, n.connection[1].First.curve)){
                     *      Road r1 = n.connection[0].First;
                     *      Road r2 = n.connection[1].First;
                     *      removeRoadWithoutChangingNodes(r1);
                     *      removeRoadWithoutChangingNodes(r2);
                     *      Destroy(allnodes[Algebra.approximate(n.position)].gameObject);
                     *      allnodes.Remove(Algebra.approximate(n.position));
                     *      Curve c2 = r1.curve.concat(r2.curve);
                     *      addPureRoad(c2, r1.laneconfigure); //TODO: deal with different lane configure
                     *  }
                     * }
                     */
                    n.updateMargins();

                    foreach (var r1 in n.connection)
                    {
                        createRoadObject(r1);
                    }
                }
            }
        }
コード例 #2
0
ファイル: RoadRenderer.cs プロジェクト: r2d2m/roadbuilder
 public void generate(Road r)
 {
     generate(r.curve, r.laneconfigure, r.margin0LLength, r.margin0RLength, r.margin1LLength, r.margin1RLength);
 }
コード例 #3
0
        Road generateVirtualRoad(int i1, int i2)
        {
            Road r1 = connection[i1];
            Road r2 = connection[i2];

            if (outLaneRange[i1, i2] == null)
            {
                return(null);
            }
            int loOutLaneNum = outLaneRange[i1, i2].First;
            int hiOutLaneNum = outLaneRange[i1, i2].Second;

            int loInLaneNum = inLaneRange[i2, i1].First;
            int hiInLaneNum = inLaneRange[i2, i1].Second;

            Debug.Assert(hiOutLaneNum - loOutLaneNum == hiInLaneNum - loInLaneNum);

            float r1_margin = startof(r1.curve) ? r1.margin0Param : r1.margin1Param;
            float r2_margin = startof(r2.curve) ? r2.margin0Param : r2.margin1Param;

            float   r1_radiOffset = 0.5f * (r1.getLaneCenterOffset(loOutLaneNum, !startof(r1.curve)) + r1.getLaneCenterOffset(hiOutLaneNum, !startof(r1.curve)));
            float   r2_radiOffset = 0.5f * (r2.getLaneCenterOffset(loInLaneNum, startof(r2.curve)) + r2.getLaneCenterOffset(hiInLaneNum, startof(r2.curve)));
            Vector3 r1_endPos     = r1.at(r1_margin) + r1.rightNormal(r1_margin) * r1_radiOffset;
            Vector3 r2_endPos     = r2.at(r2_margin) + r2.rightNormal(r2_margin) * r2_radiOffset;

            List <string> virtualRoadLaneCfg   = new List <string>();
            int           virtualRoadLaneCount = hiOutLaneNum - loOutLaneNum + 1;

            for (int i = 0; i != virtualRoadLaneCount; ++i)
            {
                virtualRoadLaneCfg.Add("lane");
                if (i != virtualRoadLaneCount - 1)
                {
                    virtualRoadLaneCfg.Add("dash_white");
                }
            }

            Vector2 r1_direction = startof(r1.curve) ? -r1.curve.direction_2d(r1_margin) : r1.curve.direction_2d(r1_margin);
            Vector2 r2_direction = startof(r2.curve) ? -r2.curve.direction_2d(r2_margin) : r2.curve.direction_2d(r2_margin);

            if (Geometry.Parallel(r1_direction, r2_direction))
            {
                /*TODO: perform a U turn when r1 = r2*/
                if (Algebra.isRoadNodeClose(r1_endPos, r2_endPos))
                {
                    /*exact same lane config for neighbors, just go straight*/
                    return(null);
                }
                //return new Road(Line.TryInit(r1_endPos, r2_endPos), virtualRoadLaneCfg, _noEntity: true);
                return(createNoEntityRoadIfNotNull(Line.TryInit(r1_endPos, r2_endPos), virtualRoadLaneCfg));
            }
            else
            {
                Curve          l1 = Line.TryInit(Algebra.toVector2(r1_endPos), Algebra.toVector2(r1_endPos) + Algebra.InfLength * r1_direction, r1_endPos.y, r1_endPos.y);
                Curve          l2 = Line.TryInit(Algebra.toVector2(r2_endPos), Algebra.toVector2(r2_endPos) + Algebra.InfLength * r2_direction, r2_endPos.y, r2_endPos.y);
                List <Vector3> intereSectionPoint = Geometry.curveIntersect(l1, l2);
                if (intereSectionPoint.Count == 1)
                {
                    //return new Road(Bezeir.TryInit(r1_endPos, intereSectionPoint.First(), r2_endPos), virtualRoadLaneCfg, _noEntity: true);
                    return(createNoEntityRoadIfNotNull(Bezeir.TryInit(r1_endPos, intereSectionPoint.First(), r2_endPos), virtualRoadLaneCfg));
                }
                else
                {
                    //return new Road(Line.TryInit(r1_endPos, r2_endPos), virtualRoadLaneCfg, _noEntity: true);
                    return(createNoEntityRoadIfNotNull(Line.TryInit(r1_endPos, r2_endPos), virtualRoadLaneCfg));
                }
            }
        }
コード例 #4
0
        Pair <float, float> smoothenCrossing(Road r1, Road r2, out List <Curve> smootheners)
        {
            float r1_angle    = startof(r1.curve) ? r1.curve.angle_ending(true) : r1.curve.angle_ending(false);
            float r2_angle    = startof(r2.curve) ? r2.curve.angle_ending(true) : r2.curve.angle_ending(false);
            float delta_angle = r1_angle < r2_angle ? r2_angle - r1_angle : r2_angle + 2 * Mathf.PI - r1_angle;

            this.r1     = r1;
            this.r2     = r2;
            smootheners = new List <Curve>();
            Vector2 streetCorner = approxStreetCorner();

            //debugPoints.Add(Algebra.toVector3(streetCorner));

            switch (Geometry.getAngleType(delta_angle))
            {
            case angleType.Sharp:
            case angleType.Blunt:
                if (c1_offset > 0f && c2_offset > 0f)
                {
                    /*c1,c2>0*/
                    float extraSmoothingLength = arcSmoothingRadius / Mathf.Tan(delta_angle / 2);
                    addIfNotNull(smootheners, Arc.TryInit(r1.curve.at_ending_2d(startof(r1.curve), c1_offset + extraSmoothingLength) +
                                                          Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), c1_offset + extraSmoothingLength) + Mathf.PI / 2) * r1.width / 2,
                                                          Mathf.PI - delta_angle,
                                                          r2.curve.at_ending_2d(startof(r2.curve), c2_offset + extraSmoothingLength) +
                                                          Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), c2_offset + extraSmoothingLength) - Mathf.PI / 2) * r2.width / 2));
                    return(new Pair <float, float>(c1_offset + extraSmoothingLength, c2_offset + extraSmoothingLength));
                }
                if (c1_offset > 0f)
                {
                    /*c1>0, c2<=0*/
                    float smoothRadius = -c2_offset;
                    addIfNotNull(smootheners, Arc.TryInit(r1.curve.at_ending_2d(startof(r1.curve), c1_offset + smoothRadius) +
                                                          Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), c1_offset + smoothRadius) + Mathf.PI / 2) * r1.width / 2,
                                                          Mathf.PI - delta_angle,
                                                          r2.curve.at_ending_2d(startof(r2.curve)) +
                                                          Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve)) - Mathf.PI / 2) * r2.width / 2));
                    /*TODO: calculate more precise delta_angle*/
                    return(new Pair <float, float>(c1_offset + smoothRadius, 0));
                }
                if (c2_offset > 0f)
                {
                    /*c1<0, c2>0*/
                    float smoothRadius = -c1_offset;
                    Curve smoothener   = Arc.TryInit(r1.curve.at_ending_2d(startof(r1.curve)) +
                                                     Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve)) + Mathf.PI / 2) * r1.width / 2,
                                                     Mathf.PI - delta_angle,
                                                     r2.curve.at_ending_2d(startof(r2.curve), c2_offset + smoothRadius) +
                                                     Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), c2_offset + smoothRadius) - Mathf.PI / 2) * r2.width / 2);
                    addIfNotNull(smootheners, smoothener);
                    return(new Pair <float, float>(0, c2_offset + smoothRadius));
                }
                Debug.Assert(false);
                break;

            case angleType.Flat:
                if (r1.width == r2.width)
                {
                    return(new Pair <float, float>(0, 0));
                }
                float widthDiff = Math.Abs(r1.width - r2.width) / 2;
                if (r1.width > r2.width)
                {
                    Vector2 P0 = r1.curve.at_ending_2d(startof(r1.curve)) +
                                 Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve)) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P1 = r2.curve.at_ending_2d(startof(r2.curve), widthDiff * bezeirSmoothingScale * 0.25f) +
                                 Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), widthDiff * bezeirSmoothingScale * 0.25f) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P4 = r2.curve.at_ending_2d(startof(r2.curve), widthDiff * bezeirSmoothingScale) +
                                 Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), widthDiff * bezeirSmoothingScale) - Mathf.PI / 2) * r2.width / 2;
                    Vector2 P3 = r2.curve.at_ending_2d(startof(r2.curve), widthDiff * bezeirSmoothingScale * 0.75f) +
                                 Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), widthDiff * bezeirSmoothingScale * 0.75f) - Mathf.PI / 2) * r2.width / 2;
                    Vector2 P2 = (P1 + P3) / 2;
                    addIfNotNull(smootheners, Bezeir.TryInit(P0, P1, P2));
                    addIfNotNull(smootheners, Bezeir.TryInit(P2, P3, P4));
                    return(new Pair <float, float>(0f, widthDiff * bezeirSmoothingScale));
                }
                else
                {
                    Vector2 P0 = r1.curve.at_ending_2d(startof(r1.curve), widthDiff * bezeirSmoothingScale)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), widthDiff * bezeirSmoothingScale) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P1 = r1.curve.at_ending_2d(startof(r1.curve), widthDiff * bezeirSmoothingScale * 0.75f)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), widthDiff * bezeirSmoothingScale * 0.75f) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P3 = r1.curve.at_ending_2d(startof(r1.curve), widthDiff * bezeirSmoothingScale * 0.25f)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), widthDiff * bezeirSmoothingScale * 0.25f) + Mathf.PI / 2) * r2.width / 2;
                    Vector2 P4 = r2.curve.at_ending_2d(startof(r2.curve)) +
                                 Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve)) - Mathf.PI / 2) * r2.width / 2;
                    Vector2 P2 = (P1 + P3) / 2;
                    addIfNotNull(smootheners, Bezeir.TryInit(P0, P1, P2));
                    addIfNotNull(smootheners, Bezeir.TryInit(P2, P3, P4));
                    return(new Pair <float, float>(widthDiff * bezeirSmoothingScale, 0f));
                }

            case angleType.Reflex:
                float arcRadius     = Mathf.Max(r1.width / 2, r2.width / 2);
                float bWidthDiff    = Mathf.Abs(r1.width - r2.width) / 2;
                Curve arcSmoothener = Arc.TryInit(twodPosition,
                                                  twodPosition + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve)) + Mathf.PI / 2) * arcRadius,
                                                  delta_angle - Mathf.PI);
                if (r1.width == r2.width)
                {
                    addIfNotNull(smootheners, arcSmoothener);
                    return(new Pair <float, float>(0f, 0f));
                }
                if (r1.width > r2.width)
                {
                    Vector2 P0 = r2.curve.at_ending_2d(startof(r2.curve)) +
                                 Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve)) - Mathf.PI / 2) * r1.width / 2;
                    Vector2 P1 = r2.curve.at_ending_2d(startof(r2.curve), bWidthDiff * bezeirSmoothingScale * 0.25f) +
                                 Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), bWidthDiff * bezeirSmoothingScale * 0.25f) - Mathf.PI / 2) * r1.width / 2;
                    Vector2 P4 = r2.curve.at_ending_2d(startof(r2.curve), bWidthDiff * bezeirSmoothingScale)
                                 + Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), bWidthDiff * bezeirSmoothingScale) - Mathf.PI / 2) * r2.width / 2;
                    Vector2 P3 = r2.curve.at_ending_2d(startof(r2.curve), bWidthDiff * bezeirSmoothingScale * 0.75f)
                                 + Algebra.angle2dir(r2.curve.angle_ending(startof(r2.curve), bWidthDiff * bezeirSmoothingScale * 0.75f) - Mathf.PI / 2) * r2.width / 2;
                    Vector2 P2 = (P1 + P3) / 2;
                    addIfNotNull(smootheners, arcSmoothener);
                    addIfNotNull(smootheners, Bezeir.TryInit(P0, P1, P2));
                    addIfNotNull(smootheners, Bezeir.TryInit(P2, P3, P4));
                    return(new Pair <float, float>(0f, bWidthDiff * bezeirSmoothingScale));
                }
                else
                {
                    Vector2 P0 = r1.curve.at_ending_2d(startof(r1.curve), bWidthDiff * bezeirSmoothingScale)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), bWidthDiff * bezeirSmoothingScale) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P1 = r1.curve.at_ending_2d(startof(r1.curve), bWidthDiff * bezeirSmoothingScale * 0.75f)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), bWidthDiff * bezeirSmoothingScale * 0.75f) + Mathf.PI / 2) * r1.width / 2;
                    Vector2 P3 = r1.curve.at_ending_2d(startof(r1.curve), bWidthDiff * bezeirSmoothingScale * 0.25f)
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve), bWidthDiff * bezeirSmoothingScale * 0.25f) + Mathf.PI / 2) * r2.width / 2;
                    Vector2 P4 = r1.curve.at_ending_2d(startof(r1.curve))
                                 + Algebra.angle2dir(r1.curve.angle_ending(startof(r1.curve)) + Mathf.PI / 2) * r2.width / 2;
                    Vector2 P2 = (P1 + P3) / 2;
                    addIfNotNull(smootheners, Bezeir.TryInit(P0, P1, P2));
                    addIfNotNull(smootheners, Bezeir.TryInit(P2, P3, P4));
                    addIfNotNull(smootheners, arcSmoothener);
                    return(new Pair <float, float>(bWidthDiff * bezeirSmoothingScale, 0f));
                }

            default:
                return(new Pair <float, float>(-1f, -1f));
            }
            return(new Pair <float, float>(-1f, -1f));
        }
コード例 #5
0
        /*
         * public Pair<float, float> getMargin(Road r){
         *  var conn = connection.Find((Pair<Road, ConnectionInfo> obj) => obj.First == r);
         *  if (!startof(r.curve))
         *  {
         *      return conn.Second.margins;
         *  }
         *  else
         *  {
         *      return new Pair<float, float>(conn.Second.margins.Second, conn.Second.margins.First);
         *  }
         * }
         */

        public void addRoad(Road road)
        {
            Debug.Assert(position.y == Mathf.NegativeInfinity || Algebra.isclose(road.curve.at_ending(startof(road.curve)).y, position.y));

            connection.Add(road);
        }
コード例 #6
0
ファイル: Vehicle.cs プロジェクト: r2d2m/roadbuilder
        // Update is called once per frame
        void Update()
        {
            if (pathOn != null)
            {
                float distToTravel;
                if (acceleration < 0f && speed < (-acceleration) * Time.deltaTime)
                {
                    distToTravel = speed * speed / (2 * (-acceleration));
                }
                else
                {
                    distToTravel = speed * Time.deltaTime + 0.5f * acceleration * Time.deltaTime * Time.deltaTime;
                }
                speed += Time.deltaTime * acceleration;
                speed  = Mathf.Max(0f, speed);

                distTraveledOnSeg += distToTravel;
                bool termination;
                int  nextSeg, nextLane;
                Pair <Road, float> nextInfo = pathOn.travelAlong(currentSeg, currentParam, distToTravel, laneOn, out nextSeg, out nextLane, out termination);

                if (termination)
                {
                    VhCtrlOfCurrentSeg.VehicleLeave(this, laneOn);

                    stopEvent.Invoke();

                    Reset();
                    return;
                }

                Road roadOn = nextInfo.First;
                currentParam = nextInfo.Second;

                if (currentSeg != nextSeg)
                {
                    VhCtrlOfCurrentSeg.VehicleLeave(this, laneOn);
                    distTraveledOnSeg = distToTravel;
                    laneOn            = nextLane;
                    currentSeg        = nextSeg;

                    VhCtrlOfCurrentSeg.VehicleEnter(this, laneOn);
                }

                if (!Algebra.isclose(rightOffset, 0f))
                {
                    float lateralAcc = (lateralSpeedMagnitude * lateralSpeedMagnitude > 2 * lateralMaxAcc * Mathf.Abs(rightOffset)) ?
                                       -0.98f * lateralMaxAcc : lateralMaxAcc;

                    lateralSpeedMagnitude = Mathf.Max(lateralSpeedMagnitude + lateralAcc * Time.deltaTime, 0f);

                    rightOffset = Mathf.Sign(rightOffset) * Mathf.Max(Mathf.Abs(rightOffset) - lateralSpeedMagnitude * Time.deltaTime, 0f);
                }
                else
                {
                    lateralSpeedMagnitude = 0f;
                }

                transform.position = roadOn.at(currentParam, usebuff: true) +
                                     roadOn.rightNormal(currentParam, usebuff: true) * (roadOn.getLaneCenterOffset(laneOn, headingOfCurrentSeg) + rightOffset);

                transform.rotation = headingOfCurrentSeg ?
                                     Quaternion.LookRotation(roadOn.frontNormal(currentParam, usebuff: true), roadOn.upNormal(currentParam, usebuff: true)) :
                                     Quaternion.LookRotation(-roadOn.frontNormal(currentParam, usebuff: true), roadOn.upNormal(currentParam, usebuff: true));

                if (rightOffset != 0f)
                {
                    if (headingOfCurrentSeg)
                    {
                        transform.Rotate(roadOn.upNormal(currentParam, usebuff: true), -Mathf.Sign(rightOffset) * Mathf.Atan(lateralSpeedMagnitude / Mathf.Max(speed, 0.2f)) * Mathf.Rad2Deg);
                    }
                    else
                    {
                        transform.Rotate(roadOn.upNormal(currentParam, usebuff: true), Mathf.Sign(rightOffset) * Mathf.Atan(lateralSpeedMagnitude / Mathf.Max(speed, 0.2f)) * Mathf.Rad2Deg);
                    }
                }

                wheelRotation = (wheelRotation + distToTravel / wheeRadius * Mathf.Rad2Deg) % 360;
                /*TODO: calculate wheel radius*/
                transform.GetChild(0).GetChild(1).localRotation     = transform.GetChild(0).GetChild(2).localRotation =
                    transform.GetChild(0).GetChild(3).localRotation = transform.GetChild(0).GetChild(4).localRotation =
                        Quaternion.Euler(wheelRotation, 0f, 0f);
            }
        }
コード例 #7
0
        /*TODO: improve efficiency*/
        public Path findPath(Road r1, float param1, Road r2, float param2)
        {
            if (r1 == r2)
            {
                /*Special trivial case*/
                return(new Path(r1, param1, param2));
            }

            List <Node> possibleStartNodes = new List <Node>();
            List <Node> possibleEndNodes   = new List <Node>();

            if (r1.directionalLaneCount(false) > 0)
            {
                Node r10;
                findNodeAt(r1.curve.At(0f), out r10);
                possibleStartNodes.Add(r10);
            }

            if (r1.directionalLaneCount(true) > 0)
            {
                Node r11;
                findNodeAt(r1.curve.At(1f), out r11);
                possibleStartNodes.Add(r11);
            }

            if (r2.directionalLaneCount(true) > 0)
            {
                Node r20;
                findNodeAt(r2.curve.At(0f), out r20);
                possibleEndNodes.Add(r20);
            }

            if (r2.directionalLaneCount(false) > 0)
            {
                Node r21;
                findNodeAt(r2.curve.At(1f), out r21);
                possibleEndNodes.Add(r21);
            }

            if (possibleStartNodes.Count * possibleEndNodes.Count == 0)
            {
                return(null);
            }

            List <Path> candicatePaths = new List <Path>();

            foreach (Node nstart in possibleStartNodes)
            {
                foreach (Node nend in possibleEndNodes)
                {
                    Path p = Node2NodeSP(nstart, nend);

                    if (p != null)
                    {
                        p.insertAtStart(r1, param1);
                        p.insertAtEnd(r2, param2);
                        candicatePaths.Add(p);
                    }
                }
            }

            if (candicatePaths.Count > 0)
            {
                return(candicatePaths.MinBy((arg) => arg.length));
            }
            else
            {
                return(null);
            }
        }
コード例 #8
0
        /* For non-virtual(existing road), should consider height diff
         *  For virtual road, always flatten
         */
        public Vector3 approxNodeToExistingRoad(Vector3 p, out Road match, List <Curve> additionalInterestedLines = null)
        {
            List <Road> allInterestedRoad;

            if (additionalInterestedLines != null)
            {
                allInterestedRoad = new List <Road>();
                allInterestedRoad.AddRange(allroads);
                allInterestedRoad.AddRange(additionalInterestedLines.ConvertAll <Road>((Curve input) => new Road(input, null)));
            }
            else
            {
                allInterestedRoad = allroads;
            }
            //Debug.Assert(additionalInterestedLines == null || additionalInterestedLines.All((arg1) => arg1 is Line));

            List <Road> candidates = allInterestedRoad.FindAll(r => r.virtualRoad ?
                                                               (Algebra.toVector2(r.curve.AttouchPoint(p)) - Algebra.toVector2(p)).magnitude <= ApproxLimit:
                                                               (r.curve.AttouchPoint(p) - p).magnitude <= ApproxLimit);

            List <Road> onlyRoadCandidates = candidates.FindAll((obj) => !obj.virtualRoad);

            if (onlyRoadCandidates.Count > 0)
            {
                Road bestMatch = onlyRoadCandidates.OrderBy(r => (r.curve.AttouchPoint(p) - p).magnitude).First();
                match = bestMatch;
                foreach (Road others in candidates)
                {
                    if (others != bestMatch)
                    {
                        List <Vector3> interPoints;
                        if (others.virtualRoad)
                        {
                            Curve othersCurve    = others.curve.deepCopy().flattened();
                            Curve bestmatchCurve = bestMatch.curve.deepCopy().flattened();
                            interPoints = Geometry.curveIntersect(othersCurve, bestmatchCurve);

                            foreach (Vector3 point in interPoints)
                            {
                                if (Algebra.toVector2(point - p).magnitude <= ApproxLimit)
                                {
                                    return(bestMatch.curve.At((float)bestMatch.curve.paramOf(point)));
                                }
                            }
                        }
                        else
                        {
                            interPoints = Geometry.curveIntersect(bestMatch.curve, others.curve);
                            foreach (Vector3 point in interPoints)
                            {
                                if ((point - p).magnitude <= ApproxLimit)
                                {
                                    return(point);
                                }
                            }
                        }
                    }
                }
                return(bestMatch.curve.AttouchPoint(p));
            }

            if (candidates.Count > 0)
            {
                match = null;
                Vector3 flattened = candidates[0].curve.AttouchPoint(p);
                return(new Vector3(flattened.x, p.y, flattened.z));
            }

            match = null;
            return(p);
        }