General technical questions about v3 Moi's API
 1-20  21-26

Next
 From:  mkdm
8010.1 
Hi Michael,

How are you ? I hope you're okay.

I'm trying to put together a bunch of javascript code in order to write a NodeEditor's node that should let the user to
filter a given set of curves, depending on some filtering criteria.

I need to check if a curve is a single curve, opened or closed doesn't matter, or if the curve is a multisegmented one,
and i need also to iterate over the curve's segments.

Looking into the Api's documentation i've found the getStandaloneCurves() method and the CurveSegment class,
but using the first i didn't get the wanted results and the second one seems to be undocumented.
(source http://moi.maxsm.net/api/)

Could you point me in the right direction ?

Thanks a lot and have a nice day.

Marco (mkdm).
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.2 In reply to 8010.1 
Hi Marco, I'm doing fine here, hope things are well with you!

re: Iterate segments of a curve, you can use crv.getSubObjects() for that, it will return an object list with the curve's segments in it.

So something like:

var segs = crv.getSubObjects();

if ( segs.length == 1 ) it's a single segment curve.

if ( segs.length > 1 ) i'ts a multi-segment curve.


The getSubObjects() method is a part of the base geometry object interface, it works on either curves to get the segments of the curve, or on breps to get the faces, curves, and segment sub-objects of the Brep. An edge curve in a Brep always has just one segment.

Hope this helps!

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.3 In reply to 8010.2 
Hi Michael,

I'm fine too, thanks.

Thank you very much for your reply, that's just what i was hoping for!

Now i can complete the node that i'm writing.

But...just out of curiosity....
What about the getStandaloneCurves() method and the CurveSegment class ?

Thanks again for all.

Marco (mkdm)
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.4 In reply to 8010.3 
Hi Marco, I'm glad that does what you need!

re: getStandaloneCurves() - that's a filtering method on an object list - when you call this method it will go through the object list and find all standalone curves and return a new object list with just those filtered objects in it. A "Standalone curve" is a curve that is its own independent top level object, which is distinct from an edge curve which is part of the structure of a surface or solid. When you create a curve using the "Draw curve" tools for example, those are standalone curves. The plain getCurves() method will target any kind of curve, either an independent curve object, or also edge curves.

re: CurveSegment - that's the script interface class for a curve segment object which are owned by Curves. In MoI curve segments can't be selected individually, you select Curve objects which can be made up of one or more segments. Because they are not part of the selection process there aren't as many script functions that target curve segments except for that getSubObjects() method.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.5 In reply to 8010.4 
Hi Michael,

please help! I think that i spoke too soon (:

In order to fill the output of the node that i'm writing, i'm doing something like this (in pseudo-code) :

code:
var output = moi.geometryDatabase.createObjectList();
...
some filtering logic
...

... all inside the main for loop....

var subObjs = <current curve object>.getSubObjects();

for ( var i2 = 0; i2 < subObjs.length; i2++ ) {
	var addSegCurve = false;

	if (segCurves.item(i2) "passes the filtering criteria") {
		addSegCurve = true;
	}
	
	if (addSegCurve) {
		output.addObject(subObjs.item(i2));
	}
}



The problem is that the line "output.addObject(subObjs.item(i2));" seems to add an incompatible object to the output ObjectList.

What i'm doing wrong ?

It's "<current curve object>.getSubObjects().item(<index>)" a valid curve object ?

That is....Should i convert a CurveSegment object into a Curve object ? If so, how to do that ?

Marco (mkdm).
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.6 In reply to 8010.5 
Hi Marco,

> The problem is that the line "output.addObject(subObjs.item(i2));" seems to add an
> incompatible object to the output ObjectList.

Could you be more specific about the problem - does that line trigger an exception with an error message being displayed? If so, please show the message.

When you say "incompatible" what are you referring to - incompatible to what specifically? What is it that you're trying to do with the object list that you have gathered the segments into?

If it's to run as an input to a geometry factory then yes that is not likely to work because commands are expecting to receive curve objects and not the lower level curve segments.

But I think one way you could convert curve segments into independent curve is using the Edit > Separate command, see Separate.js for an example. I forget what happens if you run separate on a single segment curve, if it skips those then you would need to use crv.clone() on single segment curves instead.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.7 In reply to 8010.6 
Hi Michael,

First of all i wish to thank you for your support.

After following your suggestions i produced a first working version of my javascript code.

Here's are the core javascript line codes :

code:
var input = this.getInputData(0, moi.geometryDatabase.createObjectList()); // take the input from NodeEditor
var output = moi.geometryDatabase.createObjectList();

var curves = input.getCurves();

for (var i = 0;  i < curves.length; i++) {

	var subObjs = curves.item(i).getSubObjects();

	if (subObjs.length > 1) {
		var objListTmp = moi.geometryDatabase.createObjectList();
		objListTmp.addObject(curves.item(i));

		// separate the multisegmented curve, using the NodeEditor's wrapper factory() method
		// Just for info, it simply calls the Moi's createFactory() method as shown below :
		// function factory( factoryname ) { var f = moi.command.createFactory( factoryname ); for ( var i = 1; i < arguments.length; i++ ) if (arguments[i] !==null) f.setInput( i - 1, arguments[i] ); var obj = f.calculate(); f.cancel(); return obj; }		
		
		var segCurves = factory('separate', objListTmp);

		for ( var i2 = 0; i2 < segCurves.length; i2++ ) {
			var addSegCurve = false;
			
			// INIT OF MY FILTERING CRITERIA BASED ON LENGTH
			if (this.properties.maxL != this.properties.minL) {
				if (this.properties.minL == 0) {
					addSegCurve = (segCurves.item(i2).getLength() > this.properties.minL);
				} else {
					addSegCurve = (segCurves.item(i2).getLength() >= this.properties.minL);
				}
				if (this.properties.maxL > 0) {
					addSegCurve = addSegCurve && (segCurves.item(i2).getLength() <= this.properties.maxL);
				}
			} else {
				if (this.properties.minL == 0) {
					addSegCurve = true;
				} else {
					addSegCurve = (segCurves.item(i2).getLength() == this.properties.minL);
				}
			}
			// END OF MY FILTERING CRITERIA BASED ON LENGTH
			
			if (addSegCurve) {
				output.addObject(segCurves.item(i2));
			}						
		}
	}
}


But it seems that this is the only working code...

> I forget what happens if you run separate on a single segment curve, if it skips those then you would need to use crv.clone() on single segment curves instead.

I tried both methods :

1) Trying to directly clone the curve's sub segment : var x = subObjs.item(y).clone();
It generates an error : Moi's message is "Exception occurred"

2) Trying to run the "separate" factory command on a single curve segment but it generates an empty ObjectList and i get the same "Exception occurred" :
code:
for ( var i2 = 0; i2 < subObjs.length; i2++ ) {
	var objListTmp = moi.geometryDatabase.createObjectList();
	objListTmp.addObject(subObjs.item(i2));

	var segCurves = factory('separate', objListTmp);

	moi.UI.alert(segCurves.length);

	output.addObject(segCurves.item(0)); // generate exception 'cause the ObjectList is empty
}



