//@author: original: motzi, made spreadable: dominikkoller //@help: creates a tube-like strip of triangles with adjustable thickness #region usings using System; using System.ComponentModel.Composition; using VVVV.PluginInterfaces.V1; using VVVV.PluginInterfaces.V2; using VVVV.Utils.VMath; using VVVV.Core.Logging; #endregion usings namespace VVVV.Nodes { #region PluginInfo [PluginInfo(Name = "Rope", Category = "2D", Version = "Bin", Help = "Creates rope-like triangle strip vertices with adjustable thickness from given path coordinates", Tags = "", Author = "motzi, dominikkoller")] #endregion PluginInfo public class Rope2d : IPluginEvaluate { #region fields & pins [Input("Points", DefaultValue = 1.0)] public ISpread> FInput; [Input("Thickness", DefaultValue = 0.1)] public ISpread> FWidth; [Output("Vertices")] public ISpread> FOutput; [Output("Texture Coordinates")] public ISpread> FTexCoords; [Output("Factor", Visibility = PinVisibility.OnlyInspector)] public ISpread IFactor; [Import()] public ILogger FLogger; #endregion fields & pins public void Evaluate(int SpreadMax) { FInput.SliceCount = FWidth.SliceCount = FOutput.SliceCount = FTexCoords.SliceCount = IFactor.SliceCount = Math.Max(FInput.SliceCount, FWidth.SliceCount); for(int i=0; i output; Spread texCoords; double factor; Rope(FInput[i], FWidth[i], out output, out texCoords, out factor); FOutput[i].AssignFrom(output); FTexCoords[i].AssignFrom(texCoords); IFactor[i] = factor; } } public void Rope(ISpread input, ISpread width, out Spread output, out Spread outTexCoords, out double outFactor) { output = new Spread(); outTexCoords = new Spread(); outFactor = 0; // no vertices if(input.SliceCount < 1 || width.SliceCount < 1) { output.SliceCount = 0; outTexCoords.SliceCount = 0; outFactor = 0; return; } // Only one vertex else if(input.SliceCount == 1) { output.SliceCount = input.SliceCount; output[0] = input[0]; outTexCoords.SliceCount = 1; outTexCoords[0] = new Vector2D(0,0); outFactor = 1; return; } outFactor = 1.0 /(input.SliceCount-1); output.SliceCount = input.SliceCount * 2; outTexCoords.SliceCount = input.SliceCount * 2; Vector2D hn; int i, inIndex, outIndex, outTexCoord = 0; for (i = 1; i < input.SliceCount; i++) { inIndex = input.SliceCount - i; outIndex = (i-1) * 2; outTexCoord = i-1; hn = GetHalfNormal(input[inIndex], input[inIndex-1], width[inIndex-1]); output[outIndex] = input[inIndex] - hn; outTexCoords[outIndex] = new Vector2D(outFactor * outTexCoord,1); output[outIndex + 1] = input[inIndex] + hn; outTexCoords[outIndex + 1] = new Vector2D(outFactor * outTexCoord,0); } // last point --i; inIndex = 1; outIndex = i*2; hn = GetHalfNormal(input[inIndex], input[inIndex-1], width[inIndex-1]); output[outIndex] = input[inIndex - 1] - hn; outTexCoords[outIndex] = new Vector2D(1,1); output[outIndex+1] = input[inIndex - 1] + hn; outTexCoords[outIndex+1] = new Vector2D(1,0); } private Vector2D GetHalfNormal(Vector2D vertexOne, Vector2D vertexTwo, double width) { Vector2D halfnormal = vertexTwo - vertexOne; halfnormal = ~halfnormal; halfnormal = new Vector2D(-halfnormal.y * width * 0.5, halfnormal.x * width * 0.5); return halfnormal; } } }