Example #1
0
 public override Curve concat(Curve b)
 {
     if (Algebra.isclose(t_start, b.t_start))
     {
         Curve rtn = Bezeir.TryInit(P0, P1, P2, z_start + z_offset, b.z_offset - z_offset);
         rtn.t_start = t_end;
         rtn.t_end   = b.t_end;
         return(rtn);
     }
     if (Algebra.isclose(t_start, b.t_end))
     {
         Curve rtn = Bezeir.TryInit(P0, P1, P2, z_start + z_start, -b.z_offset - z_offset);
         rtn.t_start = t_end;
         rtn.t_end   = b.t_start;
         return(rtn);
     }
     if (Algebra.isclose(t_end, b.t_start))
     {
         Curve rtn = Bezeir.TryInit(P0, P1, P2, z_start, b.z_offset + z_offset);
         rtn.t_start = t_start;
         rtn.t_end   = b.t_end;
         return(rtn);
     }
     if (Algebra.isclose(t_end, b.t_end))
     {
         Curve rtn = Bezeir.TryInit(P0, P1, P2, z_start, z_offset - b.z_offset);
         rtn.t_start = t_start;
         rtn.t_end   = b.t_start;
         return(rtn);
     }
     Debug.Assert(false);
     return(null);
 }
Example #2
0
    public override List <Curve> segmentation(float maxlen)
    {
        List <Curve> result    = new List <Curve>();
        float        lastEnd   = 0f;
        int          fragCount = Mathf.CeilToInt(this.length / maxlen);

        for (int multipler = 0; multipler < fragCount; multipler++)
        {
            float thisEnd;
            thisEnd = Algebra.newTown(this.lengthByParam, this.lengthGradient, Mathf.Min(this.length, (float)(multipler + 1) * maxlen), Mathf.Min(1f, maxlen / this.length * (multipler + 1)));

            Curve fragment = Bezeir.TryInit(this.P0, this.P1, this.P2, this.z_start + this.z_offset * lastEnd, this.z_start + this.z_offset * thisEnd);
            fragment.t_start = toGlobalParam(lastEnd);
            fragment.t_end   = toGlobalParam(thisEnd);
            result.Add(fragment);
            lastEnd = thisEnd;
        }
        return(result);
    }
Example #3
0
    Road generateVirtualRoad(int i1, int i2)
    {
        Road r1 = connection[i1].First;
        Road r2 = connection[i2].First;

        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.margin0End : r1.margin1End;
        float r2_margin = startof(r2.curve) ? r2.margin0End : r2.margin1End;

        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));
            }
        }
    }
Example #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));
    }
