Beispiel #1
0
        private void CheckHaltingConditions(DynamicSettings settings)
        {
            var staticSettings = ConvertDynSettingsToStatic(settings);
            var toRemove       = new List <Particle>();

            for (int i = 0; i < particles.Count; i++)
            {
                var p = particles[i];

                var add      = false;
                var outBasis = new Basis(p.Current.Point, p.Current.Vector);

                if (!Algos.CheckHaltingConditions(p.Current.Point, p.Start, outBasis, p.Current.Vector.Value, out add, staticSettings) || add == false)
                {
                    toRemove.Add(p);
                }
                else
                {
                    p.Current.Point = outBasis.Point;
                }
            }

            foreach (var remove in toRemove)
            {
                particles.Remove(remove);
            }
        }
Beispiel #2
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            var points          = new List <GH_Point>();
            var vectors         = new List <GH_Vector>();
            var surface         = new GH_Surface();
            var dynamicsWrapped = new List <GH_ObjectWrapper>();

            if (DA.GetDataList(0, points) && points == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid point list. Operation canceled.");
                return;
            }

            if (DA.GetDataList(1, vectors) && vectors == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid vector list. Operation canceled.");
                return;
            }

            // if vec field is empty, create parallel list of 0 vectors
            if (vectors.Count == 0)
            {
                for (int i = 0; i < points.Count; i++)
                {
                    vectors.Add(new GH_Vector());
                }
            }

            if (DA.GetDataList(2, dynamicsWrapped) && dynamicsWrapped == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid dynamics list. Operation canceled.");
                return;
            }

            if (DA.GetData(3, ref surface) && surface == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid surface. Operation canceled.");
                return;
            }

            var dynamics = new List <IDynamic>();

            foreach (var d in dynamicsWrapped)
            {
                dynamics.Add(d.Value as IDynamic);
            }
            Algos.SortDynamicsByPriority(dynamics);

            Algos.ClearDynamics(dynamics);

            foreach (var d in dynamics)
            {
                Algos.ProcessDynamics(d, points, vectors, surface);
            }

            Algos.RealignAccelerationVectors(dynamics, vectors);

            DA.SetDataList(0, points);
            DA.SetDataList(1, vectors);
        }
Beispiel #3
0
        private void UpdateWithDynamics(List <IDynamic> dynamics, DynamicSettings settings)
        {
            var points  = new List <GH_Point>(particles.Count);
            var vectors = new List <GH_Vector>(particles.Count);

            for (int i = 0; i < particles.Count; i++)
            {
                points.Add(particles[i].Current.Point);
                vectors.Add(new GH_Vector());
            }

            foreach (var d in dynamics)
            {
                // we need a new list of vectors each way through, which we add seperately to an end result
                // otherwise acceleration can apply across dynamics in unintended ways
                var tempVectors = new List <GH_Vector>(particles.Count);
                for (int i = 0; i < particles.Count; i++)
                {
                    tempVectors.Add(new GH_Vector());
                }

                // post processes use the cumulative vector list
                // pre processes use the temporary empty vector list
                if (d.PostProcess)
                {
                    // vectors is modified inline so we don't need to update as below
                    Algos.ProcessDynamics(d, points, vectors, settings.surface);
                }
                else
                {
                    Algos.ProcessDynamics(d, points, tempVectors, settings.surface);

                    for (int i = 0; i < particles.Count; i++)
                    {
                        vectors[i].Value += tempVectors[i].Value;
                    }
                }
            }

            Algos.RealignAccelerationVectors(dynamics, vectors);

            for (int i = 0; i < points.Count; i++)
            {
                points[i].Value += vectors[i].Value;

                // update particles from resultant p/v's above
                particles[i].Current.Point  = points[i];
                particles[i].Current.Vector = vectors[i];
            }
        }