So, only the first block of code seems to work.

Am i doing something wrong with the other approaches ?

Thank you very much for you patience and have a nice day!

Marco (mkdm).
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.8 In reply to 8010.7 
Hi Marco, for the single segment case you need to call .clone() on the parent curve object, not on the segment. Segments are not meant to exist outside of their parent curve, and so they don't respond to obj.clone() directly themselves.

Try this:

code:

function IsMultiSegment( crv )
{
	return crv.getSubObjects().length > 1;
}

function MakeSegmentCurves( crvlist  )
{
	var output = moi.geometryDatabase.createObjectList();

	// Separate input into 2 lists, one for single segment curves, and another for multi-segment curves.

	var single_seg_crvs = moi.geometryDatabase.createObjectList();
	var multi_seg_crvs = moi.geometryDatabase.createObjectList();
	
	for ( var i = 0; i < crvlist.length; ++i )
	{
		var crv = crvlist.item(i);
		
		if ( IsMultiSegment( crv ) )
			multi_seg_crvs.addObject( crv );
		else
			single_seg_crvs.addObject( crv );	
	}
	
	// For single segment curves, call crv.clone() to duplicate it.
	
	for ( var i = 0; i < single_seg_crvs.length; ++i )
	{
		var crv = single_seg_crvs.item(i);
		var newcrv = crv.clone();
		output.addObject( newcrv );
	}
	
	// For multi segment curves, use the separate factory to construct a new curve for each segment.
	
	var factory = moi.command.createFactory( 'separate' );
	factory.setInput( 0, multi_seg_crvs );
	
	var separated_crvs = factory.calculate();
	factory.cancel();
	
	for ( var i = 0; i < separated_crvs.length; ++i )
	{
		var crv = separated_crvs.item(i);
		output.addObject( crv );	
	}
	
	return output;
}

