/*====================================================================*\
FILE	: UtilSect.c
PURPOSE	: ProSection Utilities

HISTORY..
DATE              AUTHOR    MODIFICATIONS
14 Jun 96         Steve     $$1 First version.
09 Jul 96         Xuekai    $$2 Add some DBMS fProUtilMenuActionunctions
26-Aug-96 H-01-05 Xuekai    $$3 Modify due to change to ProMdl
09-Sep-96 H-01-08 Xuekai    $$4 ProSellistFree => ProArrayFree,obsolete protk.h
12-Sep-96 H-01-09 Xuekai    $$5 Add/Modify functions due to change in
				ProSection3DAlloc() & add DBMS fncts
24-Sep-96 H-01-10 Xuekai    $$6 Comment out temporily due to re-work
17-Oct-96 H-01-13 Xuekai    $$7 Change back
29-Oct-96 H-01-15 Steve	    $$8 Rework for new func
30-Oct-96 H-01-15 Steve     $$9 Fixed bug
12-Nov-96 H-01-16 Steve	    $$10 Added retr and info stuff
25-Nov-96 H-01-18 Steve     $$11 Expanded info stuff
03-Dec-96 H-01-19 Steve     $$12 clean up test calls
10-Dec-96 H-01-20 Steve     $$13 use exist section utils
19-Dec-96 H-01-21 Steve     $$14 fixed exist section bugs
23-Dec-96 H-01-21 amin      $$15 ProIntlistFree -> ProArrayFree
24-Dec-96 H-01-21 Steve     $$16 return checks
30-Dec-96 H-01-21 Igor      $$17 fixed bug
19-Dec-97 H-01-21 Alexey    $$18 added test code for ProSecdimLocationGet()
16-Jun-97 H-03-14 Igor      $$19 Exist. section for sweeps doesn't need location
26-Aug-97 H-03-20 Alexey    $$20 Since ProMdlRetrieve doesn't accept name with
				 extension modify ProUtilSectionRetr()
15-Sep-97 H-03-22 Pavel     $$21 Replace Pro/D on Pro/T
17-Sep-97 H-03-22 Akula     $$22 Correct to fit sgi
06-Oct-97 H-03-25 Pavel	    $$23 More includes
04-Nov-97 H-03-29 Pavel     $$24 Corrected TEST_CALL_REPORTs
07-Nov-97 H-03-31 Pavel     $$25 Fixed some bugs, Updated with new functions
11-Dec-97 H-03-32 Alexey    $$26 Set dim_loc.type = PRO_2D_POINT in
					ProUtilSectionInfoCopy
09-Feb-98 H-03-39 Alexey    $$27 Move ProUtilStdSectInfoFromElemTreeGet(),
					ProStdSectVisitAction() and
					ProUtilElementDataGet() from
					TestExtrude.c
04-Aug-98 I-01-16 Alexey    $$28 Check out the ProSectionDimensionIdsGet()
					return value in ProUtilSectionInfoGet
26-Aug-98 I-01-17 Alexey    $$29 Modify constraint type names and values due
				 to the changes in ProSecConstr.hA
28-Oct-98 I-01-26 akkur     $$30 Add ProUtilUseEdge.
01-Dec-98 I-01-27 akh       $$31 Correct TEST_CALL_REPORT
16-Dec-98 I-01-28 mka       $$32 Correct TEST_CALL_REPORT
28-Dec-98 I-01-28 akh       $$33 Don't put #if in the middle of 
                                        TEST_CALL_REPORT
30-Dec-98 I-01-28 akh	    $$34 Don't TEST_CALL_REPORT after calling to
				 ProSectionNameSet with 3D section.
21-Jan-99 I-01-29 Alexey    $$35 Add important comment to the description 
				 of ProUtilSectionInfoGet
09-Feb-99 I-03-02 Alexey    $$36 Update ProSecdimValueGet TEST_CALL_REPORT
31-May-99 I-03-11 mka       $$37 Delete unused variable
\*====================================================================*/

/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProSecdim.h>
#include <ProSection.h>
#include <ProMdl.h>
#include <ProMenu.h>
#include <ProEdge.h>
#include <ProGeomitem.h>
#include <ProFeature.h>
#include <ProSelection.h>
#include <ProSurface.h>
#include <ProArray.h>
#include <ProUtil.h>

/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/
#include <math.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "UtilMenu.h"
#include "UtilMessage.h"
#include "TestSect.h"
#include "UtilMessage.h"
#include "TestError.h"
#include "UtilMath.h"
#include "UtilMatrix.h"
#include "UtilCollect.h"

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/
#define mnUSE_EDGE          0
#define mnUSE_EDGE_CHAIN    1
#define mnUSE_EDGE_LOOP     2
#define mnUSE_CURVE_CHAIN   3
#define mnUSE_CURVE_LOOP    4
#define mnUSE_DONE          -1

/*
Used functions
*/        
int ProUtilSecEntityUseEdge (ProSection section);
int ProUtilSecEntityUseEdgeChain (ProSection section);
int ProUtilSecEntityUseEdgeLoop (ProSection section);
int ProUtilSecEntityUseCurveLoop (ProSection section);
int ProUtilSecEntityUseCurveChain (ProSection section);

/*====================================================================*\
    FUNCTION :	ProUtilSectionRetrieve
    PURPOSE  :	Retrieves a section from disk, memory or from feature
\*====================================================================*/
ProError ProUtilSectionRetrieve(ProSection *section)
{
    int by_name = 0;
    int ProUtilAssign();
    ProError status;
    int id;

    status = ProMenuFileRegister("TK SECT RETR","tk_secretr.mnu", &id);
    TEST_CALL_REPORT ("ProMenuFileRegister", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);
    status = ProMenubuttonActionSet("TK SECT RETR","-By Name",ProUtilAssign,
                      &by_name,1);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);
    status = ProMenubuttonActionSet("TK SECT RETR","-From Feature",
        ProUtilAssign, &by_name,0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);
    status = ProMenubuttonActionSet("TK SECT RETR","TK SECT RETR",
         (ProMenubuttonAction)ProMenuDelete, NULL,0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);
    status = ProMenuCreate(PROMENUTYPE_MAIN,"TK SECT RETR", &id);
    TEST_CALL_REPORT ("ProMenuCreate", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);
    status = ProMenuProcess("TK SECT RETR", &id);
    TEST_CALL_REPORT ("ProMenuProcess", "ProUtilSectionRetrieve",
        status, status != PRO_TK_NO_ERROR);

    if (by_name)
    {
	status = ProUtilSectionRetr(section);
    }
    else
    {
	status = ProUtilSectionFromFeatGet(section);
    }

    return(status);
}
/*====================================================================*\
    FUNCTION :	ProUtilSectionFromFeatGet
    PURPOSE  :	Gets a section from a feature
\*====================================================================*/
ProError ProUtilSectionFromFeatGet(ProSection *section)
{
    ProSelection *p_sels;
    int n_sels;
    ProFeature feat;
    int n_sections;
    int range[2],n;
    wchar_t wname[PRO_NAME_SIZE];
    ProError err;

    *section = NULL;

    ProUtilMsgPrint("gen","TEST %0s",
		    "Select a feature containing a sketch.");
    err = ProSelect("feature", 1,
		    NULL,NULL,NULL,NULL, &p_sels, &n_sels);
    TEST_CALL_REPORT("ProSelect", "ProUtilSectionFromFeatGet",
		      err , err != PRO_TK_NO_ERROR);

    if (err != PRO_TK_NO_ERROR || n_sels != 1)
	return(PRO_TK_USER_ABORT);

    err = ProSelectionModelitemGet(p_sels[0],&feat);
    TEST_CALL_REPORT("ProSelectionModelitemGet",
		     "ProUtilSectionFromFeatGet",
		      err , err != PRO_TK_NO_ERROR);

    err = ProFeatureNumSectionsGet(&feat,&n_sections);
    TEST_CALL_REPORT("ProFeatureNumSectionsGet",
		     "ProUtilSectionFromFeatGet",
		      err , err != PRO_TK_NO_ERROR);

    if (n_sections < 1)
    {
	ProUtilMsgPrint("gen","TEST %0s",
			"Feature does not contain any sections.");
        return(PRO_TK_GENERAL_ERROR);
    }

    range[0] = 0; range[1] = n_sections-1;
    n = 0;
    if ( range[0] != range[1] )
    {
	ProUtilMsgPrint("gen","TEST %0s",
			"Specify section number to retrieve.");
        ProUtilIntGet(range,&range[0],&n);
    }

    err = ProFeatureSectionCopy(&feat,n,section);
    TEST_CALL_REPORT("ProFeatureSectionCopy",
		     "ProUtilSectionFromFeatGet",
		      err , err != PRO_TK_NO_ERROR);
    ProUtilMsgPrint("gen","TEST %0s",
			"Enter section name [NONE]: ");
    if (ProUtilStringGet(wname,NULL, PRO_NAME_SIZE-1))
    {
	err = ProSectionNameSet(*section,wname);
	/*  The function returns -2 for feature section (3D sec)
	    but successfully sets the name. ProSection3dTo2d (doesn't 
	    exist yet))needs to be used before calling to ProSectionNameSet().
        TEST_CALL_REPORT("ProSectionNameSet",
		         "ProUtilSectionFromFeatGet",
		         err , err != PRO_TK_NO_ERROR);
	*/
    }

     return(err);
}