Beispiel #4
0
        public void Process(List <GH_Point> points, List <GH_Vector> vectors, GH_Surface surface)
        {
            var surfaces  = Param["Surfs"] as List <GH_Surface>;
            var alignList = new List <int>();

            for (int i = 0; i < points.Count; i++)
            {
                var point  = points[i].Value;
                var vector = vectors[i].Value;

                foreach (var surf in surfaces)
                {
                    var       curve = Curve.CreateControlPointCurve(new Point3d[] { point, point + vector });
                    Curve[]   overlaps;
                    Point3d[] intersections;
                    Intersection.CurveBrep(curve, surf.Value, 0.001d, out overlaps, out intersections);

                    if (intersections.Length > 0)
                    {
                        var intersect = intersections[0];

                        // get uv coordiantes of intersection
                        double u, v;
                        surf.Face.ClosestPoint(intersect, out u, out v);
                        var surfNormal = surf.Face.NormalAt(u, v);

                        // unitize manually, apply dot product
                        surfNormal *= 1 / surfNormal.Length;
                        surfNormal *= Algos.DotProduct(vector, surfNormal);

                        // black magic
                        vector -= 2 * surfNormal;

                        vectors[i].Value = vector;

                        alignList.Add(i);
                    }
                }
            }

            if (alignList.Count > 0)
            {
                Param["alignAccVectors"] = alignList;
            }
            else
            {
                Param.Remove("alignAccVectors");
            }
        }
Beispiel #5
0
        public static GH_Point GetPointModifiedByDynamics(GH_Point traveller, Basis outBasis, List <IDynamic> dynamics, StaticSettings spm_settings)
        {
            var output = new GH_Point();

            foreach (var d in dynamics)
            {
                var p = new List <GH_Point>();
                p.Add(traveller);

                var v = new List <GH_Vector>();

                if (d.PostProcess)
                {
                    v.Add(outBasis.Vector);
                }
                else
                {
                    v.Add(new GH_Vector());
                }

                ProcessDynamics(d, p, v, spm_settings.surface);

                if (d.PostProcess)
                {
                    outBasis.Vector.Value = v[0].Value;
                }
                else
                {
                    outBasis.Vector.Value += v[0].Value;
                }
            }

            // realign acceleration if necessary
            var outVec = new List <GH_Vector>()
            {
                outBasis.Vector
            };

            Algos.RealignAccelerationVectors(dynamics, outVec);
            outBasis.Vector = outVec[0];

            // compute our resultant point via the traveller + resultant vectors
            var res = traveller.Value + (outBasis.Vector.Value);

            return(new GH_Point(res));
        }
Beispiel #6
0
        public void Process(List <GH_Point> points, List <GH_Vector> vectors, GH_Surface surface)
        {
            var dynamicsWrapped = Param["D"] as List <GH_ObjectWrapper>;

            var dynamics = new List <IDynamic>();

            foreach (var d in dynamicsWrapped)
            {
                dynamics.Add(d.Value as IDynamic);
            }
            Algos.SortDynamicsByPriority(dynamics);

            foreach (var d in dynamics)
            {
                Algos.ProcessDynamics(d, points, vectors, surface);
            }
        }
Beispiel #7
0
        private void UpdateIntegration(List <GH_Point> points, List <GH_Vector> vectors, DynamicSettings settings)
        {
            // only integrate if we have a vector field to work with
            if (points.Count > 0)
            {
                // integration
                var bases = new List <Basis>();
                for (int i = 0; i < points.Count; i++)
                {
                    bases.Add(new Basis(points[i], vectors[i]));
                }

                var ptSampling = (points.Count != 0);

                var staticSettings = ConvertDynSettingsToStatic(settings);

                for (int i = 0; i < particles.Count; i++)
                {
                    var p = particles[i];

                    var traveller  = p.Current.Point;
                    var startBasis = p.Start;
                    var vecLast    = p.Current.Vector;

                    var outBasis = new Basis();

                    if (points.Count != 0 &&
                        !Algos.SampleForNextPoint(bases, traveller.Value, startBasis, vecLast, staticSettings, out outBasis))
                    {
                        break;
                    }

                    p.Current.Point  = outBasis.Point;
                    p.Current.Vector = outBasis.Vector;
                }
            }
        }
