The Origin Forum
File Exchange
Try Origin for Free
The Origin Forum
Home | Profile | Register | Active Topics | Members | Search | FAQ | Send File to Tech support
Username:
Password:
Save Password
Forgot your Password? | Admin Options

 All Forums
 Origin Forum for Programming
 Forum for Origin C
 get graphic object properties
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic Lock Topic Edit Topic Delete Topic New Topic Reply to Topic

couturier

France
291 Posts

Posted - 08/29/2017 :  02:47:54 AM  Show Profile  Edit Topic  Reply with Quote  View user's IP address  Delete Topic
Origin Ver. and Service Release (Select Help-->About Origin): 2017 SR2
Operating System:win10 64bit

Hi,

I have a bunch of vertical lines (more than a thousand) from which I want to get the color and the X value.
Line names are line1, line2, ...
Sor far, I've used LT:

dataset ds1, ds2;
int nLine=0;
doc -e G {
if (%[%b,1:4]=="line") {
nLine++;
ds1[nLine]=%b.x1;
ds2[nLine]=%b.color;
};
};

To make things faster, I've tried to write this part in OC:
int Get_Line_Info(vector& vecX, vector& vecCol)
{
vector v1, v2;
int n=0;
GraphLayer gly = Project.ActiveLayer();
if( gly.IsValid() )
{
fpoint ptNode;
foreach (GraphObject grobj in gly.GraphObjects)
{
string str1=grobj.GetName();
string str2=str1.Mid(0, 4);
if (str2=="Line")
{
grobj.GetNode(0, ptNode);
v1.SetSize(n+1);
v1[n]=ptNode.x;
v2.SetSize(n+1);
Tree trFormat;
trFormat = grobj.GetFormat(FPB_ALL, FPB_ALL, TRUE, TRUE);
v2[n]=trFormat.Root.Color.nVal;

n++;
}
}
}
vecX=v1;
vecCol=v2;
return n;
}

The OC function works but is about 2 times slower than LT.
Most of the time is spent in getting the color info from the tree.

Is there a way to significantly speed things up ?

Thanks

yuki_wu

896 Posts

Posted - 08/30/2017 :  04:28:12 AM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
Hi,

I modified your OC code a little bit:

void GetLineInfo()
{
	vector vX, vColor;
	
	GraphLayer gl = Project.ActiveLayer();
	if(gl)
	{
		foreach(GraphObject grobj in gl.GraphObjects)
		{
			if(grobj.GetObjectType() == "Line")
			{
				vX.Add(grobj.X);
				Tree trFormat;
				trFormat = grobj.GetFormat(FPB_STYLE_COLOR, FOB_ALL, TRUE, TRUE);
				vColor.Add(trFormat.Root.Color.nVal);
			}
		}
	}
}


In fact, you don’t have to get the whole format tree since you only want to know what color it is. Also, the second bit should be FOB_* not FPB_*. For bit description, you can find it in OC_const.h.

Hope it helps.

Regards,
Yuki
OriginLab

Go to Top of Page

couturier

France
291 Posts

Posted - 08/30/2017 :  12:41:08 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
Thanks a lot for your help.

I have simplified things for the example but objects' name are different and I must check their names because there might be other lines I dont care about.

I didn't recall of the Add method, instead of setting size in each iteration. Much more elegant, even if it didn't make a significant diff in time execution.

One issue in your script is that grobj.X seem to read screen X, instead of real X.

One of the main issue in my script was retrieving the whole tree.

I mixed your script, mine and GetSpecialGraphicObjectsCollection method and get a faster time execution.
Go to Top of Page

rdremov

USA
28 Posts

Posted - 08/30/2017 :  3:42:32 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
This LT script speed is not simple to beat. It has few lines and fast built in collection. Also, LT speed was greatly improved some time ago, such that it does not parse on every iteration anymore.

Now, OriginC is using XML tree, which is string based and has big overhead. However, here is my code which beats LT speed:


#include <../Originlab/okThemeID.h>
void GetLineInfo3()
{
	vector<double> vX;
	vector<int> vColor;
	
	GraphLayer gl = Project.ActiveLayer();
	if(gl)
	{
		Tree trFormat;
		trFormat = gl.GetFormat(FPB_STYLE_COLOR|FPB_DATA, FOB_LINES, FALSE, TRUE);
		TreeNode trLines;
		if(octree_theme_tree_get_node_by_id(&trLines, &trFormat, OTID_LINES, 1, true))
		{
			int nCount = trLines.Children.Count();
			vX.SetSize(nCount);
			vColor.SetSize(nCount);
			int nIndex = 0;
			vector<double> xx;
			TreeNode trData, trX, trColor;
			foreach(TreeNode trLine in trLines.Children)
			{
				trData = trLine.FindNodeByAttribute(STR_ID_ATTRIB, OTID_ANCHOR_DATA, false);
				if(trData)
				{
					trX = trData.FindNodeByAttribute(STR_ID_ATTRIB, OTID_ANCHOR_DATA_X, false);
					if(trX)
					{
						xx = trX.dVals;
						vX[nIndex] = xx[0];
					}
				}
				trColor = trLine.FindNodeByAttribute(STR_ID_ATTRIB, OTID_LINE_COLOR, false);
				if(trColor)
					vColor[nIndex] = trColor.nVal;
				nIndex++;
			}
		}
	}
}


As you can see I call GetFormat only once. I set filter to get only data and colors and only for Line objects. I preset vector sizes to children count before the loop to avoid memory re-allocations. Also, I skip on node name strings in favor of faster IDs.

These optimization results in 125ms (OriginC) vs 187ms (LT) on my computer.

It should be possible to improve it more by eliminating FindNodeByAttribute assuming rigid tree structure, not sure if worth it.
Go to Top of Page

rdremov

USA
28 Posts

Posted - 08/30/2017 :  5:33:51 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
quote:
Originally posted by couturier


I did more measuring with lines1000.opj. Out of 125ms total time of GetLineInfo3 about 80ms is the GetFormat call time. This means other optimization in GetLineInfo3 will lead to diminishing results, as it can not be better than GetFormat time. This timing is based on my computer and Origin 2017sr2 release build.

However, if you try Origin 2018 results are much better. GetFormat only takes 25ms on the same pc, which means 3x improvement in speed. This must be due to the fact that Origin 2017 and earlier were using msxml.dll for XML processing, while Origin 2018 is not anymore. It has faster XML engine.

Edited by - rdremov on 08/30/2017 5:36:18 PM
Go to Top of Page

cpyang

USA
1406 Posts

Posted - 08/30/2017 :  8:33:36 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
quote:
Originally posted by couturier
....
One issue in your script is that grobj.X seem to read screen X, instead of real X.
....




Can you be more specific? I tried the following simple code with a vertical line on a graph

void test(string strName = "line")
{
    GraphLayer        gl = Project.ActiveLayer();
    GraphObject        grobj;
    grobj = gl.GraphObjects(strName);
    out_double("X = ", grobj.X);
}


I get the same X as LT "line.x=", regardless of the line's attachment.
I remember we had issue with this a long time ago.


Separately, I have added JIRA https://originlab.jira.com/browse/ORG-16946 for general access to all the LabTalk properties available to GraphObject.


CP

Go to Top of Page

couturier

France
291 Posts

Posted - 08/31/2017 :  04:41:20 AM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
@CP
This is because there's the same issue with grobj.x and line.x
Yes we had a discussion about this a long time ago. X property doesn't return real x value but screen X, so it is affected by scale.
For getting real in LT, better use x1 and x2.
Same in OC.

void test(string strName = "line")
{
GraphLayer gl = Project.ActiveLayer();
GraphObject grobj;
grobj = gl.GraphObjects(strName);
fpoint ptNode;
grobj.GetNode(0, ptNode);
out_double("screen X = ", grobj.X);
out_double("real X = ", ptNode.x);
}

In Origin, new an empty graph.
layer.x.from=0.01;
layer.x.to=0.02;
draw -n line -l {0.015, 0, 0.015, 8};
test(line);
line.x=;
line.x1=;

layer.x.from=-500;
layer.x.to=1000;
test(line);
line.x=;
line.x1=;

Edited by - couturier on 08/31/2017 06:27:57 AM
Go to Top of Page

couturier

France
291 Posts

Posted - 08/31/2017 :  07:24:55 AM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
@Roman

your code looks good.
My whole story is I have 4 kinds of lines:
- Names starting with LIM (e.g. LIM1, LIM2, ...)
- Names sarting with LIIM (e.g LIIM1, LIIM2, ...)
- Each of them can have 2 different color.

I need to get:
- X and color for each of them, and put into vectors
- total number
- number of LIM lines
- number of LIIM lines