/*====================================================================*\
    FUNCTION :	ProUtilSectionPointTypeStr
    PURPOSE  :	Dumps section entity info to a file
\*====================================================================*/
char* ProUtilSectionPointTypeStr(
    ProSectionPointType type)
{
    switch(type)
    {
	case PRO_ENT_WHOLE:
	     return("PRO_ENT_WHOLE");
	case PRO_ENT_START:
	     return("PRO_ENT_START");
	case PRO_ENT_END:
	     return("PRO_ENT_END");
	case PRO_ENT_CENTER:
	     return("PRO_ENT_CENTER");
	case PRO_ENT_LEFT_TANGENT:
	     return("PRO_ENT_LEFT_TANGENT");
	case PRO_ENT_RIGHT_TANGENT:
	     return("PRO_ENT_RIGHT_TANGENT");
	case PRO_ENT_TOP_TANGENT:
	     return("PRO_ENT_TOP_TANGENT");
	case PRO_ENT_BOTTOM_TANGENT:
	     return("PRO_ENT_BOTTOM_TANGENT");
    }
    return("UNKNOWN");
}



/*====================================================================*\
    FUNCTION :	ProUtilSectionInfoGet
    PURPOSE  :	Dumps section entity info to a file

    WARNING:	Do not call to this function during feature redefinition. 
		The function calls to ProSectionDimensionIdsGet which 
		should be used only for completely redefined feature.
\*====================================================================*/
ProError ProUtilSectionInfoGet(FILE *fp,ProSection section)
{
    ProIntlist ent_ids,dim_ids,con_ids;
    int n_ids,n_dimids, n_conids, i,j;
    ProError status;
    Pro2dEntdef *p_ent;
    Pro2dPointdef *p_pnt;
    Pro2dLinedef *p_line;
    Pro2dArcdef *p_arc;
    Pro2dCircledef *p_circle;
    Pro2dSplinedef *p_spline;
    ProVector point,deriv,deriv2;
    double value;
    ProSecdimType dim_type;
    char d_type[50];
    char *p_type, *c_type, *c_status;
    ProSectionPointType *p_types;
    int *ref_ids;
    int n_ref_ids,k;
    ProBoolean is_projection;
    ProIntlist secdim_ids,mdldim_ids;
    int n_mdldim_ids,l;
    ProConstraintType con_type;
    ProConstraintStatus con_status;

    status = ProSectionRegenerate(section,NULL);
    TEST_CALL_REPORT("ProSectionRegenerate()",
		     "ProUtilSectionInfoGet()",
		     status, status != PRO_TK_NO_ERROR);

    fprintf(fp,"Section Entity and Dimension Info\n");
    fprintf(fp,"---------------------------------\n\n");

    status = ProSectionEntityIdsGet(section,&ent_ids,&n_ids);
    TEST_CALL_REPORT("ProSectionEntityIdsGet()", "ProUtilSectionInfoGet()",
		     status, status != PRO_TK_NO_ERROR);

    for (i=0; i<n_ids; i++)
    {
	status = ProSectionEntityGet(section,ent_ids[i],&p_ent);
        TEST_CALL_REPORT("ProSectionEntityGet()",
			 "ProUtilSectionInfoGet()",
		         status, status != PRO_TK_NO_ERROR);

	fprintf(fp,"Entity Id: [%d]\n",ent_ids[i]);
        if (status != PRO_TK_NO_ERROR) continue;

        status = ProSectionEntityIsProjection(section,ent_ids[i],
					       &is_projection);
        TEST_CALL_REPORT("ProSectionEntityIsProjection()",
			 "ProUtilSectionInfoGet()",
		         status, status != PRO_TK_NO_ERROR);
        if (status != PRO_TK_NO_ERROR) continue;

        if (is_projection == PRO_B_TRUE)
	     fprintf(fp,"\tEntity Is Projection\n");

        switch(p_ent->type)
	{
	    case PRO_2D_POINT:
	    case PRO_2D_COORD_SYS:
		if (p_ent->type == PRO_2D_POINT)
		    fprintf(fp,"\tEntity Type: PRO_2D_POINT\n");
                else
		    fprintf(fp,"\tEntity Type: PRO_2D_COORD_SYS\n");
                p_pnt = (Pro2dPointdef *)p_ent;
                fprintf(fp,"\tLocation: [ %4.2lf, %4.2lf ]\n",
			p_pnt->pnt[0],p_pnt->pnt[1]);;
		break;
            case PRO_2D_LINE:
	    case PRO_2D_CENTER_LINE:
		if (p_ent->type == PRO_2D_LINE)
		    fprintf(fp,"\tEntity Type: PRO_2D_LINE\n");
                else
		    fprintf(fp,"\tEntity Type: PRO_2D_CENTER_LINE\n");
                p_line = (Pro2dLinedef *)p_ent;
                fprintf(fp,"\tEnd1: [ %4.2lf, %4.2lf ]\n",p_line->end1[0],
						  p_line->end1[1]);
                fprintf(fp,"\tEnd2: [ %4.2lf, %4.2lf ]\n",p_line->end2[0],
						  p_line->end2[1]);
                break;
            case PRO_2D_ARC:
		fprintf(fp,"\tEntity Type: PRO_2D_ARC\n");
		p_arc = (Pro2dArcdef *)p_ent;
		fprintf(fp,"\tCenter: [ %4.2lf, %4.2lf ]\n",p_arc->center[0],
						         p_arc->center[1]);
		fprintf(fp,"\tRadius: [ %4.2lf ]\n",p_arc->radius);
		fprintf(fp,"\tStart Angle: [ %4.2lf ]\n",
				      180/PI*p_arc->start_angle);
		fprintf(fp,"\tEnd Angle: [ %4.2lf ]\n",
				      180/PI*p_arc->end_angle);
		break;
            case PRO_2D_CIRCLE:
	        fprintf(fp,"\tEntity Type: PRO_2D_CIRCLE\n");
		p_circle = (Pro2dCircledef *)p_ent;
		fprintf(fp,"\tCenter: [ %4.2lf ]\n",p_circle->center[0],
						  p_circle->center[1]);
		fprintf(fp,"\tRadius: [ %4.2lf ]\n",p_circle->radius);
		break;
            case PRO_2D_SPLINE:
	        fprintf(fp,"\tEntity Type: PRO_2D_SPLINE\n");
		p_spline = (Pro2dSplinedef *)p_ent;
		fprintf(fp,"\tTangency Type: [%d]\n",
			p_spline->tangency_type);
                fprintf(fp,"\tStart Tangent Angle: [ %4.2lf ]\n",
			180/PI*p_spline->start_tang_angle);
                fprintf(fp,"\tEnd Tangent Angle: [ %4.2lf ]\n",
			180/PI*p_spline->end_tang_angle);
                fprintf(fp,"\tNum Points: [%d]\n",p_spline->n_points);
		for (j=0; j<(int)p_spline->n_points; j++)
		    fprintf(fp,"\tPoint%d: [ %4.2lf, %4.2lf ]\n",j,
			    p_spline->point_arr[j][0],
			    p_spline->point_arr[j][1]);
                break;
            default:
		fprintf(fp,"\tEntity Type: UNKNOWN\n");
		break;
         }

         if (p_ent->type != PRO_2D_POINT &&
	     p_ent->type != PRO_2D_COORD_SYS )
         {
             fprintf(fp,"\tPoints Evaluated on Entity\n");
             for (j=0; j<=4; j++)
	     {
	        status = ProSectionEntityEval(section,ent_ids[i],j*.25,
					  point,deriv,deriv2);
                TEST_CALL_REPORT("ProSectionEntityEval()",
			     "ProUtilSectionInfoGet()",
		              status, status != PRO_TK_NO_ERROR);
                fprintf(fp,"\t\tParameter: [%4.2lf]\n",j*.25);
	        fprintf(fp,"\t\t\tPoint: [ %4.2lf, %4.2lf ]\n",
				     point[0],point[1]);
	        fprintf(fp,"\t\t\tFirst Derivative: [ %4.2lf, %4.2lf ]\n",
				     deriv[0],deriv[1]);
	        fprintf(fp,"\t\t\tSecond Derivative: [ %4.2lf, %4.2lf ]\n",
				     deriv2[0],deriv2[1]);
             }
         }

	 fprintf(fp,"\n");
    }

    status = ProArrayFree((ProArray*)&ent_ids);
    TEST_CALL_REPORT("ProArrayFree()",
	    "ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);

/*------------------------------------------------*\
    Section dimensions
\*------------------------------------------------*/

    status = ProSecdimIdsGet(section,&dim_ids,&n_dimids);
    TEST_CALL_REPORT("ProSecdimIdsGet()", "ProUtilSectionInfoGet()",
		     status, status != PRO_TK_NO_ERROR);
    n_mdldim_ids = 0;
    status = ProSectionDimensionIdsGet(section,&secdim_ids,
				       &mdldim_ids, &n_mdldim_ids);
    TEST_CALL_REPORT("ProSectionDimensionIdsGet()",
		     "ProUtilSectionInfoGet()",
		     status, (status != PRO_TK_NO_ERROR) && 
                     (status != PRO_TK_NOT_EXIST));
    if( status != PRO_TK_NO_ERROR )
	n_mdldim_ids = 0;
    fprintf(fp,"\n");
    for (j=0; j<n_dimids; j++)
    {
	fprintf(fp,"\tSecDim Id: [%d]\n",dim_ids[j]);

        for (l=0; l<n_mdldim_ids; l++)
	    if (dim_ids[j] == secdim_ids[l])
	    {
		fprintf(fp,"\tDimension Id: [%d]\n",mdldim_ids[l]);
		break;
            }

        status = ProSecdimValueGet(section,dim_ids[j],&value);
        TEST_CALL_REPORT("ProSecdimValueGet()",
			 "ProUtilSectionInfoGet()",
		         status, 
                         status != PRO_TK_NO_ERROR);

        if (status != PRO_TK_NO_ERROR) continue;
	fprintf(fp,"\t\tValue: [%4.2lf]\n",value);

	status = ProSecdimTypeGet(section,dim_ids[j],&dim_type);
        TEST_CALL_REPORT("ProSecdimTypeGet()",
			 "ProUtilSectionInfoGet()",
		         status, status != PRO_TK_NO_ERROR);
        if (status != PRO_TK_NO_ERROR) continue;

        switch(dim_type)
	{
	    case PRO_TK_DIM_LINE:
		 strcpy(d_type,"PRO_TK_DIM_LINE");
		 break;
            case PRO_TK_DIM_LINE_POINT:
		 strcpy(d_type,"PRO_TK_DIM_LINE_POINT");
		 break;
            case PRO_TK_DIM_RAD:
		 strcpy(d_type,"PRO_TK_DIM_RAD");
		 break;
            case PRO_TK_DIM_DIA:
		 strcpy(d_type,"PRO_TK_DIM_DIA");
		 break;
            case PRO_TK_DIM_LINE_LINE:
		 strcpy(d_type,"PRO_TK_DIM_LINE_LINE");
		 break;
            case PRO_TK_DIM_PNT_PNT:
		 strcpy(d_type,"PRO_TK_DIM_PNT_PNT");
		 break;
            case PRO_TK_DIM_PNT_PNT_HORIZ:
		 strcpy(d_type,"PRO_TK_DIM_PNT_PNT_HORIZ");
		 break;
            case PRO_TK_DIM_PNT_PNT_VERT:
		 strcpy(d_type,"PRO_TK_DIM_PNT_PNT_VERT");
		 break;
            case PRO_TK_DIM_AOC_AOC_TAN_HORIZ:
		 strcpy(d_type,"PRO_TK_DIM_AOC_AOC_TAN_HORIZ");
		 break;
            case PRO_TK_DIM_AOC_AOC_TAN_VERT:
		 strcpy(d_type,"PRO_TK_DIM_AOC_AOC_TAN_VERT");
		 break;
            case PRO_TK_DIM_ARC_ANGLE:
		 strcpy(d_type,"PRO_TK_DIM_ARC_ANGLE");
		 break;
            case PRO_TK_DIM_LINES_ANGLE:
		 strcpy(d_type,"PRO_TK_DIM_LINES_ANGLE");
		 break;
            case PRO_TK_DIM_LINE_AOC:
		 strcpy(d_type,"PRO_TK_DIM_LINE_AOC");
		 break;
            case PRO_TK_DIM_LINE_CURVE_ANGLE:
		 strcpy(d_type,"PRO_TK_DIM_LINE_CURVE_ANGLE");
		 break;
            case PRO_TK_DIM_CONIC_PARAM:
		 strcpy(d_type,"PRO_TK_DIM_CONIC_PARAM");
		 break;
            case PRO_TK_DIM_NONE:
		 strcpy(d_type,"PRO_TK_DIM_NONE");
		 break;
            default:
		 strcpy(d_type,"PRO_TK_DIM_TYPE_UNKNOWN");
		 break;
        }
	fprintf(fp,"\t\tType: %s\n",d_type);

        status = ProSecdimReferencesGet(section,dim_ids[j],&ref_ids,
					&p_types,&n_ref_ids);
        TEST_CALL_REPORT("ProSecdimReferencesGet()",
			 "ProUtilSectionInfoGet()",
		         status, status != PRO_TK_NO_ERROR);
        if (status != PRO_TK_NO_ERROR) continue;

        fprintf(fp,"\t\tDimension References:\n");
        for (k=0; k<n_ref_ids; k++)
	{
	    p_type = ProUtilSectionPointTypeStr(p_types[k]);
            fprintf(fp,"\t\t\tRef%d: Entity Id [%d], Point Type %s\n",
		    k,ref_ids[k],p_type);
        }

	status = ProArrayFree((ProArray*)&p_types);
        TEST_CALL_REPORT("ProArrayFree()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);
	status = ProArrayFree((ProArray*)&ref_ids);
        TEST_CALL_REPORT("ProArrayFree()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);
	fprintf(fp,"\n");
    }

    status = ProArrayFree((ProArray*)&dim_ids);
    TEST_CALL_REPORT("ProArrayFree()",
	    "ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);

/*------------------------------------------------*\
    Section constarins
\*------------------------------------------------*/
#if 1
    status = ProSectionConstraintsIdsGet(section, &con_ids,&n_conids);
    TEST_CALL_REPORT("ProSectionConstraintsIdsGet()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);

    fprintf(fp,"\n");
    for (j=0; j<n_conids; j++)
    {
	fprintf(fp,"\tConstraint Id: [%d]\n",con_ids[j]);

        status = ProSectionConstraintsGet(section, con_ids[j],
	    &con_type, &con_status, &n_ref_ids, &ref_ids, &p_types);
	TEST_CALL_REPORT("ProSectionConstraintsGet()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);

	if (status != PRO_TK_NO_ERROR)
	    continue;

        switch(con_type)
	{
	    case PRO_CONSTRAINT_TYPE_UNKNOWN:
		 c_type = "PRO_CONSTRAINT_TYPE_UNKNOWN";
		 break;
            case PRO_CONSTRAINT_SAME_POINT:
		 c_type = "PRO_CONSTRAINT_SAME_POINT";
		 break;
            case PRO_CONSTRAINT_HORIZONTAL_ENT:
		 c_type = "PRO_CONSTRAINT_HORIZONTAL_ENT";
		 break;
            case PRO_CONSTRAINT_VERTICAL_ENT:
		 c_type = "PRO_CONSTRAINT_VERTICAL_ENT";
		 break;
            case PRO_CONSTRAINT_PNT_ON_ENT:
		 c_type = "PRO_CONSTRAINT_PNT_ON_ENT";
		 break;
            case PRO_CONSTRAINT_TANGENT_ENTS:
		 c_type = "PRO_CONSTRAINT_TANGENT_ENTS";
		 break;
            case PRO_CONSTRAINT_PARALLEL_ENTS:
		 c_type = "PRO_CONSTRAINT_PARALLEL_ENTS";
		 break;
            case PRO_CONSTRAINT_ORTHOG_ENTS:
		 c_type = "PRO_CONSTRAINT_ORTHOG_ENTS";
		 break;
            case PRO_CONSTRAINT_EQUAL_SEGMENTS:
		 c_type = "PRO_CONSTRAINT_EQUAL_SEGMENTS";
		 break;
            case PRO_CONSTRAINT_EQUAL_RADII:
		 c_type = "PRO_CONSTRAINT_EQUAL_RADII";
		 break;
            case PRO_CONSTRAINT_SYMMETRY:
		 c_type = "PRO_CONSTRAINT_SYMMETRY";
		 break;
            case PRO_CONSTRAINT_SAME_COORD:
		 c_type = "PRO_CONSTRAINT_SAME_COORD";
		 break;
            default:
		 c_type = "Unknown";
		 break;
        }

        switch(con_status)
	{
	    case PRO_TK_CONSTRAINT_DENIED:
		c_status = "PRO_TK_CONSTRAINT_DENIED";
		break;
	    case PRO_TK_CONSTRAINT_ENABLED:
		c_status = "PRO_TK_CONSTRAINT_ENABLED";
		break;
            default:
		c_status = "Unknown";
		break;
	}

	fprintf(fp,"\t\tType: %-30s Status: %s\n", c_type, c_status);

        fprintf(fp,"\t\tConstraint References:\n");
        for (k=0; k<n_ref_ids; k++)
	{
	    p_type = ProUtilSectionPointTypeStr(p_types[k]);
            fprintf(fp,"\t\t\tRef%d: Entity Id [%d], Point Type %s\n",
		    k,ref_ids[k],p_type);
        }

	status = ProArrayFree((ProArray*)&p_types);
        TEST_CALL_REPORT("ProArrayFree()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);
	status = ProArrayFree((ProArray*)&ref_ids);
        TEST_CALL_REPORT("ProArrayFree()",
		"ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);
	fprintf(fp,"\n");
    }

    status = ProArrayFree((ProArray*)&con_ids);
    TEST_CALL_REPORT("ProArrayFree()",
	    "ProUtilSectionInfoGet()", status, status != PRO_TK_NO_ERROR);
#endif

    return(status);
}

/*====================================================================*\
    FUNCTION :	ProUtilSectionRetr
    PURPOSE  :	Retrieves a 2D section
\*====================================================================*/
ProError ProUtilSectionRetr(ProSection *section)
{
    ProFamilyName sec_name;
    ProError status;
    char str[100];
    char *p;

    ProUtilMsgPrint("gen","TEST %0s","Enter section name to retrieve: ");
    if (!ProUtilStringGet(sec_name,NULL,PRO_NAME_SIZE-1))
	 return(PRO_TK_GENERAL_ERROR);

    ProWstringToString( str, sec_name );
    if( (p = strchr( str, '.')) != NULL )
	*p = '\0';
    printf("Section name %s.sec\n",str);
    ProStringToWstring( sec_name, str );
    status = ProMdlRetrieve(sec_name,PRO_MDL_2DSECTION,(ProMdl *)section);
    TEST_CALL_REPORT("ProMdlRetrieve()", "ProUtilSectionRetr()",
		     status, status != PRO_TK_NO_ERROR);
    return(status);
}

/*====================================================================*\
    FUNCTION :  ProUtilSectionSave
    PURPOSE  :  Saves a 2D section
\*====================================================================*/
ProError ProUtilSectionSave(ProSection section)
{
    ProError status;

    status = ProMdlSave((ProMdl) section);
    TEST_CALL_REPORT("ProMdlSave()", "ProUtilSectionSave()",
                     status, status != PRO_TK_NO_ERROR);
    return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilSectionErase
    PURPOSE  :  Erases a 2D section
\*====================================================================*/
ProError ProUtilSectionErase(ProSection section)
{
    ProError status;

    status = ProMdlErase((ProMdl) section);
    TEST_CALL_REPORT("ProMdlErase()", "ProUtilSectionErase()",
                     status, status != PRO_TK_NO_ERROR);
    return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilSectionDelete
    PURPOSE  :  Delete a 2D section
\*====================================================================*/
ProError ProUtilSectionDelete(ProSection section)
{
    ProError status;

    status = ProMdlDelete((ProMdl) section);
    TEST_CALL_REPORT("ProMdlDelete()", "ProUtilSectionDelete()",
                     status, status != PRO_TK_NO_ERROR);
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProUtilLinesParallel
    PURPOSE  :	Check if two lines are parallel (returns 1) to each other
\*====================================================================*/
int ProUtilLinesParallel(double line1[2][3],double line2[2][3])
{
     double vec1[3], vec2[3];

     ProUtilVectorDiff(line1[0],line1[1],vec1);
     ProUtilVectorDiff(line2[0],line2[1],vec2);

     ProUtilVectorNormalize(vec1,vec1);
     ProUtilVectorNormalize(vec2,vec2);

     if ( (1.0-fabs(ProUtilVectorDot(vec1,vec2))) <= EPSM6 )
	  return(1);

     return(0);
}

/*====================================================================*\
    FUNCTION :	ProUtilLinesPerpend
    PURPOSE  :	Check if two lines are perpendicular (returns 1)
\*====================================================================*/
int ProUtilLinesPerpend(double line1[2][3],double line2[2][3])
{
     double vec1[3], vec2[3];

     ProUtilVectorDiff(line1[0],line1[1],vec1);
     ProUtilVectorDiff(line2[0],line2[1],vec2);

     ProUtilVectorNormalize(vec1,vec1);
     ProUtilVectorNormalize(vec2,vec2);

     if ( fabs(ProUtilVectorDot(vec1,vec2) ) <= EPSM6 )
	  return(1);

     return(0);
}

/*====================================================================*\
    FUNCTION :	ProUtilLineLineX
    PURPOSE  :	Get the intersection point of two lines
\*====================================================================*/
double *ProUtilLineLineX(
     double l1[2][3],
     double l2[2][3],
     double int_pnt[3])
{
     double v1[3], v2[3], v3[3], v4[4];
     double n[3],n1[3], n2[3];

     /* if lines parallel return NULL */
     if ( ProUtilLinesParallel(l1,l2) )
	 return(NULL);

     ProUtilVectorDiff(l1[0],l1[1],v1);
     ProUtilVectorDiff(l2[0],l2[1],v2);

     if ((fabs(l1[0][0]-l2[0][0])<= EPSM6) &&
         (fabs(l1[0][1]-l2[0][1])<= EPSM6) &&
         (fabs(l1[0][2]-l2[0][2])<= EPSM6))
     {
	 memcpy(int_pnt,l1[0],3*sizeof(double));
	 return(int_pnt);
     }

     if ((fabs(l1[1][0]-l2[1][0])<= EPSM6) &&
         (fabs(l1[1][1]-l2[1][1])<= EPSM6) &&
         (fabs(l1[1][2]-l2[1][2])<= EPSM6))
     {
	 memcpy(int_pnt,l1[1],3*sizeof(double));
	 return(int_pnt);
     }

     ProUtilVectorDiff(l1[0],l2[0],v3);
     ProUtilVectorDiff(l1[1],l2[1],v4);
     ProUtilVectorCross(v1,v2,n1);
     ProUtilVectorCross(v3,v4,n2);
     ProUtilVectorNormalize(n1,n1);
     ProUtilVectorNormalize(n2,n2);

     /* if lines not on same plane return NULL */
     if ( (1.0 - fabs(ProUtilVectorDot(n1,n2))) >= EPSM6 )
	  return(NULL);

     ProUtilVectorNormalize(v1,v1);
     ProUtilVectorNormalize(v2,v2);
     ProUtilVectorCross(n1,v1,n);
     ProUtilPlaneLineX(l1[0],n,l2[0],v2,int_pnt);

     return(int_pnt);

}

/*====================================================================*\
    FUNCTION :	ProUtilParallelLineEntityGet
    PURPOSE  :	Given sk line ent and array of line ents - finds first
		parallel entity
\*====================================================================*/
ProError ProUtilParallelLineEntityGet(
    ProSection section,
    int ent_id,
    int ent_ids[],
    int n_ids,
    int *parallel_index)
{
    ProError status;
    Pro2dLinedef *line;
    int i;
    double l1[2][3];
    double l2[2][3];

    status = ProSectionEntityGet(section,ent_id,(Pro2dEntdef **)&line);
    TEST_CALL_REPORT("ProSectionEntityGet()",
		     "ProUtilParallelLineEntityGet()",
                     status, status != PRO_TK_NO_ERROR);

    if (!(line->type == PRO_2D_LINE || line->type == PRO_2D_CENTER_LINE))
	return(PRO_TK_GENERAL_ERROR);

    l1[0][0] = line->end1[0];
    l1[0][1] = line->end1[1];
    l1[1][0] = line->end2[0];
    l1[1][1] = line->end2[1];
    l1[0][2] = l1[1][2] = 0.0;

    for (i=0; i<n_ids; i++)
    {
	status = ProSectionEntityGet(section,ent_ids[i],
				    (Pro2dEntdef **)&line);
        TEST_CALL_REPORT("ProSectionEntityGet()",
		         "ProUtilParallelLineEntityGet()",
                         status, status != PRO_TK_NO_ERROR);

        if (!(line->type == PRO_2D_LINE || line->type == PRO_2D_CENTER_LINE))
	    return(PRO_TK_GENERAL_ERROR);

        l2[0][0] = line->end1[0];
        l2[0][1] = line->end1[1];
        l2[1][0] = line->end2[0];
        l2[1][1] = line->end2[1];
        l2[0][2] = l2[1][2] = 0.0;

        if (ProUtilLinesParallel(l1,l2))
	{
	    *parallel_index = i;
	    return(PRO_TK_NO_ERROR);
        }
    }

    return(PRO_TK_E_NOT_FOUND);
}

/*====================================================================*\
    FUNCTION :  ProUtilSketchCsysGet
    PURPOSE  :  Gets the sketch csys transform
\*====================================================================*/
ProError ProUtilSketchCsysGet(
    ProTestSectionInfo *p_sketch_refs,
    double sk_transf[4][4])
{
    int status;

    status = ProSectionLocationGet(p_sketch_refs->section,sk_transf);
    TEST_CALL_REPORT("ProSectionLocationGet()","ProUtilSketchCsysGet()",
		     status, status != PRO_TK_NO_ERROR);

    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProUtilSectCsysTransformGet
    PURPOSE  :	Given a plane selection and two orthogonal lines on
		the plane defining a csys, output transform from this
		csys to plane csys (selection point is used to determine
		x and y vectors such that the point is in the first
		quadrant) (currently works for part mode)
\*====================================================================*/
ProError ProUtilSectCsysTransformGet(
     ProTestSectionInfo *p_sketch_refs,
     double sk_transf[4][4],
     double l1[2][3],
     double l2[2][3],
     double transform[4][4],
     double *angle)
{

     ProMatrix inv_sk_transf;
     Pro3dPnt origin, sel_pnt, proj_sel_pnt;
     ProVector n, v, n1, plane_x;
     ProVector x, y, z_vec={0,0,1};
     double dot;
     ProSurface p_plane;
     ProModelitem mdlitem;
     ProError status;

     ProUtilLineLineX(l1,l2,origin);

     status = ProSelectionModelitemGet(p_sketch_refs->sketch_pln,&mdlitem);
     TEST_CALL_REPORT("ProSelectionModelitemGet()",
		      "ProUtilSectCsysTransformGet()",
		      status, status != PRO_TK_NO_ERROR);

     status = ProSurfaceInit(mdlitem.owner,mdlitem.id,&p_plane);
     TEST_CALL_REPORT("ProSurfaceInit()",
		      "ProUtilSectCsysTransformGet()",
		      status, status != PRO_TK_NO_ERROR);

     status = ProSurfaceXyzdataEval(p_plane,p_sketch_refs->sketch_uv,
				    sel_pnt,NULL,NULL,NULL);
     TEST_CALL_REPORT("ProSurfaceXyzdataEval()",
		      "ProUtilSectCsysTransformGet()",
		      status, status != PRO_TK_NO_ERROR);

     ProUtilVectorDiff(l1[0],l1[1],x);
     ProUtilVectorNormalize(x,x);
     ProUtilVectorDiff(l2[0],l2[1],y);
     ProUtilVectorNormalize(y,y);

     ProUtilMatrixInvert(sk_transf,inv_sk_transf);
     ProUtilPointTrans(inv_sk_transf,sel_pnt,proj_sel_pnt);
     proj_sel_pnt[2] = 0.0;

     ProUtilVectorDiff(proj_sel_pnt,origin,v);
     v[2] = 0.0;
     ProUtilVectorNormalize(v,v);

     /* make sure sel pnt is in first quadrant */

     dot = ProUtilVectorDot(v,x);
     if ( dot < 0.0 )
	  ProUtilVectorScale(-1.0,x,x);
     dot = ProUtilVectorDot(v,y);
     if ( dot < 0.0 )
	  ProUtilVectorScale(-1.0,y,y);

     /* make sure x and y are correct relative to plane normal */
     ProUtilVectorCross(x,y,n);
     if ( n[2] < 0.0 )
     {
	ProUtilVectorCopy(x, n);
	ProUtilVectorCopy(y, x);
	ProUtilVectorCopy(n, y);
     }

     status = ProMatrixInit(x, y, z_vec, origin, transform);
     TEST_CALL_REPORT("ProMatrixInit()",
	"ProUtilSectCsysTransformGet()",  status, status != PRO_TK_NO_ERROR);

     /* calculate rotation angle */
     plane_x[0] = 1.0;
     plane_x[1] = plane_x[2] = 0.0;
     ProUtilVectorCross(x,y,n);
     ProUtilVectorCross(plane_x,x,n1);
     *angle = fabs(acos(ProUtilVectorDot(plane_x,x)));
     if (ProUtilVectorDot(n,n1) < 0.0)
	  *angle *= -1.0;

     return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProUtilTwoOrthogEdgesOnPlaneGet
    PURPOSE  :	Gets the selection of two orthogonal edges on sketch
		plane from the user
\*====================================================================*/
ProError ProUtilTwoOrthogEdgesOnPlaneGet(
    ProSection section,
    int ent_ids[2],
    double edge1[2][3],
    double edge2[2][3])
{

    int status;
    double edges[2][2][3];
    ProSelection *p_sels;
    int n_edges,i;
    int error = 0, cont = 1;
    Pro2dLinedef *linedef;

    while (cont)
    {
         ProUtilMsgPrint("sec","TEST Select two orthogonal edges.");
	 status = ProSelect("edge",2,NULL,NULL,NULL,NULL,&p_sels,&n_edges);
	 TEST_CALL_REPORT("ProSelect()", "ProUtilTwoOrthogEdgesOnPlaneGet()",
	                   status, status != PRO_TK_NO_ERROR);

	 if (n_edges < 2) return(PRO_TK_GENERAL_ERROR);

	 for (i=0; i<2; i++)
	 {
              status = ProSectionEntityFromProjection(section,p_sels[i],
							   &ent_ids[i]);
              TEST_CALL_REPORT("ProSectionEntityFromProjection()",
			       "ProUtilTwoOrthogEdgesOnPlaneGet()",
			       status, status != PRO_TK_NO_ERROR);

	      if (status == PRO_TK_NO_ERROR)
	      {
                   status = ProSectionEntityGet(section,ent_ids[i],
						(Pro2dEntdef **)&linedef);
                   TEST_CALL_REPORT("ProSectionEntityGet()",
				    "ProUtilTwoOrthogEdgesOnPlaneGet()",
				    status, status != PRO_TK_NO_ERROR);
              }
	      else
	      {
                   ProUtilMsgPrint("sec",
			"TEST One of the edges is perpendicular to sketch plane.");
		   error = 1;
		   break;
              }

	      edges[i][0][0] = linedef->end1[0];
	      edges[i][0][1] = linedef->end1[1];
	      edges[i][0][2] = 0.0;
	      edges[i][1][0] = linedef->end2[0];
	      edges[i][1][1] = linedef->end2[1];
	      edges[i][1][2] = 0.0;
         }
	 if (error)
	 {
	      error = 0;
	      continue;
         }

         if (!ProUtilLinesPerpend(edges[0],edges[1]))
	 {
	      ProUtilMsgPrint("sec", "TEST Edges are not orthogonal.");
              continue;
         }
	 else
	 {
	      ProUtilVectorCopy(edges[0][0],edge1[0]);
	      ProUtilVectorCopy(edges[0][1],edge1[1]);
	      ProUtilVectorCopy(edges[1][0],edge2[0]);
	      ProUtilVectorCopy(edges[1][1],edge2[1]);
              break;
         }
    }

    return(PRO_TK_NO_ERROR);
}

void ProUtil2DPointTrans(
    double m[4][4],
    double p2D[2],
    double out2D[2])
{
    double p3D[3];
    double out3D[3];

    p3D[0] = p2D[0];
    p3D[1] = p2D[1];
    p3D[2] = 0.0;

    ProUtilPointTrans(m,p3D,out3D);

    out2D[0] = out3D[0];
    out2D[1] = out3D[1];
}

/*====================================================================*\
    FUNCTION :	ProUtilXyOffsetsGet
    PURPOSE  :	Gets xy offsets from the user
\*====================================================================*/
ProError ProUtilXyOffsetsGet(
    double offsets[2])
{

    ProUtilMsgPrint("sec",
	"TEST Enter offset dimension from first reference [%0(6.4)f]: ",&offsets[0]);
    ProUtilDoubleGet(NULL,&offsets[0],&offsets[0]);
    ProUtilMsgPrint("sec",
	"TEST Enter offset dimension from second reference [%0(6.4)f]: ",&offsets[1]);
    ProUtilDoubleGet(NULL,&offsets[1],&offsets[1]);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProUtilSectEpsModify
    PURPOSE  :	Allows interactive section epsilon modification
\*====================================================================*/
ProError ProUtilSectEpsModify(
    ProSection section)
{
    double eps;
    int status;

    status = ProSectionEpsilonGet(section,&eps);
    TEST_CALL_REPORT("ProSectionEpsilonGet()", "ProUtilSectEpsModify()",
		     status, status != PRO_TK_NO_ERROR);

    ProUtilMsgPrint("sec","TEST Enter section solver epsilon [%0(6.4)f]: ",&eps);
    ProUtilDoubleGet(NULL,&eps,&eps);

    status = ProSectionEpsilonSet(section,eps);
    TEST_CALL_REPORT("ProSectionEpsilonSet()", "ProUtilSectEpsModify()",
		     status, status != PRO_TK_NO_ERROR);

    return(PRO_TK_NO_ERROR);
}
/*====================================================================*\
    FUNCTION :	ProUtilSectionUseExisting
    PURPOSE  :	Top level function for extracting existing section
		definition and applying it to a new section
\*====================================================================*/
ProError ProUtilSectionUseExisting(ProSection new_section,
				   ProTestSectionInfo *secinfo)
{
    ProSection exist_section;
    ProError status;
    ProSelection *sel = NULL;
    int proj_ent, n;
    double transf[4][4];
    double inv_transf[4][4];
    ProVector d1,d2;
    ProSectionPointType pnt_types[2];
    ProIntlist ids;
    int n_ids;
    double orig_3d[3],origin[3];
    double ent_origin[3];
    double ref_pnt3d[3],ref_pnt[3];
    int ent_ids[2], id,i;
    Pro2dPnt dim_pnt;
    ProVector trans_vector;
    ProModelitem mdlitem;
    ProSurface p_plane;
    ProBoolean is_proj;
    Pro2dEntdef *entity;

/*--------------------------------------------------------------------*\
Retrieve existing section from
\*--------------------------------------------------------------------*/
    status = ProUtilSectionRetrieve(&exist_section);

    if (status != PRO_TK_NO_ERROR)
	return(PRO_TK_GENERAL_ERROR);
#if 0
    status = ProSectionCheck(exist_section, &sec_error, &sec_info)
    TEST_CALL_REPORT("ProSectionEntityIdsGet()",
		     "ProUtilSectionUseExisting()",
	             status, status != PRO_TK_NO_ERROR);
#endif

/*--------------------------------------------------------------------*\
If 2D section copy the section as is
\*--------------------------------------------------------------------*/
    if (secinfo == NULL)
    {
        ProUtilVectorCopy(NULL,trans_vector);
        status = ProUtilSectionInfoCopy(exist_section,new_section,
					trans_vector);
    }
/*--------------------------------------------------------------------*\
Else copy, translate and locate 3D section as necessary
\*--------------------------------------------------------------------*/
    else
    {
/*--------------------------------------------------------------------*\
Get tranform to new section coordinates
\*--------------------------------------------------------------------*/
	status = ProUtilSketchCsysGet(secinfo, transf);
        ProUtilMatrixInvert(transf, inv_transf);

/*--------------------------------------------------------------------*\
Find start vertex of first section-defining entity to use to locate sect
\*--------------------------------------------------------------------*/
        status = ProSectionEntityIdsGet(exist_section,&ids,&n_ids);
	TEST_CALL_REPORT("ProSectionEntityIdsGet()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

        for (i=0; i<n_ids; i++)
	{
	    status = ProSectionEntityGet(exist_section,ids[i],
					          &entity);
	    TEST_CALL_REPORT("ProSectionEntityGet()",
			     "ProUtilSectionUseExisting()",
	                     status, status != PRO_TK_NO_ERROR);
            if (entity->type != PRO_2D_CENTER_LINE)
	    {
                status = ProSectionEntityEval(exist_section,ids[i],0.0,
				          ent_origin,d1,d2);
	        TEST_CALL_REPORT("ProSectionEntityEval()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);
                break;
            }
        }

        status = ProArrayFree( (ProArray *) &ids);
	TEST_CALL_REPORT("ProArrayFree()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

     if(secinfo->sketch_pln != NULL)
      {
/*--------------------------------------------------------------------*\
Get sect location point from selection (new origin)
\*--------------------------------------------------------------------*/
        status = ProSelectionModelitemGet(secinfo->sketch_pln,&mdlitem);
        TEST_CALL_REPORT("ProSelectionModelitemGet()",
		      "ProUtilSectionUseExisting()",
		      status, status != PRO_TK_NO_ERROR);
        status = ProSurfaceInit(mdlitem.owner,mdlitem.id,&p_plane);
        TEST_CALL_REPORT("ProSurfaceInit()",
		      "ProUtilSectionUseExisting()",
		      status, status != PRO_TK_NO_ERROR);
        status = ProSurfaceXyzdataEval(p_plane,secinfo->sketch_uv,
				    orig_3d,NULL,NULL,NULL);
        TEST_CALL_REPORT("ProSurfaceXyzdataEval()",
		      "ProUtilSectionUseExisting()",
		      status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
Calc trans vector to move first ent pnt to location pnt
\*--------------------------------------------------------------------*/
        ProUtilPointTrans(inv_transf,orig_3d,origin);
	origin[2] = 0.0;
        ProUtilVectorDiff(origin,ent_origin,trans_vector);
       }
      else
       {
         origin[0] = 0.0;
         origin[1] = 0.0;
         origin[2] = 0.0;
         ProUtilVectorCopy(NULL,trans_vector);
       }
/*--------------------------------------------------------------------*\
Copy and translate existing section entities to new section
\*--------------------------------------------------------------------*/
        status = ProUtilSectionInfoCopy(exist_section,new_section,
					trans_vector);

/*--------------------------------------------------------------------*\
Choose a model vertex to dimension section (first ent start pnt) to
\*--------------------------------------------------------------------*/
        ProUtilMsgPrint("gen","TEST %0s",
			"Select a vertex as the section location reference.");
	status = ProSelect("edge_end",1,NULL,NULL,NULL,NULL,&sel,&n);
	TEST_CALL_REPORT("ProSelect()", "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

        if (status != PRO_TK_NO_ERROR) return(PRO_TK_GENERAL_ERROR);

        status = ProSectionEntityFromProjection(new_section,sel[0],
						&proj_ent);
	TEST_CALL_REPORT("ProSectionEntityFromProjection()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

        status = ProSelectionPoint3dGet(sel[0],ref_pnt3d);
	TEST_CALL_REPORT("ProSelectionPoint3dGet()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);
        ProUtilPointTrans(inv_transf,ref_pnt3d,ref_pnt);
	ref_pnt[2] = 0;

/*--------------------------------------------------------------------*\
Find the first section defining entity in the new section
\*--------------------------------------------------------------------*/
        status = ProSectionEntityIdsGet(new_section,&ids,&n_ids);
	TEST_CALL_REPORT("ProSectionEntityIdsGet()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

        for (i=0; i<n_ids; i++)
	{
	    status = ProSectionEntityGet(new_section,ids[i],
					          &entity);
	    TEST_CALL_REPORT("ProSectionEntityGet()",
			     "ProUtilSectionUseExisting()",
	                     status, status != PRO_TK_NO_ERROR);
	    status = ProSectionEntityIsProjection(new_section,ids[i],
					          &is_proj);
	    TEST_CALL_REPORT("ProSectionEntityIsProjection()",
			     "ProUtilSectionUseExisting()",
	                     status, status != PRO_TK_NO_ERROR);

            if (entity->type != PRO_2D_CENTER_LINE &&
		is_proj == PRO_B_FALSE)
	    {
		ent_ids[1] = ids[i];
                break;
            }
        }


/*--------------------------------------------------------------------*\
Create horiz and vertical pnt to pnt dims from first ent start pnt
to projected vertex pnt to locate the section
\*--------------------------------------------------------------------*/
	ent_ids[0] = proj_ent;
	pnt_types[0] = PRO_ENT_CENTER;
	pnt_types[1] = PRO_ENT_START;
	dim_pnt[0] = origin[0] + (ref_pnt[0] - origin[0])/2.0;
	dim_pnt[1] = origin[1];
	status = ProSecdimCreate(new_section,ent_ids,pnt_types,
			 2,PRO_TK_DIM_PNT_PNT_HORIZ,dim_pnt,&id);
	TEST_CALL_REPORT("ProSectionEntityEval()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);
	dim_pnt[0] = origin[0];
	dim_pnt[1] = origin[1] + (ref_pnt[1] - origin[1])/2.0;
	status = ProSecdimCreate(new_section,ent_ids,pnt_types,
			 2,PRO_TK_DIM_PNT_PNT_VERT,dim_pnt,&id);
	TEST_CALL_REPORT("ProSectionEntityEval()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

        ProArrayFree( (ProArray *) &ids);
	TEST_CALL_REPORT("ProArrayFree()",
			 "ProUtilSectionUseExisting()",
	                 status, status != PRO_TK_NO_ERROR);

    }

    status = ProTestSectionSolveRegen(new_section);

    return(status);
}
/*====================================================================*\
    FUNCTION :	ProUtilSectionInfoCopy
    PURPOSE  :	Copies section defining entities to a new section
		applying translation vector
\*====================================================================*/
ProError ProUtilSectionInfoCopy(ProSection exist_section,
				ProSection new_section,
				ProVector trans_vector)
{
    ProError err;
    ProIntlist ent_ids, new_ent_ids;
    int n_ids,i,j,k;
    ProBoolean is_proj;
    Pro2dEntdef *p_entity;
    ProIntlist dim_ids;
    int n_dim_ids,*p_ent_refs;
    ProSecdimType d_type;
    ProSectionPointType *p_pnt_types;
    int n_refs,new_ent_refs[5],dim_id, tmp_id;
    ProBoolean ref_proj;
    ProVector mid_pnt, d1, d2;
    Pro2dPnt dim_pnt;
    Pro2dPointdef dim_loc;

    err = ProSectionEntityIdsGet(exist_section,&ent_ids,&n_ids);
    TEST_CALL_REPORT("ProSectionEntityIdsGet()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

    err = ProArrayAlloc(n_ids,sizeof(ProIntlist),n_ids,
			(ProArray *)&new_ent_ids);
    TEST_CALL_REPORT("ProArrayAlloc()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

    for (i=0; i<n_ids; i++)
    {
	err = ProSectionEntityIsProjection(exist_section,ent_ids[i],
					   &is_proj);
        TEST_CALL_REPORT("ProSectionEntityIsProjection()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        if (is_proj == PRO_B_TRUE)
	{
	    new_ent_ids[i] = -1;
	    continue;
        }

        err = ProSectionEntityGet(exist_section,ent_ids[i],&p_entity);
        TEST_CALL_REPORT("ProSectionEntityGet()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        if (err != PRO_TK_NO_ERROR)
	{
	    printf(
        "ProUtilSectionInfoCopy Section Entity Id: %d not suppported\n",
		   ent_ids[i]);
	    continue;
        }


        err = ProSectionEntityAdd(new_section,p_entity,
				  &new_ent_ids[i]);
        TEST_CALL_REPORT("ProSectionEntityAdd()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        err = ProSectionEntityTranslate(new_section,new_ent_ids[i],
					trans_vector);
        TEST_CALL_REPORT("ProSectionEntityTranslate()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);
    }

    err = ProSecdimIdsGet(exist_section,&dim_ids,&n_dim_ids);
    TEST_CALL_REPORT("ProSecdimIdsGet()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

    for (i=0; i<n_dim_ids; i++)
    {
	err = ProSecdimTypeGet(exist_section,dim_ids[i],&d_type);
        TEST_CALL_REPORT("ProSecdimTypeGet()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        err = ProSecdimReferencesGet(exist_section,dim_ids[i],
			      &p_ent_refs,&p_pnt_types,&n_refs);
        TEST_CALL_REPORT("ProSecdimReferencesGet()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        ref_proj = PRO_B_FALSE;
        for (j=0; j<n_refs; j++)
	{
	    err = ProSectionEntityIsProjection(exist_section,
				   p_ent_refs[j],&is_proj);
            TEST_CALL_REPORT("ProSectionEntityFromProjection()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);
	    if ( is_proj == PRO_B_TRUE )
	    {
		ref_proj = PRO_B_TRUE;
		break;
            }
        }

        if (ref_proj == PRO_B_TRUE)
	{
	    ref_proj = PRO_B_FALSE;
	    continue;
        }

        for (j=0; j<n_refs; j++)
	{
	    for (k=0; k<n_ids; k++)
		if ( ent_ids[k] == p_ent_refs[j] )
		    break;

	    new_ent_refs[j] = new_ent_ids[k];
        }

	err = ProSecdimLocationGet(exist_section, dim_ids[i], dim_loc.pnt);
        TEST_CALL_REPORT("ProSecdimLocationGet",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

	dim_loc.type = PRO_2D_POINT;
	err = ProSectionEntityAdd(new_section, (Pro2dEntdef*)&dim_loc, &tmp_id);
        TEST_CALL_REPORT("ProSectionEntityAdd",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        err = ProSectionEntityTranslate(new_section, tmp_id, trans_vector);
        TEST_CALL_REPORT("ProSectionEntityTranslate()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        err = ProSectionEntityEval(new_section, tmp_id, 0, mid_pnt, d1, d2);
        TEST_CALL_REPORT("ProSectionEntityEval()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);

        err = ProSectionEntityDelete(new_section, tmp_id);
        TEST_CALL_REPORT("ProSectionEntityDelete()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);
        dim_pnt[0] = mid_pnt[0];
        dim_pnt[1] = mid_pnt[1];

        err = ProSecdimCreate(new_section,new_ent_refs,
		   p_pnt_types,n_refs,d_type,dim_pnt,&dim_id);
        TEST_CALL_REPORT("ProSecdimCreate()",
			  "ProUtilSectionCopy()", err, err != PRO_TK_NO_ERROR);
    }

    return(err);
}

/*====================================================================*\
    FUNCTION :	ProUtilSectionClean
    PURPOSE  :	Deletes all dimensions and entities from a section
\*====================================================================*/
ProError ProUtilSectionClean(ProSection section)
{
    ProError err;
    ProIntlist ent_ids, dim_ids, constr_ids;
    int n_dim_ids, n_ids, i, n_constr_ids;

#if 1
    err = ProSectionConstraintsIdsGet(section, &constr_ids, &n_constr_ids);
    TEST_CALL_REPORT("ProSectionConstraintsIdsGet()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);

    for (i=0; i<n_constr_ids; i++)
    {
	err = ProSectionConstraintDeny(section, constr_ids[i]);
        TEST_CALL_REPORT("ProSectionConstraintDeny()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);
    }

    err = ProArrayFree( (ProArray *) &constr_ids);
    TEST_CALL_REPORT("ProArrayFree()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);
#endif
    err = ProSecdimIdsGet(section,&dim_ids,&n_dim_ids);
    TEST_CALL_REPORT("ProSecdimIdsGet()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);

    for (i=0; i<n_dim_ids; i++)
    {
	err = ProSecdimDelete(section,dim_ids[i]);
        TEST_CALL_REPORT("ProSecdimDelete()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);
    }

    err = ProArrayFree( (ProArray *) &dim_ids);
    TEST_CALL_REPORT("ProArrayFree()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);

    err = ProSectionEntityIdsGet(section,&ent_ids,&n_ids);
    TEST_CALL_REPORT("ProSectionEntityIdsGet()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);

    for (i=0; i<n_ids; i++)
    {
	err = ProSectionEntityDelete(section,ent_ids[i]);
        TEST_CALL_REPORT("ProSectionEntityDelete()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);
    }

    err = ProArrayFree( (ProArray *) &dim_ids);
    TEST_CALL_REPORT("ProArrayFree()",
		     "ProUtilSectionClean()", err, err != PRO_TK_NO_ERROR);

    return(err);
}



/*====================================================================*\
FUNCTION : ProUtilStdSectInfoFromElemTreeGet
PURPOSE  : Nicely gets the pertinent section info from feat elem tree;
\*====================================================================*/
ProError ProUtilStdSectInfoFromElemTreeGet(ProElement std_sect_elem,
                                        ProTestSectionInfo *secinfo)
{
    ProError status;
    ElemtreeElement *elements;
    int elements_num, i;

    ProError ProStdSectVisitAction();


    status = ProUtilCollectElemtreeElements (std_sect_elem, NULL, &elements);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)elements, &elements_num);
        TEST_CALL_REPORT( "ProArraySizeGet()",
            "ProUtilStdSectInfoFromElemTreeGet()",
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < elements_num; i++)
        {
            status = ProStdSectVisitAction (std_sect_elem,
                elements[i].p_element,
                elements[i].p_elempath, (ProAppData)secinfo);
        }
        status = ProUtilElemtreeElementArrayFree (&elements);
    }
    return(status);
}



/*====================================================================*\
FUNCTION : ProStdSectVisitAction
PURPOSE  : Visit function for getting std section information
\*====================================================================*/
ProError ProStdSectVisitAction(ProElement tree,ProElement element,
                               ProElempath elem_path,
                               ProAppData data)
{
    ProElemId elem_id;
    ProError err;
    ProTestSectionInfo *secinfo;

    ProError ProUtilElementDataGet();


    err = ProElementIdGet(element,&elem_id);
    TEST_CALL_REPORT("ProElementIdGet",
                     "ProStdSectVisitAction",
                     err, err != PRO_TK_NO_ERROR);

    secinfo = (ProTestSectionInfo *)data;

    switch(elem_id)
    {
         case PRO_E_SKETCHER:
              err = ProUtilElementDataGet(element,NULL,0,
                                          &secinfo->section);
              break;
         case PRO_E_STD_SEC_PLANE:
              err = ProUtilElementDataGet(element,NULL,0,
                                          &secinfo->sketch_pln);
              break;
         case PRO_E_STD_SEC_PLANE_VIEW_DIR:
              err = ProUtilElementDataGet(element,NULL,0,
                                          &secinfo->view_dir);
              break;
         case PRO_E_STD_SEC_PLANE_ORIENT_DIR:
              err = ProUtilElementDataGet(element,NULL,0,
                                          &secinfo->orient_dir);
              break;
         case PRO_E_STD_SEC_PLANE_ORIENT_REF:
              err = ProUtilElementDataGet(element,NULL,0,
                                          &secinfo->orient_pln);
              break;
     }

     return(err);
}



/*====================================================================*\
FUNCTION : ProUtilElementDataGet
PURPOSE  : Gets element single value data given tree and path
\*====================================================================*/
ProError ProUtilElementDataGet(ProElement tree,ProElempathItem *path_items,
                               int path_size,void *data)
{
    ProElempath elem_path;
    ProElement element;
    ProError err;
    ProValue value;
    ProValueData vdata;
    int *i;
    double *d;
    void **p;
    char **s;
    wchar_t **w;
    ProSelection *r;

    if (path_items != NULL)
    {
        err = ProElempathAlloc(&elem_path);
        TEST_CALL_REPORT("ProElempathAlloc",
                     "ProUtilElementDataGet",
                     err,err != PRO_TK_NO_ERROR);
        err = ProElempathDataSet(elem_path,path_items,path_size);
        TEST_CALL_REPORT("ProElempathDataSet",
                     "ProUtilElementDataGet",
                     err,err != PRO_TK_NO_ERROR);
        err = ProElemtreeElementGet(tree,elem_path,
                                &element);
        TEST_CALL_REPORT("ProElemtreeElementGet",
                     "ProUtilElementDataGet",err,
                     err != PRO_TK_NO_ERROR);
    }
    else element = tree;

    err = ProElementValueGet(element,&value);
    TEST_CALL_REPORT("ProElementValueGet",
                     "ProUtilElementDataGet",err,
                     err != PRO_TK_NO_ERROR);
    err = ProValueDataGet(value,&vdata);
    TEST_CALL_REPORT("ProValueDataGet",
                     "ProUtilElementDataGet",err,
                     err != PRO_TK_NO_ERROR);

    if (err != PRO_TK_NO_ERROR)
    {
        *(char*)data = (char)NULL;
        return(PRO_TK_GENERAL_ERROR);
    }

    switch(vdata.type)
    {
        case PRO_VALUE_TYPE_INT:
                i = (int*)data;
                *i = vdata.v.i;
                break;
        case PRO_VALUE_TYPE_DOUBLE:
                d = (double*)data;
                *d = vdata.v.d;
                break;
        case PRO_VALUE_TYPE_POINTER:
                p = (void **)data;
                *p = vdata.v.p;
                break;
        case PRO_VALUE_TYPE_STRING:
                s = (char **)data;
                *s = vdata.v.s;
                break;
        case PRO_VALUE_TYPE_WSTRING:
                w = (wchar_t **)data;
                *w = vdata.v.w;
                break;
        case PRO_VALUE_TYPE_SELECTION:
                r = (ProSelection *)data;
                *r = vdata.v.r;
                break;
    }

    if (path_items != NULL)
    {
        err = ProElempathFree(&elem_path);
        TEST_CALL_REPORT("ProElempathFree","ProUtilElementDataGet",
                      err, err != PRO_TK_NO_ERROR);
    }

    return(err);
}

/*====================================================================*\
FUNCTION : ProUtilUseEdge
PURPOSE  : Create "TkSect/-Use Edge/" menu
\*====================================================================*/
int ProUtilUseEdge(ProAppData app_dt, int act)
{   
    int                 ret;
    ProError            status;
    ProUtilMenuButtons  menu [] = 
    {
        {"UseEdge", -1, 0},
            {"-Use Edge",       mnUSE_EDGE,         0},
            {"-SelEdgeChain",   mnUSE_EDGE_CHAIN,   0},
            {"-SelEdgeLoop",    mnUSE_EDGE_LOOP,    0},
            {"-SelCurveChain",  mnUSE_CURVE_CHAIN,  0},
            {"-SelCurveLoop",   mnUSE_CURVE_LOOP,   0},
            {"-Done",           mnUSE_DONE,         0},
        {"",-1, -1}
    };
    ProSection          section = (ProSection)app_dt;

    while(1==1)
    {
        status = ProUtilMenuIntValueSelect (menu, &ret);
    
        if (status != PRO_TK_NO_ERROR)
            break;
    
        switch (ret)
        {
        case mnUSE_EDGE : 
            ret = ProUtilSecEntityUseEdge(section);
            break;
        case mnUSE_EDGE_CHAIN: 
            ret = ProUtilSecEntityUseEdgeChain(section);
            break;
        case mnUSE_EDGE_LOOP : 
            ret = ProUtilSecEntityUseEdgeLoop(section);
            break;
        case mnUSE_CURVE_LOOP:
            ret = ProUtilSecEntityUseCurveLoop (section);
            break;
        case mnUSE_CURVE_CHAIN:
            ret = ProUtilSecEntityUseCurveChain (section);
            break;
        case mnUSE_DONE:
            ProTestSectionSolveRegen (section);
            return 0;
        }
        
        if (ret == -1)
            break;
    }
    return (-1);
}

/*====================================================================*\
FUNCTION : ProUtilSecEntityUseEdge
PURPOSE  : Simulates behavior of Sketcer/Geom Tools/Use Edge/Sel Edge
\*====================================================================*/
int ProUtilSecEntityUseEdge(ProSection section)

{
    int             r_ent_id, sel_count, i;
    ProSelection    *ref_edge, sel;
    ProError        status;

    ProUtilMsgPrint ("sec", "TEST %0s", "Select edge.");
    
    status = ProSelect("edge", -1,NULL,NULL,NULL,NULL, &ref_edge, &sel_count);
    TEST_CALL_REPORT("ProSelection","ProUtilSecEntityUseEdge",
        status, status != PRO_TK_NO_ERROR);
    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
    
    for (i=0; i<sel_count; i++)
    {
        status = ProSelectionCopy (ref_edge[i], &sel);
        TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseEdge",
            status, status != PRO_TK_NO_ERROR);

        status = ProSectionEntityUseEdge(section, sel, &r_ent_id);
        TEST_CALL_REPORT("ProSectionEntityUseEdge","ProUtilSecEntityUseEdge",
            status, status != PRO_TK_NO_ERROR);
    }

    return(0);
}

/*====================================================================*\
FUNCTION : ProUtilSecEntityUseEdgeLoop
PURPOSE  : Simulates behavior of Sketcer/Geom Tools/Use Edge/Sel Loop
\*====================================================================*/
int ProUtilSecEntityUseEdgeLoop(ProSection section)
{
    int             r_ent_id, sel_count, i;
    ProSelection    *sel_ptr = NULL, sel1, sel2;
    ProError        status;
    ProIntlist      p_id_list;

    ProUtilMsgPrint ("sec", "TEST %0s", "Select surface.");
    
    status = ProSelect("surface",1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection","ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);

    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
        
    status = ProSelectionCopy (*sel_ptr, &sel1);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);
    
    ProUtilMsgPrint ("sec", "TEST %0s",
        "Select edge belonging to the contour of the surface.");
    
    status = ProSelect("edge", 1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection","ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);

    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
    
    status = ProSelectionCopy (sel_ptr[0], &sel2);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);

    status = ProSectionEntityUseEdgeLoop (
        section, sel1, sel2, &p_id_list, &r_ent_id);
    TEST_CALL_REPORT("ProSectionEntityUseEdgeLoop",
        "ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);
    printf ("Edge loop IDs:");
    for (i=0; i<r_ent_id; i++)
    {
        printf ("%d\n", p_id_list[i]);
    }
    status = ProArrayFree ((ProArray*)&p_id_list);
    TEST_CALL_REPORT("ProArrayFree", "ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);
    return(0);
}

/*====================================================================*\
FUNCTION : ProUtilSecEntityUseEdge
PURPOSE  : Simulates behavior of Sketcer/Geom Tools/Use Edge/Sel Chain
\*====================================================================*/
int ProUtilSecEntityUseEdgeChain(ProSection section)
{   
    int             i, num, sel_count;
    char            *msg[4] = 
    {
    "Select surface from whose contour the chain of entities should be created.",
    "Select first edge delimiting the chain.",
    "Select second edge delimiting the chain.",
    "Select vertex at the end of the chain."
    };
    char            geomTypes[4][9]={"surface", "edge", "edge", "edge_end"};
    ProSelection    *sel_ptr, sels[4];
    ProError        status;
    ProIntlist       p_id_list;

    for(i=0; i<4; i++)
    {
        ProUtilMsgPrint ("sec", "TEST %0s", msg[i]);
        
        status = ProSelect (geomTypes[i], 1, NULL,NULL,NULL,NULL,
            &sel_ptr, &sel_count);
        TEST_CALL_REPORT("ProSelection",
            "ProUtilSecEntityUseEdgeChain",
            status, status != PRO_TK_NO_ERROR);

        if (status!=PRO_TK_NO_ERROR || sel_count < 1)
            return -1;
        
        status = ProSelectionCopy (*sel_ptr, &sels[i]);
        TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseEdgeChain",
            status, status != PRO_TK_NO_ERROR);

    }

    status = ProSectionEntityUseEdgeChain (section, sels[0], sels[1],
        sels[2], sels[3], &p_id_list, &num);
    TEST_CALL_REPORT("ProSectionEntityUseEdgeChain",
    "ProUtilSecEntityUseEdgeChain", status, status != PRO_TK_NO_ERROR);

    printf ("Edge chain IDs:");
    for (i=0; i<num; i++)
    {
        printf ("%d\n", p_id_list[i]);
    }
    status = ProArrayFree ((ProArray*)&p_id_list);
    TEST_CALL_REPORT("ProArrayFree", "ProUtilSecEntityUseEdgeLoop",
        status, status != PRO_TK_NO_ERROR);

    return(0);
}

/*====================================================================*\
FUNCTION : ProUtilSecEntityUseCurveLoop
PURPOSE  : Adds loop of entities to the specified section creating them
   from projections of 3D curve segments (datum curve, IGES, or pipe
   segments can be selected) .
\*====================================================================*/
int ProUtilSecEntityUseCurveLoop (ProSection section)
{
    int             num_ids, sel_count;
    ProIntlist      id_list;
    ProSelection    *sel_ptr, sel;
    ProError        status;
    
    ProUtilMsgPrint ("sec", "TEST %0s",
        "Select curve belonging to the contour from which" 
        "the loop of entities should be created.");
    
    status = ProSelect("curve", 1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection","ProUtilSecEntityUseCurveLoop",
        status, status != PRO_TK_NO_ERROR);
    
    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
    
    status = ProSelectionCopy (sel_ptr[0], &sel);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseCurveLoop",
        status, status != PRO_TK_NO_ERROR);
    
    status = ProSectionEntityUseCurveLoop (
        section, sel, &id_list, &num_ids);
    TEST_CALL_REPORT("ProSectionEntityUseCurveLoop",
        "ProUtilSecEntityUseCurveLoop", status, status != PRO_TK_NO_ERROR);
    return (0);
}

/*====================================================================*\
FUNCTION : ProUtilSecEntityUseCurveChain
PURPOSE  : AAdds chain of entities to the specified section creating them
   from projections of 3D curve segments (datum curve, IGES, or pipe
   segments can be selected) .
\*====================================================================*/
int ProUtilSecEntityUseCurveChain (ProSection section)
{
    int             num_ids, sel_count;
    ProIntlist      id_list;
    ProSelection    *sel_ptr,sel1, sel2, sel3;
    ProError        status;
    
    ProUtilMsgPrint ("sec", "TEST %0s", "Select first curve.");
    status = ProSelect("curve",1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection", "ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);
    
    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
    
    status = ProSelectionCopy (*sel_ptr, &sel1);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);
        
    ProUtilMsgPrint ("sec", "TEST %0s", "Select second curve.");
    status = ProSelect("curve",1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection", "ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);

    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;
    
    status = ProSelectionCopy (*sel_ptr, &sel2);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);

    ProUtilMsgPrint ("sec", "TEST %0s", "Select vertex at end of the chain.");
    status = ProSelect("curve_end",1,NULL,NULL,NULL,NULL, &sel_ptr, &sel_count);
    TEST_CALL_REPORT("ProSelection", "ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);
    
    if (status!=PRO_TK_NO_ERROR || sel_count < 1)
        return -1;

    status = ProSelectionCopy (*sel_ptr, &sel3);
    TEST_CALL_REPORT("ProSelectionCopy","ProUtilSecEntityUseCurveChain",
        status, status != PRO_TK_NO_ERROR);

    status = ProSectionEntityUseCurveChain (
        section, sel1, sel2, sel3, &id_list, &num_ids);
    TEST_CALL_REPORT("ProSectionEntityUseCurveChain",
        "ProUtilSecEntityUseCurveChain", status, status != PRO_TK_NO_ERROR);
    return (0);
}