Beispiel #8
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // inputs
            var points          = new List <GH_Point>();
            var vectors         = new List <GH_Vector>();
            var startPoints     = new List <GH_Point>();
            var lifeTime        = new GH_Integer();
            var settings        = new GH_ObjectWrapper();
            var reset           = new GH_Boolean();
            var dynamicsWrapped = new List <GH_ObjectWrapper>();
            var dynamics        = new List <IDynamic>();

            if (DA.GetDataList(0, points) && points == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid points list. Operation canceled.");
                return;
            }

            if (DA.GetDataList(1, vectors) && vectors == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid vector list. Operation canceled.");
                return;
            }

            if (vectors.Count != points.Count && vectors.Count != 0)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Vector list size mismatch with points list, they must be equal in length (or empty). Operation canceled.");
                return;
            }

            if (DA.GetDataList(2, startPoints) && startPoints == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid travelling points. Operation canceled.");
                return;
            }

            if (DA.GetData(3, ref lifeTime) && lifeTime == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid lifetime input. Operation canceled.");
                return;
            }

            if (DA.GetDataList(4, dynamicsWrapped) && dynamicsWrapped == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid dynamics list. Operation canceled.");
                return;
            }
            dynamics = (from d in dynamicsWrapped select d.Value as IDynamic).ToList();
            Algos.SortDynamicsByPriority(dynamics);

            // if vectors list is empty we'll populate it with empty vectors to match each point
            if (vectors.Count == 0)
            {
                for (int i = 0; i < points.Count; i++)
                {
                    vectors.Add(new GH_Vector());
                }
            }

            // spm parameters component is optional, we use its defaults if it is not available
            var spm_settings = new DynamicSettings();

            if (DA.GetData(5, ref settings))
            {
                // if getdata succeeded but the settings var is null we had bad input
                if (settings == null)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid settings input. Operation canceled.");
                    return;
                }

                // otherwise cast from gh_objectwrapper and continue
                spm_settings = (DynamicSettings)settings.Value;
            }

            if (DA.GetData(6, ref reset) && reset == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid reset input. Operation canceled.");
                return;
            }

            if (emitter == null || reset.Value)
            {
                emitter = new Emitter(startPoints, lifeTime.Value, spm_settings);
                DA.SetDataList(0, startPoints);

                var zv = new List <GH_Vector>(startPoints.Count);
                for (int i = 0; i < startPoints.Count; i++)
                {
                    zv.Add(new GH_Vector());
                }

                Algos.ClearDynamics(dynamics);

                DA.SetDataList(1, zv);
                return;
            }

            // emitter updates dynamics
            emitter.Update(dynamics, points, vectors, spm_settings);

            DA.SetDataList(0, emitter.Points);
            DA.SetDataList(1, emitter.Vectors);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // inputs
            var points      = new List <GH_Point>();
            var vectors     = new List <GH_Vector>();
            var startPoints = new List <GH_Point>();
            var reset       = new GH_Boolean();

            var settings = new GH_ObjectWrapper();

            if (DA.GetDataList(0, points) && points == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid points list. Operation canceled.");
                return;
            }

            if (DA.GetDataList(1, vectors) && vectors == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid vector list. Operation canceled.");
                return;
            }

            if (vectors.Count != points.Count)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Vector list size mismatch with points list, they must be equal in length. Operation canceled.");
                return;
            }

            if (DA.GetDataList(2, startPoints) && startPoints == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid travelling points. Operation canceled.");
                return;
            }

            // spm parameters component is optional, we use its defaults if it is not available
            SPM_Parameters spm_settings = new SPM_Parameters();

            if (DA.GetData(3, ref settings))
            {
                // if getdata succeeded but the settings var is null we had bad input
                if (settings == null)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid settings input. Operation canceled.");
                    return;
                }

                // otherwise cast from gh_objectwrapper and continue
                spm_settings = (SPM_Parameters)settings.Value;
            }

            if (DA.GetData(4, ref reset) && reset == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid reset input. Operation canceled.");
                return;
            }

            if (startBasis == null || reset.Value)
            {
                var count = startPoints.Count;

                startBasis = new Basis[count];
                lastVecs   = new GH_Vector[count];

                xy = new double[count];
                yz = new double[count];
                xz = new double[count];

                for (int i = 0; i < count; i++)
                {
                    startBasis[i] = new Basis(startPoints[i]);
                    lastVecs[i]   = new GH_Vector();
                    xy[i]         = 0;
                    yz[i]         = 0;
                    xz[i]         = 0;
                }
            }

            if (moving == null || reset.Value)
            {
                moving = startPoints;
                return;
            }

            int steps = spm_settings.steps;

            if (steps == 0)
            {
                steps = 1;
            }

            var bases = new List <Basis>();

            for (int i = 0; i < points.Count; i++)
            {
                bases.Add(new Basis(points[i], vectors[i]));
            }

            // find each next point based on an averaging formula and iterate

            for (int i = 0; i < startPoints.Count; i++)
            {
                for (int j = 0; j < steps; j++)
                {
                    bool add = false;

                    var outBasis = new Basis();

                    bool working = Algos.SampleForNextPoint(bases, moving[i].Value, startBasis[i], lastVecs[i], spm_settings, out outBasis, out add);

                    if (spm_settings.stop && spm_settings.windAngle != 0.0d)
                    {
                        if (!lastVecs[i].Value.IsZero)
                        {
                            double cxy = xy[i];
                            double cyz = yz[i];
                            double cxz = xz[i];

                            if (Algos.IsWoundPast(outBasis.Vector.Value, lastVecs[i].Value, spm_settings.windAngle, ref cxy, ref cyz, ref cxz))
                            {
                                break;
                            }

                            xy[i] = cxy;
                            yz[i] = cyz;
                            xz[i] = cxz;
                        }
                    }

                    lastVecs[i] = outBasis.Vector;

                    if (working && startBasis[i].Vector.Value.IsZero)
                    {
                        startBasis[i].Vector.Value = moving[i].Value - startBasis[i].Point.Value;
                    }

                    if (add)
                    {
                        moving[i] = outBasis.Point;
                    }

                    if (!working)
                    {
                        moving[i] = startPoints[i];
                    }
                }
            }

            DA.SetDataList(0, moving);
        }
