Jump to content

Welcome to eMastercam

Register now to participate in the forums, access the download area, buy Mastercam training materials, post processors and more. This message will be removed once you have signed in.

Use your display name or email address to sign in:

Zaffin_D

Verified Members
  • Posts

    374
  • Joined

  • Days Won

    1

Posts posted by Zaffin_D

  1. 1 hour ago, baby byte said:

    Sorry, while this will work for importing to c++ there appear to be issues with c# and structs

     https://stackoverflow.com/questions/35912787/using-c-cli-structs-from-c-sharp

    I would go ahead with the array  instead

    I think you are misunderstanding that thread.  The example below works for me. 

    OperationService.h

    #pragma once
    
    namespace OperationServiceNative
    {
    
    	public ref struct OperationData
    	{
    		System::String^ Comment;
    		int ID;
    		int Type;
    		int ToolNumber;
    	};
    
    	public ref class OperationService
    	{
    	public:
    		OperationService();
    
    		OperationData^ GetOperationData(int opID);
    
    		~OperationService();
    
    	};
    }

    OperationService.cpp

    #include "pch.h"
    
    #include "OperationService.h"
    
    OperationServiceNative::OperationService::OperationService()
    {
    }
    
    OperationServiceNative::OperationData^ OperationServiceNative::OperationService::GetOperationData(int opID)
    {
    	OperationData^ opData = nullptr;
    
    	auto operation = TpMainOpMgr.GetMainOpList().OpByID(opID);
    
    	if (operation != nullptr)
    	{
    		opData = gcnew OperationData();
    
    		System::String^ commentString = gcnew System::String(operation->comment);
    
    		opData->Comment = commentString;
    		opData->ID = operation->op_idn;
    		opData->Type = operation->opcode;
    		opData->ToolNumber = operation->tl.tlno;
    	}
    
    	return opData;
    }
    
    OperationServiceNative::OperationService::~OperationService()
    {
    }

    Main.cs

    namespace MyNetHook
    {
        using Mastercam.App;
        using Mastercam.App.Types;
    
        using OperationServiceNative;
    
     
        public class Main : NetHook3App
        {
    
            public override MCamReturn Run(int param)
            {
                var opService = new OperationServiceNative.OperationService();
    
                var opData = opService.GetOperationData(1);
           
                return MCamReturn.NoErrors;
            }
    
        }
    }

     

  2. 20 hours ago, megabyte said:

    Did you learn all that from just reading the docs?

    Are there c-hook docs?  I know about the .chm file, but I never spent any time with it; it was very hard for me to find anything in there.

    I search the headers in Visual Studio.  If my search comes up empty I ask a coworker.  If my coworkers don’t know I ask the SDK team.

    It comes down to time and experience;  I stated with C++ and c-hooks about 8 months ago, and at first I couldn’t find my butt with both hands.

     

     

     

    • Like 1
  3. 1 hour ago, JParis said:

    Alex hit on it..

    As long as you maintain the xml formatting, editing in the post is fine...break that though and it could be a headache. 

    XML requires certain characters to be escaped, try putting an ampersand(&) in a text tag and watch the post text default to system text.  If you add an ampersand thru the CD it will be escaped correctly.

    The post and post text also must be encoded in UTF-8, in the unlikely case the editor used to edit the post doesn't support UTF-8 (some people still use PFE) and you venture outside the ASCII range the post text will also blow up.

    Editing through the CD eliminates both problems.

    @Sushant Singh, ask your reseller for a copy of the Working with machine and control definitions  MP application guide, it goes over everything in great detail.

     

    • Like 2
  4. MP has two data types, string and numeric.  Strings always start with 's' and are initialized with quote characters (single or double).  The data coming from the 20002 is a string, so try this....

    s_group_com : ""
    
    pparameter$
        if prmcode$ = 20002, s_group_com = sparameter$

     If you'd like the "TC=" prefix you can build a string with a global formula as shown below

    s_group_com_out = "TC=" + s_group_com
      
    ptlchg$
      s_group_com_out, e$

     

    • Like 2
  5. I think it's worth noting that the K value in a ZXZ Euler can be anything provided the points are mapped to that XY orientation.  I only bring this up because I think ZXZ is the default rotation order on a Fanuc.

    Also roll pitch yaw (Tait–Bryan angles) are very similar to Euler angles; the difference is that Euler's repeat an axis (ZXZ, XYX, ZYZ, you get the idea...), and roll pitch yaw angles don't(XYZ, YZX, YXZ, etc.)

    • Like 1
  6. 21 hours ago, Megabyte said:

    When I used your method on operations on the bottom plane the value gets inverted

    For example Method 1 outputs ZMin -.500 ZMax-.035

    Method 2 outputs ZMin .035 ZMax .500 

    is there a reliable way to use your method for bottom operations?

    Hmm that is odd.  Rather than rely on the GetBnciLowerLeft()/GetBnciUpperRight() function, try reading the BNCI as shown below.  You'll want to cover more NCI lines (NCI_ARC_CW, NCI_5AX_LINEAR, NCI_ARC_CCW, etc.),  but it should get you started.

    			double minZ = 99999.999;
    			double maxZ = -99999.999;
    
    			CBnciReadWrite bnciReader;
    
    			bnciReader.ReadSection(currentOperation->op_idn, false);
    
    			auto binaryNCILines = bnciReader.GetData();
    
    			for (auto nciLine : binaryNCILines)
    			{
    				switch (nciLine->gcode)
    				{
    				case NCI_RAPID:
    					if (minZ > nciLine->u.m0.ep1[Z])
    					{
    						minZ = nciLine->u.m0.ep1[Z];
    					}
    					if (maxZ < nciLine->u.m0.ep1[Z])
    					{
    						maxZ = nciLine->u.m0.ep1[Z];
    					}
    					break;
    				case NCI_LINEAR:
    					if (minZ > nciLine->u.m1.ep1[Z])
    					{
    						minZ = nciLine->u.m1.ep1[Z];
    					}
    					if (maxZ < nciLine->u.m1.ep1[Z])
    					{
    						maxZ = nciLine->u.m1.ep1[Z];
    					}
    					break;
    				default:
    					break;
    				}
    			}

     

  7. Parameter 19 contains the minimum Z value for an operation. I think you could use this information to check if you're at the lowest Z; below is some pseudo code.

    op_min_z : 99999
    
    fmt  "Z" 2  z$        #Z position output
    fmt  ""  2  op_min_z  #Min Z position, formated for comparision
    
    ptlchg$
        op_min_z = 99999
        # Get the opertions min Z position
        op_min_z = opinfo(19, 0)
    
    plin$
        # Test to see if we are at the min Z position
        if fmtrnd(op_min_z) = fmtrnd(z$),
            [
            # The min Z has been reached, update the prefix/suffix
            result = nwadrs("Z[#502+", z$)
            result = nwsufx("]", z$)
            ]
        else,
            [
            # We are not at the min Z, restore the orignal prefix/suffix
            result = nwadrs("Z", z$)
            result = nwsufx("", z$)
            ]

      

  8. Rather than use MP's comment mechanism, query parameter 15239.

    s_op_comment : ""
    
    p_any_postblock
        # Get the op comment of the current operation
        s_op_comment = opinfo(15239, 0, 0000)
    
        # If we are in a transform operation, we can query the soure operation...
        s_op_comment = opinfo(15239, 0, 0000)
    
        # ...or we can query the transform parameters.
        s_op_comment = opinfo(15239, 0, 0010)

     

    • Thanks 1
    • Like 2
  9. 15 hours ago, coolsas said:

    Hi there,

    perhaps if somebody is interested, this is how it works for me:

    Using the previously attached part file that function returns the arc direction of the upper profile as CCW when chained clockwise with the C-plane set to TOP; so I think somethings up.  I'm using 2020, but I don't think that would make a difference.

    The below function matches the analyze contour results in my tests.

    void GetChainDirection()
    {
    	LPCTSTR prompt(_T("Select a Chain"));
    	CHAIN* selectedChain = nullptr;
    
    	auto result = chain_1(prompt, &selectedChain);
    
    	if (result == CHAIN_OK && &selectedChain != nullptr)
    	{
    		auto selectedChainPointer = selectedChain->start;
    
    		while (selectedChainPointer != nullptr)
    		{
    			auto entityPointer = selectedChainPointer->e_ptr->eptr;
    
    			if (entityPointer->id == A_ID)
    			{
    				p_3d arcStartVector;
    				p_3d arcEndVector;
    				p_3d crossProduct;
    			
    				p_3d arcStart;
    				p_3d arcCenter;
    				p_3d arcEnd;
    
    				double arcSweep;
    
    				view_to_world(entityPointer->u.ar.c, entityPointer->u.ar.view, arcCenter);
    
    				view_to_view(entityPointer->u.ar.ep1, 1, CONSTR_VIEW_N, arcStart);
    				view_to_view(arcCenter, 1, CONSTR_VIEW_N, arcCenter);
    				view_to_view(entityPointer->u.ar.ep2, 1, CONSTR_VIEW_N, arcEnd);
    
    				if (selectedChainPointer->ep_n)
    				{
    					arcStartVector = arcEnd - arcCenter;
    					arcEndVector = arcStart - arcCenter;
    				}
    				else
    				{
    					arcStartVector = arcStart - arcCenter;
    					arcEndVector = arcEnd - arcCenter;
    				}
    
    				crossProduct = Cross(arcStartVector, arcEndVector).NormalizeThis();
    
    				arcSweep = std::abs(entityPointer->u.ar.sw) * (180.0 / PI);
    				arcSweep = (int)(arcSweep * 1000.0) / 1000.0;
    
    				if (crossProduct[Z] < 0.0)
    				{
    					if (arcSweep <= 180.0)
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    					else
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CCW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    
    				}
    				else if (crossProduct[Z] > 0.0)
    				{
    					if (arcSweep >= 180.0)
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    					else
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CCW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    				}
    				else
    				{
    					::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("crossProduct = 0; arc direction could not be obtained."), _T("ArcDirection"), MB_OK);
    				}
    			}
    
    			selectedChainPointer = selectedChainPointer->next;
    		}
    
    		free_chain(&selectedChain);
    	}
    }

     

    • Like 1
  10. 2 hours ago, coolsas said:

    Hi Zaffin_D,

    I have tried your code, unfortunately I have similar problems, sometimes arc direction is correct, sometimes not. You can check that in my uploaded file Testarc.mcam the link is in my 2nd post. I select c-plane top and start your function, then I select the wireframe contour on top of the solid, I chain it clockwise (then all 4 arcs should be CW) then I get 3 CW and 1 CCW. When I select c-plane bottom, start your function and chain the geometry on bottom of the solid, then I get 2 CW and 2 CCW as message.

    When I use the mastercam function analyze->contour then I get the correct data, chaining the contour clockwise I get 4 CW arcs, chaining counterclockwise I get 4 CCW arcs. That is what I need.

    Unfortunatley I am not the mathematician to calculate it from entity data (ep1, ep2, c, r, sa, sw) depending the active c-plane.

    I thank you Zaffin_D and Peter for trying to help me.

    Best wishes Karsten

     

    Funny arcs...

    The center point isn't mapped to the same view as the endpoints, try mapping the center to world with view_to_world as shown below.

    			if (entityPointer->id == A_ID)
    			{
    				p_3d worldCenter;
    
    				view_to_world(entityPointer->u.ar.c, entityPointer->u.ar.view, worldCenter);
    
    				if (selectedChainPointer->ep_n)
    				{
    					arcStartVector = entityPointer->u.ar.ep2 - worldCenter;
    					arcEndVector = entityPointer->u.ar.ep1 - worldCenter;
    				}
    				else
    				{
    					arcStartVector = entityPointer->u.ar.ep1 - worldCenter;
    					arcEndVector = entityPointer->u.ar.ep2 - worldCenter;
    				}

    Also I think we should take the absolute sweep...

    				arcSweep = fabs(entityPointer->u.ar.sw) * (180.0 / PI);

    ...but i'm not a math guru.

  11. This seems like a lot of code to accomplish this.  Writing the text NCI to disk then scanning it seems rather inefficient, especially on larger NCI files.

    I think you could achieve the same result doing something like this...

    extern "C" __declspec(dllexport) int eMCExample452020Entry (int param)
    {
    	// Must call this prior to accessing any Resources in the C-Hook DLL !
    	ChangeResCl res (GetChookResourceHandle ());
    
    	CInterrogateMastercamFile fileInterrogator;
    
    	fileInterrogator.Load();
    
    	auto operationIDs = fileInterrogator.GetOpIDsInOpMgrOrder();
    
    	if (operationIDs != nullptr)
    	{
    		p_3d min;
    		p_3d max;
    
    		Cnc::Tool::TlAssemblyCPtr toolAssembly;
    
    		std::wstring newComment = L"";
    
    		DB_LIST_ENT_PTR outPointer = nullptr;
    
    		bool result;
    
    		for (auto opID : *operationIDs)
    		{
    			auto operation = TpMainOpMgr.GetMainOpList().OpByID(opID);
    
    			fileInterrogator.LoadForSingleOperation(operation->op_idn, true);
    
    			fileInterrogator.CalcBnciExtents(false, false, true, true);
    
    			min = fileInterrogator.GetBnciLowerLeft();
    			max = fileInterrogator.GetBnciUpperRight();
    
    			newComment = L"Z Min: " + std::to_wstring(min[2]) + L"\r\n";
    			newComment += L"Z Max: " + std::to_wstring(max[2]) + L"\r\n";
    
    			Cnc::Tool::GetToolSystem()->Find(operation->tl.slot, toolAssembly);
    
    			if (toolAssembly != nullptr)
    			{
    				newComment += L"Tool Projection: " + std::to_wstring(toolAssembly->GetToolProjection()) + L"\r\n";
    			}
    
    			_tcscpy_s(operation->comment, newComment.c_str());
    			
    			operation_manager(operation, OPMGR_REWRITE, &outPointer, &result);
    		}
    	}
    	
    
    	return MC_NOERROR | MC_UNLOADAPP;
    }

      

    I know you might feel like this...

    ...but don't; developing in a vacuum is hard. 

     

     

    • Like 1
  12. I'm unfamiliar with how you are determining the arc's direction.

    Below is something that works in my testing as long as the sweep's not 180 degrees (it will fail if the sweep is 180).  I'm not sure how helpful it will be.

    extern "C" __declspec(dllexport) int ArcDirectionEntry (int param)
    	{
    	// Must call this prior to accessing any Resources in the C-Hook DLL !
    	ChangeResCl res (GetChookResourceHandle ());
    
    	LPCTSTR prompt(_T("Select a Chain"));
    	CHAIN* selectedChain = nullptr;
    
    	auto result = chain_1(prompt, &selectedChain);
    
    	if (result == CHAIN_OK && &selectedChain != nullptr)
    	{
    		auto selectedChainPointer = selectedChain->start;
    
    		p_3d arcStartVector;
    		p_3d arcEndVector;
    		p_3d crossProduct;
    
    		double arcSweep;
    
    		while (selectedChainPointer != nullptr)
    		{
    			auto entityPointer = selectedChainPointer->e_ptr->eptr;
    
    			if (entityPointer->id == A_ID)
    			{
    				if (selectedChainPointer->ep_n)
    				{
    					arcStartVector = entityPointer->u.ar.ep2 - entityPointer->u.ar.c;
    					arcEndVector = entityPointer->u.ar.ep1 - entityPointer->u.ar.c;
    				}
    				else
    				{
    					arcStartVector = entityPointer->u.ar.ep1 - entityPointer->u.ar.c;
    					arcEndVector = entityPointer->u.ar.ep2 - entityPointer->u.ar.c;
    				}
    
    				crossProduct = Cross(arcStartVector, arcEndVector).NormalizeThis();
    
    				arcSweep = entityPointer->u.ar.sw * (180.0 / PI);
    				arcSweep = (int)(arcSweep * 1000.0) / 1000.0;
    
    				if (crossProduct[2] < 0.0)
    				{
    					if (arcSweep <= 180.0)
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    					else
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CCW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    					
    				}
    				else if (crossProduct[2] > 0.0)
    				{
    					if (arcSweep >= 180.0)
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    					else
    					{
    						::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("CCW ARC FOUND!"), _T("ArcDirection"), MB_OK);
    					}
    				}
    				else
    				{
    					::MessageBox(get_MainFrame()->GetSafeHwnd(), _T("crossProduct = 0; arc direction could not be obtained."), _T("ArcDirection"), MB_OK);
    				}
    			}
    
    			selectedChainPointer = selectedChainPointer->next;
    		}
    
    		free_chain(&selectedChain);
    	}
    
    	return MC_NOERROR | MC_UNLOADAPP;
    	}

     

  13. double StringManipulation::StringToDouble(StringType input)
    {
    	CString c_str = input.c_str();
    	// Convert a TCHAR string to a LPCSTR
    	CT2CA pszConvertedAnsiString(c_str);
    	// construct a std::string using the LPCSTR input
    	std::string strStd(pszConvertedAnsiString);
    	return atof(strStd.c_str()); /*c_str is needed to convert string to const char*/
    }
    
    int StringManipulation::StringToInt(StringType input)
    {
    	CString c_str = input.c_str();
    	// Convert a TCHAR string to a LPCSTR
    	CT2CA pszConvertedAnsiString(c_str);
    	// construct a std::string using the LPCSTR input
    	std::string strStd(pszConvertedAnsiString);
    	return atoi(strStd.c_str()); /*c_str is needed to convert string to const char*/
    }

    These functions smell funny;  atoi and atof both return 0 on failure and that's not great. 

    Consider using std::stoi or std::stod.  They accept a std::string or std::wstring so there is no need to do whatever your doing to convert the input.  They also throw an exception on failure rather than an ambiguous value.

     

  14. 2 hours ago, mkd said:

    i'd like to hear more on this.

    Not much more to it.  PLANE VECTOR requires two vectors defined by the values BX, BY, BZ (the base vector) and NX, NY, NZ (the normal vector).

    The normal vector is the Z vector of the tool plane.  I can't remember, but I think the base vector is the X vector of the tool plane, but it could be the Y vector; it's been awhile.

    • Like 1
  15. Can I ask why you are programming for COR?  It seems that your issue would solve itself if you used the PLANE functions.

    24 minutes ago, huskermcdoogle said:

    I believe I understand how the PLANE functions work, but it is possible for me to shift the entire program using them.

    WESC is not something the 530 offers out of the box.  As you may or may not be aware you can not add a secondary axis (a or b) value in the preset table and have M128 or the PLANE function work.  I thought Hermle had a cycle 300-something to work around this but I was a Mikron guy.

    28 minutes ago, huskermcdoogle said:

    Also how or can you shift the coordinate system to a new local coordinate system? Such as you can with G68.2 on a Fanuc.

    Cycle 7 or TRANS DATUM if the machine is newer.

     

     

    • Like 2
  16. What manuals are you looking at?  I've always found Heidenhain manuals to be excellent.

    Anyway, you can define a plane in several ways.  The old way was cycle 19, but you should be using the PLANE function if it's available.  The PLANE function has several options for how to define a plane...

    • Spatial angles 
    • Projection angles
    • Euler angles ZXZ
    • Two vectors
    • Three points

    The plane function also allows you to specify other options...

    • SEQ + or -; this chooses the rotation solution 
    • MOVE, TURN, STAY.  MOVE will move the rotary axes and the tool when the command is executed.  TURN will move only the rotary axes.  STAY will do the math but will not cause motion.  A retract can also be specified 
    • TABLE ROT or COORD ROT; move the rotaries or move the coordinate system   

    The above lists are not exhaustive.   

    When I was an AE for Mikron spatial angles were the most popular.  If you have a BC machine, SPA would be 0, SPB would be the B-axis angle, and SPC would be the C-axis angle. 

    On the machine this works great, but in the post this involves some mapping/rotating because the two angles don't fully define a plane.  The code would look something like this...

     PLANE SPATIAL SPA+0 SPB-45 SPC+0 SEQ- TURN MBMAX FMAX TABLE ROT

    So that says I want to define the plane by spatial angles(PLANE SPATIAL); set the B-axis at 45 degrees(SPA+0 SPB-45 SPC+0); choose the negative solution(SEQ-); move only the rotaries(TURN); before you move, retract along the tool axis to the limit switch(MBMAX); do everything at max feed rate(FMAX); rotate the table(TABLE ROT).

    The above is from memory, it's best to build a few cycles at the control; it walks you through every step.  Heidenhain also offers a free simulator.

    I personally like the two vectors method because Mastercam gives you the toolplane matrix.

     

    Hope that helps.

    • Like 1
  17. 5 hours ago, Peter from S.C.C.C. said:

    I requested the mpmaster documentation from my reseller, they said I could only request for versions prior to Mastercam 2020 because the process has changed since then, I imagine we are going to see a lot of difference in the post development process as the years tick on..

    Assuming you mean the MP post docs, this is likely specific to your reseller.

    The post docs for 2020 are available, but their format has changed.  Gone is the bulky .PDF; for 2020 and beyond the post docs are in (a much improved) .HTML format.

    • Like 1
  18. 19 hours ago, pro grammer said:

    pe              #End of line
          e$

    All that section of code does is rename the e$ function to "pe". Just renaming. that is it. And, that code can easily be locked as any other code to "avoid piracy".

    This appears to do a bit more than rename e$.  It appers to allow the user to add a end of line string to every output line in one place.  For example if you wanted to add '*' to the end of every string you could do the following.

    pe
    	'*', e$

    Even if the post isn't encrypted this seems to have value, no?

     

    I'm not a post expert so I'll differ to you; objectively whats wrong with the above?  How would you handle this?

    What standards would you like to see set in regards to MP posts? 

    Software development is an art as much as it is a science; a standard in something so abstract seems like telling a painter they can only paint black circles on a white background.  How can innovation happen if everyone is required to do the same thing? 

    • Like 6
  19. 3 hours ago, Norbert Dalhoff said:

    Hello peter~ and Zaffin,

    thanks for your replies. My Mastercam-Version is 2019 (21.0.28020.0).

     

    I think I see what's going on here; by non-reserved plane you mean a view that doesn't appear in the view manager?  For example the view of a rotated arc

    You should be able to get the arc's view matrix by using the get_view_matrix function.

Join us!

eMastercam - your online source for all things Mastercam.

Together, we are the strongest Mastercam community on the web with over 56,000 members, and our online store offers a wide selection of training materials for all applications and skill levels.

Follow us

×
×
  • Create New...