In FindNodeByAttribute, is there any name property, so I can filter them ?

Thanks
Go to Top of Page

rdremov

USA
28 Posts

Posted - 08/31/2017 :  11:41:52 AM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
couturier, unfortunately we do not have Name exposed to theme yet.

You mentioned "Each of them can have 2 different color". Is it possible to filter by color if colors between LIM and LIIM do not overlap?

If they do overlap, there is this kind of code, which uses theme properties object access:

int GetLineInfo4()
{
	vector<double> vPos;
	vector<int> vColor;
	int n=0;
	GraphLayer gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		vector<double> xx;
		foreach (GraphObject go in gly.GraphObjects)
		{
			if(go.GetName().Left(4)=="Line")
			{
				vColor.Add(go.Line.Color.nVal);
				xx = go.Line.Data.X.dVals;
				vPos.Add(xx[0]);
				n++;
			}
		}
	}
	return n;
}


It is simple, but not very fast. On my pc it took 314ms in Origin 2017 sr2. However, Origin 2018 is much better - takes only 65ms.

to test speed use high res timer like this (Code Builder should be closed to avoid debug and breakpoints impact):
sec -AB; GetLineInfo4; sec -AE elapsed; elapsed=;

Edited by - rdremov on 08/31/2017 12:08:19 PM
Go to Top of Page

couturier

France
291 Posts

Posted - 08/31/2017 :  12:14:37 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
Not sure to understand what you mean with overlapping colors.
Lines can only be red or green.

My actual code looks like this.
About 2 x faster than LT, but still a bit long.

int  EMG_Get_Bars_Info(vector& vecX, vector& vecDir, int& nLimS, int& nLimD)
{
    int nLim=0;
    vector vX, vCol;
    GraphLayer gly = Project.ActiveLayer();
    if( gly.IsValid() )
    {
        Collection<GraphObject> coll;
        if ( gly.GetSpecialGraphicObjectsCollection(coll, "LIM") )
        {
            GraphObject grobj;
	    Tree trColor;
	    fpoint ptNode;
            foreach(grobj in coll)
            {
                grobj.GetNode(0, ptNode);
                trColor=grobj.GetFormat(FPB_STYLE_COLOR, FOB_OBJECT, TRUE, TRUE);
		vX.Add(ptNode.x);
		vCol.Add(trColor.Root.Color.nVal);
		nLim++;
            	nLimS++;
            }
        }
        if ( gly.GetSpecialGraphicObjectsCollection(coll, "LIIM") )
        {
            GraphObject grobj;
	    Tree trColor;
	    fpoint ptNode;
            foreach(grobj in coll)
            {
                grobj.GetNode(0, ptNode);
                trColor=grobj.GetFormat(FPB_STYLE_COLOR, FOB_OBJECT, TRUE, TRUE);
		vX.Add(ptNode.x);
		vCol.Add(trColor.Root.Color.nVal);
		nLim++;
            	nLimD++;
            }
        }
        vCol.Replace(22657947,1,MATREPL_TEST_EQUAL);
        vCol.Replace(21844160,-1,MATREPL_TEST_EQUAL);
        ocmath_sort_xy(vX, vCol, nLim);
    }
	
    vecX=vX;
    vecDir=vCol;
    return nLim;
}

Go to Top of Page

cpyang

USA
1406 Posts

Posted - 08/31/2017 :  12:27:48 PM  Show Profile  Edit Reply  Reply with Quote  View user's IP address  Delete Reply
2018 will have general OC access to all the LT properties, this will include GraphObject, Column, Worksheet, etc. I tested with Roman's project with 1000 lines.

int cc()
{
	vector<double> vPos;
	vector<int> vColor;
	int n=0;
	GraphLayer gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		vector<double> xx;
		foreach (GraphObject go in gly.GraphObjects)
		{
			if(go.GetName().Left(4)=="Line")
			{
				vColor.Add(go.GetProp("color"));//color is integeter, can directly return
				double xPos=0;
				go.GetProp("x1",&xPos);
				vPos.Add(xPos);
				n++;
			}
		}
	}
	return n;
}



On my machine this now takes 17ms, while the corresponding LT code takes 173 ms.

CP
Go to Top of Page
  Previous Topic Topic Next Topic Lock Topic Edit Topic Delete Topic New Topic Reply to Topic
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
The Origin Forum © 2020 Originlab Corporation Go To Top Of Page
Snitz Forums 2000