Beispiel #10
0
        public void Process(List <GH_Point> points, List <GH_Vector> vectors, GH_Surface surface)
        {
            var planes  = Param["Pl"] as List <GH_Plane>;
            var h       = (double)Param["h"];
            var k       = (double)Param["k"];
            var a       = (double)Param["a"];
            var e       = (bool)Param["e"];
            var funnel  = (bool)Param["F"];
            var reverse = (bool)Param["r"];

            var    nv = new GH_Vector();
            double u1, v1, u2, v2;

            u1 = u2 = v1 = v2 = 0.0d;

            for (int i = 0; i < points.Count; i++)
            {
                foreach (var pl in planes)
                {
                    var o     = pl.Value.Origin;
                    var currP = points[i].Value;

                    if (surface.IsValid)
                    {
                        if (!e)
                        {
                            surface.Face.ClosestPoint(currP, out u1, out v1);
                            var surfPl = new Plane(currP, surface.Face.NormalAt(u1, v1));

                            Point3d remap;
                            surfPl.RemapToPlaneSpace(pl.Value.Origin, out remap);

                            var dir = surfPl.PointAt(remap.X, remap.Y) - surfPl.Origin;
                            dir.Unitize();

                            surface.Face.ClosestPoint(pl.Value.Origin, out u2, out v2);

                            Point2d uv1 = new Point2d(u1, v1);
                            Point2d uv2 = new Point2d(u2, v2);

                            var dis = uv1.DistanceTo(uv2);
                            dir *= (k / Math.Pow(dis, h));

                            var tan = Vector3d.CrossProduct(dir, surface.Face.NormalAt(u1, v1));
                            tan.Unitize();
                            tan *= a / dis;

                            Vector3d rotation = dir + tan;
                            rotation.Unitize();

                            Basis offCheck = new Basis(new GH_Point(currP + rotation));
                            if (!Algos.CheckIfOffSurface(offCheck, surface))
                            {
                                nv.Value += rotation;
                            }
                        }
                        else
                        {
                            surface.Face.ClosestPoint(currP, out u1, out v1);
                            surface.Face.ClosestPoint(o, out u2, out v2);

                            var p1 = new Point2d(u1, v1);
                            var p2 = new Point2d(u2, v2);

                            var c = surface.Face.ShortPath(p1, p2, 0.001d);
                            var v = c.TangentAtStart;

                            nv = new GH_Vector(v);
                            nv.Value.Unitize();
                            nv.Value *= (k / Math.Pow(c.GetLength(), 1d + h));

                            var sn   = surface.Face.NormalAt(u1, v1);
                            var sncv = Vector3d.CrossProduct(sn, v);
                            sncv.Unitize();
                            sncv *= a / c.GetLength();

                            nv.Value += sncv;
                        }

                        if (reverse)
                        {
                            surface.Face.ClosestPoint(currP, out u1, out v1);
                            var surfN = surface.Face.NormalAt(u1, v1);

                            var v = Vector3d.CrossProduct(surfN, nv.Value);
                            v.Unitize();
                            v       *= nv.Value.Length;
                            nv.Value = v;
                        }
                    }
                    else
                    {
                        nv = new GH_Vector(o - currP);
                        nv.Value.Unitize();
                        nv.Value *= (k / Math.Pow(currP.DistanceTo(o), 1d + h));

                        if (funnel)
                        {
                            Point3d outP;
                            pl.Value.RemapToPlaneSpace(currP, out outP);
                            nv.Value *= Math.Sign(outP.Z);
                        }

                        Point3d sign;
                        pl.Value.RemapToPlaneSpace(currP, out sign);

                        if (sign.X != 0 && sign.Y != 0)
                        {
                            Vector3d tan;

                            tan = new Vector3d(-sign.Y, sign.X, 0);

                            var tanAtPl = pl.Value.PointAt(tan.X, tan.Y, 0);
                            var tanAtO  = tanAtPl - o;

                            tanAtO   *= a / Math.Pow(tan.Length, 2d + h);
                            nv.Value += tanAtO;
                        }
                    }

                    vectors[i].Value += nv.Value;
                }
            }
        }
