MoI discussion forum
MoI discussion forum

Full Version: Parametric design in MoI?

Show messages:  1-15  …  276-295  296-315  316-335  336-355  356-375  376-395  396-415  …  896-912

From: mkdm
18 May 2016   [#336]
Hi everyone!

While waiting for new versions of Max's NodeEditor,
i'm doing some experiments with PatternArray selection :

Here's my current unfinished version of the node PatternSelectArray :

code:
// PatternSelectArray
function PatternSelArray()
{
	this.addInput("In","pointarray");
	this.addInput("Start","number");
	this.addInput("Qt_Max","number");
	this.addInput("Step","number");		
	
	this.addOutput("Out","pointarray");
	this.addOutput("Elems","number");
	this.addOutput("Source","pointarray");
	
	this.properties = { mode:["Pattern + Subset", "Pattern + Subset", "Subset + Pattern"],
		pattern:"+",
		start:0,
		qt_max:-1,
		step:1};
	
}

PatternSelArray.title = "PatternSelArray";
PatternSelArray.desc = "PatternSelArray";

PatternSelArray.prototype.onExecute = function()
{
	//if (this.properties.order[0] == "By Selection") {
		
	var source = this.getInputData(0, new pointArray());
	this.properties.pattern = this.properties.pattern.trim();
	
	var usePattern = false;
	var isMixedPattern = false;
	
	// check the pattern
	if (this.properties.pattern != '') {
		// check if pattern contains valid characters
		usePattern = this.properties.pattern.match('^[+\-0-1]+$');
		
		if (usePattern) {
			// check if pattern contains only include characters (+ or 1)
			usePattern = !this.properties.pattern.match('^[+1]+$');
			
			if (usePattern) {
				// if pattern contains both include and exclude characters, then the pattrn will be used
				// otherwise it means that contains only exclude characters (- or 0), and therefore
				// the output pointarray list will be empty
				isMixedPattern = !this.properties.pattern.match('^[\-0]+$');
			}
		}
	}

	var output = new pointArray(); // init to empty list

	if (usePattern) {
		if (isMixedPattern) {
			var len = source.getLength();
			var cn = 0;
			
			for (i = 0; i < len ; i++) {
				if ( this.properties.pattern[cn] === '1' || this.properties.pattern[cn] === '+') {
							
					var source_elem = source.getElement(i);
					
					output.push(source_elem.pt.x,
						source_elem.pt.y,
						source_elem.pt.z,
						source_elem.AngleX,
						source_elem.AngleY,
						source_elem.AngleZ,
						source_elem.Size);
				}
				cn = (cn < this.properties.pattern.length-1) ? cn+1 : 0;
			}
		}
	} else {
		// elaborate the whole source pointarray
		this.properties.pattern = '';
		output = source;		
	}

	var outLength = output.getLength();
	
	this.properties.start = this.getInputData(1, this.properties.start);
	if (this.properties.start < 0) this.properties.start = 0;
	if (this.properties.start > (outLength - 1)) this.properties.start = (outLength - 1);

	this.properties.qt_max = this.getInputData(2, this.properties.qt_max);
	if ((this.properties.qt_max < 0) || (this.properties.qt_max > outLength)) this.properties.qt_max = outLength;
	
	this.properties.step = this.getInputData(3, this.properties.step);
	if (this.properties.step <= 0) this.properties.step = 1;
	if (this.properties.step > outLength) this.properties.step = outLength;
	
	// generate the final pointarray list
	var outputFinal = new pointArray();
		
	for (i = this.properties.start, cont = 0; i < outLength && cont < this.properties.qt_max; i += this.properties.step, cont++) {
		var source_elem = output.getElement(i);
		
		outputFinal.push(source_elem.pt.x,
			source_elem.pt.y,
			source_elem.pt.z,
			source_elem.AngleX,
			source_elem.AngleY,
			source_elem.AngleZ,
			source_elem.Size);
	}
	
	output = null;
	
	this.setOutputData(0, outputFinal);
	this.setOutputData(1, outputFinal.getLength());
	this.setOutputData(2, source);
	
	this.outputs[1].label = "Elems(" + outputFinal.getLength() + ")";
}

LiteGraph.registerNodeType("Arrays/PatternSelArray", PatternSelArray);


The inputs and outputs are :

1 - In : the source PointArray
2 - pattern : the filter pattern string : 1 or + pick the element, 0 or - skip the element
Example "1001" or "+--+"

3 - Start : the first element index of the resulting array after the pattern filtering
4 - Qt_Max : Max quantity of elements present in the final output array
5 - Step : The step used while iterate over the patterned array

6 - Out : the final array
7 - Elems : the number of elements present in the final array
8 - Source : The initial source PointArray


Actually the node works in this way :

1) The pattern is applied to the source array
2) Start , Qt_Max and Step are used to iterate over the patterned PointArray