function TestGetSegments()
{
	var output = moi.geometryDatabase.createObjectList();

	var crvs = moi.geometryDatabase.getSelectedObjects().getCurves();
	if ( crvs.length == 0 )
	{
		moi.ui.alert( 'Select a curve before running this command.' );
		return;
	}
	
	var crvsegs = MakeSegmentCurves( crvs );
	
	moi.ui.alert( crvsegs.length );	
}	

TestGetSegments();




Hope this helps!

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.9 In reply to 8010.8 
Hi Michael,

Thank you for these clarifications.

> Hi Marco, for the single segment case you need to call .clone() on the parent curve object, not on the segment. Segments are not meant to exist outside of their parent curve, and so they don't respond to obj.clone() directly themselves.

You're right! I realised that i misunderstood your previous reply regarding the use of the .clone() method on a curve's segment.

I apprechiated the clean and educational style of the code that you posted in your last reply, but looking at it more deeply,
i noticed that is, more or less, what i already wrote in my previous post (http://moi3d.com/forum/index.php?webtag=MOI&msg=8010.7).

I simply used the 'separate' factory command not directly, but with the help of the "factory()" method defined inside the NodeEditor.

code:
// separate the multisegmented curve, using the NodeEditor's wrapper factory() method
// Just for info, it simply calls the Moi's createFactory() method as shown below :
// function factory( factoryname ) { var f = moi.command.createFactory( factoryname ); for ( var i = 1; i < arguments.length; i++ ) if (arguments[i] !==null) f.setInput( i - 1, arguments[i] ); var obj = f.calculate(); f.cancel(); return obj; }


And regarding the cloning of the objects, before putting them in the output ObjectList, this is implicitly done again by the "output" node of the NodeEditor.

Finally, after some tests, i confirm that calling the "separate" factory command directly on a curve's segment, generates an empty ObjectList .

Thank you again for all your technical clarifications and have a nice day!

Marco (mkdm).
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.10 In reply to 8010.9 
Hi Marco, you're welcome!

> I apprechiated the clean and educational style of the code that you posted in your last reply, but
> looking at it more deeply, noticed that is, more or less, what i already wrote in my previous post

Yes, but sorry I wasn't entirely sure which exact part you were having a problem with, so I wanted
to provide you with a complete working version for reference just in case.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.11 In reply to 8010.10 
Hi Michael,

> so I wanted to provide you with a complete working version for reference just in case.

In doing so you did the right thing!

Thanks again.

I know that this is mainly a modeling related forum and not a developer forum,
but i must admit that, since i'm first of all a software developer it's really funny for me,
in my garbage time, playing with javascript and Moi's Api.

If only i had a better mathematical knowledge...but it's not my field.

So, I take this opportunity to address a question to you, that I have in mind for a long time.

I suppose that It's not long before the first public beta of Moi V4,
but i want to ask you if you could release a very tiny intermediate upgrade of the current Moi V3's DLL (API),
in order to provide one method that given a curve as input, would return an Array of points,
representing the CONTROL POINTS of the curve itself.
And maybe would return also another Array of points, representing the KNOTS POINTS of the curve.

I think that this wouldn't be a big effort for you, while it would be a BIG big improvement for all us, as regards in writing utility scripts.

Do you think that this is a reasonable request ?

I hope so.

Anyway, all good wishes for your work!

Ciao.

Marco (mkdm)
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.12 In reply to 8010.11 
Hi Marco, it's a pretty big effort for me to release new versions like that for individual special requests. I'm sorry but you'll have to wait until the v4 betas until I'll be able to add control point access for scripting. Just one example - I don't have any way to distribute a new version like that other than rebuilding the full official release, it would not work for me to post something like that on the forum because I don't want people who make cracked versions of MoI to have easy access to the full version binary.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.13 In reply to 8010.12 
Ok Michael,

I understand your point of view...

Well...i'll wait the V4 betas!

Again, all good wishes for your work.

Marco (mkdm)
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.14 In reply to 8010.11 
Hi Marco, one possibility for getting low level access to a curve's control points and knots right now would be to export your curve to 3DM format, and then write a c++ helper .exe program that would read the 3DM file and write out the data you need to a text file that could then be read in by your script.

You can open 3DM files in your own c++ program using the OpenNURBS library which is available from here: http://opennurbs.org/

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.15 In reply to 8010.14 
Hi Michael,

Thanks a lot for this suggestion!

I think that it should be pretty easy to do a thing like that.
I hope to get some time off work, to take a look at the docs of http://opennurbs.org/

Maybe it would be better for me if I could use Java instead C++, but anyway i think it's more or less the same thing.

Thanks!

Marco (mkdm)

P.S. i see in http://opennurbs.org/ that it's possible to use the .NET framework also. Good thing!
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.16 In reply to 8010.14 
Hi Michael,

Considering that i own a commercial version of Rhino V5, i'm thinking that i could also use Rhino + Grasshopper and Rhino Script Compiler for Rhino5.
(for example i saw that Grasshopper has a ControlPoints component that extracts the nurbs control points and knots of a curve.)

Maybe it could be a good idea...

Ciao!

Marco (mkdm)
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.17 In reply to 8010.14 
Hi Michael,

Regarding the possibility to easily access curves' control points, i've found a solution that has always been in front of me!

I've written a modified version of Max's DelCorners script, that simply given a bunch of selected curves as input,
creates a bunch of new point objects, automatically selected, representing the selected curves' control points.

I'm aware that this is a simple solution that doesn't allow me to access to the control points' data,
as said by you in your post (http://moi3d.com/forum/index.php?webtag=MOI&msg=6890.5)

> Hi Andrei, Max's script works by doing a "select all" and then a copy to the clipboard of the points and then a paste back in of those points.
> That is indeed a way for a script to access the points without there being a proper script interface, but it's limited in what it can recover,
> it only gets a big bunch of points and isn't able to access additional information like being able to determine
> which particular points are actually corner points or not.

> Just in general it's difficult to make scripts that do control point manipulation since things
> are not currently set up to make all the information about the points accessible to a script.

Here's my code :

code:
// ExtractCurvesControlPoints.js v.0.1 - Marco Di Mario (mkdm), 2016
// based on :
// 		Max Smirnov's DelCorners, v.1.0.2015.09.09

// Given a bunch of selected curves as input, creates a bunch of new point objects, automatically selected,
// representing the selected curves' control points.


function extractCurvesControlPoints() {
	var gd = moi.geometryDatabase;	

	var obj = gd.getObjects(); // get all the objs
	
	var selCurves = gd.getSelectedObjects().getCurves(); // get all the selected curves
	
	if (selCurves.length == 0) {
		moi.UI.alert("At least one curve must be selected!");
		return;
	}
	
	// 1 - deselect everything and turn off all control points
	obj.setProperty('selected', 0);
	obj.setProperty('showPoints', 0);
	
	// 2 - turn on control points on selected curves
	selCurves.setProperty('showPoints', 1);
	
	// 3 - select all the objs
	gd.selectAll();
	
	// 4 - doing so, only all control points remains selected.
	// In this case, the control points of the selected curves
	obj.setProperty('selected', 0);
	
	// 5 - doing so only the control points will be copied and then pasted.
	// Pasted objects are automatically selected
	gd.copyToClipboardCommand( selCurves );	
	gd.pasteFromClipboard();
	
	// 6 - turn off control points on selected curves
	selCurves.setProperty('showPoints', 0);
	
	// As final result, we have now a bunch of new point objects, automatically selected,
	// representing the selected curves' control points!

}

extractCurvesControlPoints();



The ExtractCurvesControlPoints.zip file contains a 3dm example file that can be useful to test the script.

The ExtractCurvesControlPoints.js file can be equally copied to "commands" or "scripts" folder.

I've written this script also for using it together with some NodeEditor's nodes that i'm writing
and that i hope to post as soon as possible.

For example one of these, called "ArrayRemDupl", can be used to remove duplicated points.
That is, given a PointArray and a distance, this node returns a new PointArray, containing only
all the original points, far from each other at least the given distance.

Anyway....thank you for all and have a nice day!

Ciao.

Marco (mdkm).

  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.18 In reply to 8010.17 
Hi Marco, yeah Max figured out that you can use the copy/paste function to extract control points since that duplicates the control points as point objects.

But be aware that it's not exactly a general solution, there is more to the definition of a curve than just control points (there are also values for degree, weights, and knot vector) and so if you try to build a new curve from those points alone it won't necessarily be the same curve as the one you extracted the points from except in the case of what's called a "uniform" curve. But Draw curve > Freeform > Control points does make a uniform curve.

- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  mkdm
8010.19 In reply to 8010.18 
Hi Michael,

You're right, as usual.

In fact, as said in my previous post, I'm aware that this is a simple solution that doesn't allow me to access to the control points' data.

But for the moment, since i'm overwhelmed at work and have i no time to take a look at the openNURBS library,
it's enough for me to get a bunch of simple point objects in order to elaborate them with the utility nodes that i'm writing,
dedicated to the elaboration of PointArrays.

But, it would be very interesting for me at least having the possibility to recognize which of the control points extracted, are real SHARP points.
This could make me a qualitative leap into the elaboration of those points.

So I'm wondering if some of the javascript code, present in your "fillet" commands, could lead me in that direction.
I saw that, given a single StandaloneCurve selected, the "fillet" command starts by showing
the CORNER points present in that curve.

Maybe i can get these CORNER points for recognize them inside the code of my ExtractCurvesControlPoints.js,
in order to, for example, reconstruct the original curve leaving intact at least the original SHARP points.

Maybe....

What do you think about it ? It is a feasible thing, to use a portion of the javascript code in your "fillet" command ?

Thank you for your support and...Ciao!

Marco (mkdm)
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged

Previous
Next
 From:  Michael Gibson
8010.20 In reply to 8010.19 
Hi Marco, yes I think it's possible to use the Fillet factory to get corner points, there is a custom method .generateVertices() on the fillet factory, you can use it like this to get an object list of point objects, one at each sharp corner of the curve:

code:

function GetCorners( crvs )
{
	var factory = moi.command.createFactory( 'fillet' );
	
	factory.setInput( 0, crvs ); // Set an object list with one curve in it.
	factory.generateVertices();

	var corners = factory.getCreatedObjects();
	
	factory.cancel();
	
	return corners;
}

function TestGetCorners()
{
	var crvs = moi.geometryDatabase.getSelectedObjects().getCurves();
	if ( crvs.length != 1 )
	{
		moi.ui.alert( 'Select a curve before running this command.' );
		return;
	}
	
	var corners = GetCorners( crvs );
	
	moi.ui.alert( 'Got ' + corners.length + ' corners' );
}	

TestGetCorners();



- Michael
  Reply Reply More Options
Post Options
Reply as PM Reply as PM
Print Print
Mark as unread Mark as unread
Relationship Relationship
IP Logged
 

Reply to All Reply to All

 

 
Show messages:  1-20  21-26