Beispiel #11
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // inputs
            var points = new List <GH_Point>();
            var planes = new List <GH_Plane>();

            var vectors         = new List <GH_Vector>();
            var traveller       = new GH_Point();
            var settings        = new GH_ObjectWrapper();
            var dynamicsWrapped = new List <GH_ObjectWrapper>();
            var dynamics        = new List <IDynamic>();

            // outputs
            var linePoints = new List <GH_Point>();
            var lineVecs   = new List <GH_Vector>();

            // gather and validate inputs
            if (DA.GetDataList(0, points) && points == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid points list. Operation canceled.");
                return;
            }

            if (DA.GetData(2, ref traveller) && traveller == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid travelling point. Operation canceled.");
                return;
            }

            if (DA.GetDataList(3, dynamicsWrapped) && dynamicsWrapped == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid dynamics list. Operation canceled.");
                return;
            }
            dynamics = (from d in dynamicsWrapped select d.Value as IDynamic).ToList();
            Algos.SortDynamicsByPriority(dynamics);

            // spm parameters component is optional, we use its defaults if it is not available
            StaticSettings spm_settings = new StaticSettings();

            if (DA.GetData(4, ref settings))
            {
                // if getdata succeeded but the settings var is null we had bad input
                if (settings == null)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid settings input. Operation canceled.");
                    return;
                }

                // otherwise cast from gh_objectwrapper and continue
                spm_settings = (StaticSettings)settings.Value;
            }

            var bases        = new List <Basis>();
            var basesWrapper = new List <GH_ObjectWrapper>();

            // we need to get the vector field information after settings, for tensor settings
            if (spm_settings.tensor && (spm_settings.tensorDir >= 0 && spm_settings.tensorDir <= 2))
            {
                if (DA.GetDataList(1, basesWrapper) && basesWrapper == null)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid tensor field. Operation canceled.");
                    return;
                }

                for (int i = 0; i < basesWrapper.Count; i++)
                {
                    Basis b = basesWrapper[i].Value as Basis;
                    bases.Add(new Basis(points[i], b.Vectors));
                    bases[i].Axes = spm_settings.tensorAxes;
                }
            }
            else
            {
                if (DA.GetDataList(1, vectors) && vectors == null)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid vector list. Operation canceled.");
                    return;
                }

                if (vectors.Count != points.Count && vectors.Count != 0)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Vector list size mismatch with points list, they must be equal in length (or empty if you wish to integrate using just dynamics). Operation canceled.");
                    return;
                }

                // if vectors list is empty we'll populate it with empty vectors to match each point
                if (vectors.Count == 0)
                {
                    foreach (var i in Enumerable.Range(0, points.Count))
                    {
                        vectors.Add(new GH_Vector());
                    }
                }

                for (int i = 0; i < points.Count; i++)
                {
                    bases.Add(new Basis(points[i], vectors[i]));
                }
            }

            int steps = spm_settings.steps;

            if (steps == 0)
            {
                steps = MAX_ITERATIONS;
            }

            var    startBasis = new Basis(traveller);
            var    vecLast    = new GH_Vector();
            double xy         = 0;
            double yz         = 0;
            double xz         = 0;

            // add start point to output
            linePoints.Add(startBasis.Point);

            Algos.ClearDynamics(dynamics);

            // find each next point based on an averaging formula and iterate
            for (int i = 0; i < steps; i++)
            {
                bool add      = false;
                var  outBasis = new Basis();

                if (points.Count != 0 &&
                    !Algos.SampleForNextPoint(bases, traveller.Value, startBasis, vecLast, spm_settings, out outBasis))
                {
                    break;
                }

                if (dynamics.Count > 0)
                {
                    traveller      = Algos.GetPointModifiedByDynamics(traveller, outBasis, dynamics, spm_settings);
                    outBasis.Point = traveller;
                }
                else
                {
                    traveller = outBasis.Point;
                }

                // this step must be done oustide of the regular halting checks as we must store the axes rotations
                if (spm_settings.windAngle != 0.0d && !vecLast.Value.IsZero &&
                    Algos.IsWoundPast(outBasis.Vector.Value, vecLast.Value, spm_settings.windAngle, ref xy, ref yz, ref xz))
                {
                    break;
                }

                var working = Algos.CheckHaltingConditions(traveller, startBasis, outBasis, vecLast.Value, out add, spm_settings);

                traveller = outBasis.Point;
                vecLast   = outBasis.Vector;

                // cache the vector between start and start+1
                if (i == 0 && working)
                {
                    startBasis.Vector.Value = traveller.Value - startBasis.Point.Value;
                }

                if (add)
                {
                    linePoints.Add(traveller);
                    lineVecs.Add(vecLast);
                }

                if (!working)
                {
                    break;
                }
            }

            DA.SetDataList(0, linePoints);
            DA.SetDataList(1, lineVecs);
        }