Actually the property "mode" is not used, but when activated,
will determine the order of the used logic :
First do Pattern operation and then Iterates
or
First Iterates and then do Pattern operation


Nice evening to all,


Marco.
From: James (JFH)
18 May 2016   [#337] In reply to [#334]
Hi Karsten

Great work!

I am totally onboard with your wrapping function for additional outputs proposal.
However could it be achieved with a two tiered menu as shown?
& removed in a similar method to the removal of additional inputs

This way the info panel is not further crowded with non-dynamic elements.

Just a thought
-James

Image Attachments:
Outputs.gif 


From: Karsten (KMRQUS)
18 May 2016   [#338] In reply to [#337]
Hello James,

I had the same idea also, but I could not get it to run:-( I don't understand the core stuff already. Every time I have a short look in it, I have to google for hours. Nevertheless I am still learning. The other reason why I switched back to a selection of the function in the info panel was, that I don't know a good way for multiple outputs (not implemented, but I think possible this way) So the code is only an experiment to explain the idea, not a real solution. I hope Max will implement such a feature. It would help to extend the nodeeditor with such basic functions in a simple way.

Have a nice day
Karsten
From: James (JFH)
18 May 2016   [#339] In reply to [#338]
Karsten/Max

I also think it would be useful to introduce a radio button associated to inputs as shown.
In the case of array nodes, range inputs could all be activated with cascade menu directly on node
or individually in info panel. It would be immediately apparent in the info panel which field has an
active input and which can be activated/deactivated if need be.

The simple remains simple; & the complex is possible

-James
From: mkdm
19 May 2016   [#340] In reply to [#339]
Hi James,

i agree with you.

It would be very useful having the possibility to use a bunch of classic input controls inside nodes,
like radiobuttons and checkboxes.

In my garbage time i'm testing some javascript code that goes in that direction.

But i think that until Max will not release a new updated version of Nodeeditor, all these idea are only valid as a javascript developing practise...

Nice day,

Marco.
From: mkdm
19 May 2016   [#341]
Hi everyone!

here's the new code of my "PatternSelArray" and "ArrayReplicator".

The attached pictures show a simple example.

If you find bugs and errors, please, let me know...

Nice evening to all,

Marco (mkdm)

code:
// PatternSelectArray
function PatternSelArray()
{	
	this.size = [160,70];
	this.minsize = [160,70];
	
	this.addInput("In","pointarray");
	this.addInput("Start_Idx","number");
	this.addInput("Qt_Max","number");
	this.addInput("Step","number");		
	
	this.addOutput("Out","pointarray");
	this.addOutput("Elems","number");
	this.addOutput("Source","pointarray");
	
	this.properties = { mode:["Pattern + Subset", "Pattern + Subset", "Subset + Pattern"],
		pattern:"",
		start_idx:0,
		qt_max:-1,
		step:1 };
	
}

PatternSelArray.title = "PatternSelArray";
PatternSelArray.desc = "PatternSelArray";

PatternSelArray.prototype.onExecute = function()
{		
	/*
		source = the source array
		start_idx = index of the first element to pick
		numMaxElem = max number of elements that will be present in the resulting array
		step = step amount for the for..loop
	*/
	var getPointArraySection = function(source, start_idx, numMaxElem, step) {

		var result = new pointArray();
		
		if (source) {
			var sourceLength = source.getLength();
			for (i = start_idx, cont = 0; i < sourceLength && cont < numMaxElem; i += step, cont++) {
				var source_elem = source.getElement(i);
				
				result.push(source_elem.pt.x,
					source_elem.pt.y,
					source_elem.pt.z,
					source_elem.AngleX,
					source_elem.AngleY,
					source_elem.AngleZ,
					source_elem.Size);
			}
		}
		return result;
	}

	/*
		source = the source array
		pattern = string that define the selection pattern
			1 or + = pick element
			0 or - = skip element
	*/	
	var applyPatternToPointArray = function(source, pattern)
	{
		function ResultObj(pattern) {
			this.array = new pointArray();
			this.pattern = pattern;
		}

		var usePattern = false;
		var isMixedPattern = false;			
		var result = new ResultObj(pattern);
		
		if (pattern) {
			result.pattern = pattern.trim();
			
			// check the pattern
			if (result.pattern != '') {
				// check if pattern contains valid characters
				usePattern = result.pattern.match('^[+\-0-1]+$');
				
				if (usePattern) {
					// check if pattern contains only include characters (+ or 1)
					usePattern = !result.pattern.match('^[+1]+$');
					
					if (usePattern) {
						// if pattern contains both include and exclude characters, then the pattrn will be used
						// otherwise it means that contains only exclude characters (- or 0), and therefore
						// the output pointarray list will be empty
						isMixedPattern = !result.pattern.match('^[\-0]+$');
					}
				}
			}
		}

		if (usePattern) {
			if (isMixedPattern) {
				var len = source.getLength();
				var patLen = result.pattern.length;
				var cn = 0;
				
				for (i = 0; i < len ; i++) {
					if ( result.pattern[cn] === '1' || result.pattern[cn] === '+') {
								
						var source_elem = source.getElement(i);
						
						result.array.push(source_elem.pt.x,
							source_elem.pt.y,
							source_elem.pt.z,
							source_elem.AngleX,
							source_elem.AngleY,
							source_elem.AngleZ,
							source_elem.Size);
					}
					cn = (cn < (patLen - 1)) ? (cn + 1) : 0;
				}
			}
		} else {
			// elaborate the whole source pointarray
			result.pattern = '';
			result.array = source;		
		}

		return result;
	}

	// Business logic
	var source = this.getInputData(0, new pointArray());
	
	this.properties.start_idx = this.getInputData(1, this.properties.start_idx);
	this.properties.qt_max = this.getInputData(2, this.properties.qt_max);
	this.properties.step = this.getInputData(3, this.properties.step);

	if (this.properties.step <= 0) this.properties.step = 1;
	
	var patternedArray;
	var outputIntermediate;
	var outIntermLength;
	
	if (this.properties.mode[0] == "Pattern + Subset") {
		patternedArray = applyPatternToPointArray(source, this.properties.pattern);		
		outputIntermediate = patternedArray.array;		
		outIntermLength = outputIntermediate.getLength();
	} else {
		outputIntermediate = source;
		outIntermLength = source.getLength();
	}

	if ((this.properties.start_idx < 0) || (this.properties.start_idx > (outIntermLength - 1))) this.properties.start_idx = 0;
	
	if (this.properties.qt_max < 0) this.properties.qt_max = outIntermLength;
	
	outputIntermediate = getPointArraySection(outputIntermediate,
						this.properties.start_idx,
						this.properties.qt_max,
						this.properties.step);

	if (this.properties.mode[0] == "Subset + Pattern") {
		patternedArray = applyPatternToPointArray(outputIntermediate, this.properties.pattern);
		
		outputIntermediate = patternedArray.array;
		
		outIntermLength = outputIntermediate.getLength();
	}
						
	this.properties.pattern = patternedArray.pattern;
	patternedArray = null;
	
	this.outputs[0].label = "Out (" + outputIntermediate.getLength() + ")";
	this.outputs[1].label = "Elems (" + outputIntermediate.getLength() + ")";
	this.inputs[0].label = "In (" + source.getLength() + ")";
	
	this.setOutputData(0, outputIntermediate);
	this.setOutputData(1, outputIntermediate.getLength());
	this.setOutputData(2, source);
	
}

LiteGraph.registerNodeType("Arrays/PatternSelArray", PatternSelArray);

// ArrayReplicator
function ArrayReplicator()
{
	this.labels = "abcdef";
	this.size = [140,40];
	this.minsize = [140,40];

	this.internal = {a:1, b:1};
	
	this.addInput("In","pointarray");
	
}

ArrayReplicator.title = "Array Replicator";
ArrayReplicator.desc = "Array Replicator";

ArrayReplicator.prototype.onGetOutputs = function()
{
	var list = [];
	for ( var i = 0; i<this.labels.length; i++ )
	{
		var out = this.labels.charAt(i);
		if ( !(out in this.internal)) { list.push([this.labels.charAt(i),"pointarray", {locked:true}]); break; }
	}
	return list;
}

ArrayReplicator.prototype.onOutputAdded = function(out)
{
	this.internal[out.name] = 1;
	for ( var i in this.outputs ) this.outputs[i].locked = true;
	if (i>1) this.outputs[i].locked = false;
}

ArrayReplicator.prototype.onOutputRemoved = function(slot, name)
{
	if ( this.internal[name] ) delete this.internal[name];
	for ( var i in this.outputs ) this.outputs[i].locked = true;
	if ( this.outputs.length > 2 )this.outputs[i].locked = false;
}

ArrayReplicator.prototype.onAdded = function()
{
	for ( var i = 0; i<this.labels.length; i++ ) if ( this.internal[this.labels.charAt(i)] && this.outputs.length == i ) this.addOutput(this.labels.charAt(i), "pointarray");
	this.setDirtyCanvas(true);
}

ArrayReplicator.prototype.onExecute = function()
{
	var source = this.getInputData(0, new pointArray());

	this.inputs[0].label = "In (" + source.getLength() + ")";
	
	for ( var i = 0; i<this.outputs.length; i++)
	{
		this.setOutputData(i, source);
	}	
}

LiteGraph.registerNodeType("Arrays/ArrayReplicator", ArrayReplicator);

Image Attachments:
01_Capture.PNG  02_Capture.PNG 


From: Frenchy Pilou (PILOU)
19 May 2016   [#342]
Cool thing to have all possible nodes in one wink!
From: Max Smirnov (SMIRNOV)
20 May 2016   [#343]
Hi guys!
Sorry, I didn't write a line of code this week. I was so busy at work.
Maybe next week I'll continue developing of this project.

Marco, this ArrayReplicator looks good, but it will be better if we use a multiple output connections. ;)
From: mkdm
20 May 2016   [#344] In reply to [#343]
Hi Max,

> Marco, this ArrayReplicator looks good, but it will be better if we use a multiple output connections. ;)

I totally agree with you!

While waiting your next NodeEditor release, i'm still playing with array nodes, and after "PatternSelArray" and "ArrayReplicator",
i'm thinking to write :
- "ArrayShuffler" : shuffle the elements inside one array
- "ArrayInspector" : it should output to a textarea, the numeric values of all array elements. Useful for debugging purposes.
- "ArrayExporter" : it should output to a file, the numeric values of all array elements.
- "RandomArray" : In should generate random points inside a 3d cube area.

These ideas are nothing more then a funny and simple javascript programming practice for me,
simple ideas that you might find interesting.

Nice night to all,

Marco.
From: Karsten (KMRQUS)
20 May 2016   [#345] In reply to [#343]
Hello Max,

the main thing , you are well . I enjoy the break:-)

Have a nice weekend
Karsten
From: bemfarmer
25 May 2016   [#346]
Here is a lighter color for the Canvas.
Under nodeeditor/core/imgs, save the original grid.png, and replace it with the lighter grid.png.

The colors of the original grid was inverted. This was done with Gimp2, or with Greenfish Icon Editor Pro (GFIE).
The lighter colors were swapped with GFIE. GFIE does not compress the PNG, so PNGGauntlet was used to shrink the PNG file size.

A button to select the grid colors might be nice, as well as an even lighter grid for printing.

- Brian (Grid.png removed as it is no longer used.)



From: bemfarmer
27 May 2016   [#347] In reply to [#346]
I made an even lighter grid, but the cursor is almost invisible. :-(

The few icon/png editors I've tried have been difficult to use as well.

- Brian
From: bemfarmer
27 May 2016   [#348] In reply to [#346]
. So how do I delete a message?

- Brian
From: Michael Gibson
27 May 2016   [#349] In reply to [#348]
Hi Brian,

re:
> . So how do I delete a message?

In the bottom right corner of a message there's a "more" link and if you click it a menu will pop out with a "Delete" link on it.

If that doesn't work, just give a link to the message you want to delete and I can do it for you too.

- Michael
From: bemfarmer
27 May 2016   [#350] In reply to [#349]
Thank you Michael.
(I've been unable to delete from the edit window.)
From: Karsten (KMRQUS)
27 May 2016   [#351] In reply to [#348]
Hello Brian,
dont't delete the message. The cursor can be customized with e.g. Gimp. Take a cursor example (also png) from this thread and change form and color and share it also, please.

Have a nice day
Karsten
From: bemfarmer
28 May 2016   [#352] In reply to [#351]
To switch to an arrow cursor, locate the litegraph.css file under nodeeditor\css\, and change "crosshair" to "default", without the quote marks.
(Line 4)

https://css-tricks.com/almanac/properties/c/cursor/

Attached is a lighter grid.png replacement for the canvas. In the canvas display it still seems to be relatively dark.

The Wand selector of the Greenfish Icon editor cannot distinguish between two different tints and/or tones and/or shades, which are nearly the same .
This makes it hard to select the proper areas of the grid.png for editing.

The Wand selector of the IcoFX2 icon editor can so distinguish, but does not do Hex colors. Setting one of the two colors of Grid.png to a very different color allows the .png to be edited in the Greenfish Icon editor, which does do Hex colors.

- Brian

Grid.png removed as no longer needed.
From: mkdm
30 May 2016   [#353]
Hi everyone,

While waiting the next official NodeEditor release by Max, here's my the first stable version (0.1) of some nodes i wrote :

N.B. these nodes requires the latest v.0.65b version of Max's NodeEditor.

- "PatternSelArray" : returns a PointArray, made by a patterned+subset selection of the input PointArray's element

- "ArrayShuffler" : returns a PointArray, by shuffling the elements inside the input PointArray (RMB -> Update : generate a new random shuffle)
For example, it may be useful to create objects like ball of wool.

- "ArrayFlipper" : returns a PointArray, made by flipping the elements of the input PointArray

- "ArrayLogger" : Outputs to a textarea the content of the input PointArray. It's useful for debugging.
You can copy/paste the textarea's content, to a text editor, in order to better view all the text.
Every line of text contains the full data of each point present in the input PointArray, separated by a single space :
X Y Z AngleX AngleY AngleZ Size

- "ArrayReplicator" : Replicates the input PointArray. It may be useful only in order to keep the graph cleaner.

In order to use these new nodes, follow these steps :

1) copy the "arraysExt.js" file into the "nodes" folder of NodeEditor
2) copy the "litegraphExt.js" file into the "core" folder of NodeEditor
3) add these lines of code to the "index.html" file of NodeEditor

code:
<script type="text/javascript" src="core/litegraphExt.js"></script>
<script type="text/javascript" src="nodes/arraysExt.js"></script>


I hope that you will find these nodes useful.

Please, let me know if you will find bugs.

Nice day to all!

Marco (mkdm)

Attachments:
arraysExt.js
ArraysExt_001.nod
ArraysExt_002.nod
litegraphExt.js

Image Attachments:
00_Capture.png  01_Capture.png  02_Capture.png  03_Capture.png 


From: Karsten (KMRQUS)
31 May 2016   [#354] In reply to [#353]
Hello Marco,

Thank You very much for sharing. I have tested some nodes and for now, everything works fine. Especially the ArrayLogger will help to debug while programming and also while using the nodeeditor. I'm very curious what's comming next.

Have a nice day
Karsten
From: mkdm
31 May 2016   [#355] In reply to [#354]
Hi Karsten,

I'm glad to know that you appreciated my little contribution and also that you haven't found some strange bugs...

Currently i'm working on a node that will be called "ArraySketcher".
It will process a PointArray and, following some criteria, it will use the array elements to draw some basic geometry objects :

"Triangles", "Quads", "Curve", "Interpcurve", "Arc3pt", "Circle3pt", "Rect3pts", "EllipseDiam","EllipseCen" and some others...

I also wrote "PatternSelObjects" node, that does the same things of "PatternSelArray", but with it,
it's possible to operate on a ObjectList rather than a PointArray.

I hope to post soon these new nodes.

Thank you for your reply and have a nice day!

Marco (mkdm).

Show messages:  1-15  …  276-295  296-315  316-335  336-355  356-375  376-395  396-415  …  896-912