Example #5
0
    public void Update()
    {
        clearAngleDrawing();
        laneConfig = GameObject.FindWithTag("UI/laneconfig").GetComponent <LaneConfigPanelBehavior>().laneconfigresult;
        interestedApproxLines.Clear();

        if (pointer >= 1)
        {
            interestedApproxLines.Add(Line.TryInit(controlPoint[pointer - 1] + Vector3.back * Algebra.InfLength, controlPoint[pointer - 1] + Vector3.forward * Algebra.InfLength));
            interestedApproxLines.Add(Line.TryInit(controlPoint[pointer - 1] + Vector3.left * Algebra.InfLength, controlPoint[pointer - 1] + Vector3.right * Algebra.InfLength));
            if (targetRoad != null && !Algebra.isProjectionClose(controlPoint[pointer - 1], targetRoad.curve.AttouchPoint(controlPoint[pointer - 1])))
            {
                interestedApproxLines.Add(Line.TryInit(controlPoint[pointer - 1], targetRoad.curve.AttouchPoint(controlPoint[pointer - 1])));
            }
        }

        if (indicatorType == IndicatorType.none)
        {
            nodeIndicator.transform.localScale = Vector3.zero;
        }

        if (controlPoint[pointer].x != Vector3.negativeInfinity.x && indicatorType != IndicatorType.none)
        {
            Vector3 adjustedAttach;
            if (targetRoad != null)
            {
                adjustedAttach = targetRoad.at(targetRoad.curve.paramOf(targetRoad.curve.AttouchPoint(controlPoint[pointer])).Value);
            }
            else
            {
                adjustedAttach = controlPoint[pointer];
            }
            nodeIndicator.transform.position   = new Vector3(adjustedAttach.x, adjustedAttach.y / 2 + 0.1f, adjustedAttach.z);
            nodeIndicator.transform.localScale = new Vector3(1.5f, Mathf.Max(1f, adjustedAttach.y / 2), 1.5f);

            if (indicatorType == IndicatorType.line)
            {
                if (pointer == 1)
                {
                    Destroy(roadIndicator);
                    addAngleDrawing(controlPoint[1], controlPoint[0]);
                    addAngleDrawing(controlPoint[0], controlPoint[1]);

                    Road cp0_targetRoad;
                    roadManager.approxNodeToExistingRoad(controlPoint[0], out cp0_targetRoad);
                    if (cp0_targetRoad != null)
                    {
                        //perpendicular
                        interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d((float)cp0_targetRoad.curve.paramOf(controlPoint[0])) + Mathf.PI / 2) * Algebra.InfLength));
                        interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d((float)cp0_targetRoad.curve.paramOf(controlPoint[0])) - Mathf.PI / 2) * Algebra.InfLength));
                        //extension
                        if (Algebra.isclose(cp0_targetRoad.curve.at_ending(true), controlPoint[0]))
                        {
                            Node crossingRoad;
                            roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(true), out crossingRoad);
                            Debug.Assert(crossingRoad != null);
                            interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                        }
                        else
                        {
                            if (Algebra.isclose(cp0_targetRoad.curve.at_ending(false), controlPoint[0]))
                            {
                                Node crossingRoad;
                                roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(false), out crossingRoad);
                                Debug.Assert(crossingRoad != null);
                                interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                            }
                        }
                    }

                    if (!Algebra.isProjectionClose(controlPoint[0], controlPoint[1]))
                    {
                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(Line.TryInit(controlPoint[0], controlPoint[1]), laneConfig);
                    }
                }

                if (pointer == 2)
                {
                    roadManager.addRoad(Line.TryInit(controlPoint[0], controlPoint[1]), laneConfig);
                    reset();
                }
            }
            if (indicatorType == IndicatorType.bezeir)
            {
                if (pointer == 1)
                {
                    Destroy(roadIndicator);
                    addAngleDrawing(controlPoint[1], controlPoint[0]);
                    addAngleDrawing(controlPoint[0], controlPoint[1]);
                    interestedApproxLines.Add(Line.TryInit(controlPoint[0] + Vector3.back * Algebra.InfLength, controlPoint[0] + Vector3.forward * Algebra.InfLength));
                    interestedApproxLines.Add(Line.TryInit(controlPoint[0] + Vector3.left * Algebra.InfLength, controlPoint[0] + Vector3.right * Algebra.InfLength));

                    Road cp0_targetRoad;
                    roadManager.approxNodeToExistingRoad(controlPoint[0], out cp0_targetRoad);
                    if (cp0_targetRoad != null)
                    {
                        interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d((float)cp0_targetRoad.curve.paramOf(controlPoint[0])) + Mathf.PI / 2) * Algebra.InfLength));
                        interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d((float)cp0_targetRoad.curve.paramOf(controlPoint[0])) - Mathf.PI / 2) * Algebra.InfLength));
                        if (Algebra.isclose(cp0_targetRoad.curve.at_ending(true), controlPoint[0]))
                        {
                            Node crossingRoad;
                            roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(true), out crossingRoad);
                            Debug.Assert(crossingRoad != null);
                            interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                        }
                        else
                        {
                            if (Algebra.isclose(cp0_targetRoad.curve.at_ending(false), controlPoint[0]))
                            {
                                Node crossingRoad;
                                roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(false), out crossingRoad);
                                Debug.Assert(crossingRoad != null);
                                interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                            }
                        }
                    }

                    if (!Algebra.isProjectionClose(controlPoint[0], controlPoint[1]))
                    {
                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(Line.TryInit(controlPoint[0], controlPoint[1]), laneConfig);
                    }
                }

                if (pointer == 2)
                {
                    if (!Geometry.Parallel(controlPoint[1] - controlPoint[0], controlPoint[2] - controlPoint[1]) &&
                        !Algebra.isRoadNodeClose(controlPoint[2], controlPoint[1]))
                    {
                        Destroy(roadIndicator);
                        addAngleDrawing(controlPoint[2], controlPoint[1]);

                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(Bezeir.TryInit(controlPoint[0], controlPoint[1], controlPoint[2]), laneConfig);
                    }
                }

                if (pointer == 3)
                {
                    if (!Geometry.Parallel(controlPoint[1] - controlPoint[0], controlPoint[2] - controlPoint[1]) &&
                        !Algebra.isRoadNodeClose(controlPoint[2], controlPoint[1]))
                    {
                        roadManager.addRoad(Bezeir.TryInit(controlPoint[0], controlPoint[1], controlPoint[2]), laneConfig);
                        reset();
                    }
                    else
                    {
                        pointer = 2;
                    }
                }
            }

            if (indicatorType == IndicatorType.arc)
            {
                if (pointer == 1)
                {
                    Road cp0_targetRoad;
                    roadManager.approxNodeToExistingRoad(controlPoint[0], out cp0_targetRoad);
                    if (cp0_targetRoad != null)
                    {
                        addAngleDrawing(controlPoint[0], controlPoint[1]);

                        if (Algebra.isclose(cp0_targetRoad.curve.at_ending(true), controlPoint[0]))
                        {
                            interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d(0f) + Mathf.PI / 2) * Algebra.InfLength));
                            interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d(0f) - Mathf.PI / 2) * Algebra.InfLength));
                            Node crossingRoad;
                            roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(true), out crossingRoad);
                            Debug.Assert(crossingRoad != null);
                            interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                        }
                        else
                        {
                            if (Algebra.isclose(cp0_targetRoad.curve.at_ending(false), controlPoint[0]))
                            {
                                interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d(1f) + Mathf.PI / 2) * Algebra.InfLength));
                                interestedApproxLines.Add(Line.TryInit(controlPoint[0], controlPoint[0] + Algebra.angle2dir_3d(cp0_targetRoad.curve.Angle_2d(1f) - Mathf.PI / 2) * Algebra.InfLength));
                                Node crossingRoad;
                                roadManager.findNodeAt(cp0_targetRoad.curve.at_ending(false), out crossingRoad);
                                Debug.Assert(crossingRoad != null);
                                interestedApproxLines.AddRange(crossingRoad.directionalLines(Algebra.InfLength, reverse: true));
                            }
                        }
                    }

                    /*ind[0] is start, ind[1] isorigin*/
                    Destroy(roadIndicator);
                    if (!Algebra.isProjectionClose(controlPoint[0], controlPoint[1]))
                    {
                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(Line.TryInit(controlPoint[1], controlPoint[0]), laneConfig);
                        if (!Algebra.isclose(controlPoint[1], controlPoint[0]))
                        {
                            roadConfigure.generate(Arc.TryInit(controlPoint[1], controlPoint[0], 1.999f * Mathf.PI), laneConfig);
                        }
                    }
                }

                if (pointer == 2)
                {
                    Vector3 basedir    = controlPoint[0] - controlPoint[1];
                    Vector3 towardsdir = controlPoint[2] - controlPoint[1];
                    interestedApproxLines.Add(Arc.TryInit(controlPoint[1], controlPoint[0], Mathf.PI * 1.999f));
                    if (!Algebra.isProjectionClose(Vector3.zero, towardsdir) && !Algebra.isProjectionClose(controlPoint[1], controlPoint[0]) && !Geometry.Parallel(basedir, towardsdir))
                    {
                        Destroy(roadIndicator);
                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(Arc.TryInit(Algebra.toVector2(controlPoint[1]), Algebra.toVector2(controlPoint[0]),
                                                           Mathf.Deg2Rad * Vector2.SignedAngle(Algebra.toVector2(basedir), Algebra.toVector2(towardsdir)),
                                                           controlPoint[0].y, controlPoint[2].y), laneConfig);
                        roadConfigure.generate(Arc.TryInit(controlPoint[1], controlPoint[1] + Vector3.right, 1.999f * Mathf.PI), laneConfig);
                    }
                }

                if (pointer == 3)
                {
                    Vector3 basedir    = controlPoint[0] - controlPoint[1];
                    Vector3 towardsdir = controlPoint[2] - controlPoint[1];
                    if (Algebra.isclose(0, towardsdir.magnitude))
                    {
                        pointer = 2;
                    }
                    else
                    {
                        roadManager.addRoad(Arc.TryInit(Algebra.toVector2(controlPoint[1]), Algebra.toVector2(controlPoint[0]), Mathf.Deg2Rad * Vector2.SignedAngle(Algebra.toVector2(basedir), Algebra.toVector2(towardsdir)),
                                                        controlPoint[0].y, controlPoint[2].y), laneConfig);
                        reset();
                    }
                }
            }

            if (indicatorType == IndicatorType.delete)
            {
                if (pointer == 0)
                {
                    Destroy(roadIndicator);

                    if (targetRoad != null)
                    {
                        roadIndicator = Instantiate(roadIndicatorPrefab, transform);
                        RoadRenderer roadConfigure = roadIndicator.GetComponent <RoadRenderer>();
                        roadConfigure.generate(targetRoad.marginedOutCurve, new List <string> {
                            "removal_" + targetRoad.width
                        });
                    }
                }
                else
                {
                    if (targetRoad != null)
                    {
                        roadManager.deleteRoad(targetRoad);
                        reset();
                    }
                    else
                    {
                        pointer = 0;
                    }
                }
            }
        }
    }