/*
	Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved.
*/

#include <ProToolkit.h>
#include <ProDrawing.h>
#include <ProDimension.h>
#include <ProArray.h>
#include <ProSolid.h>
#include <ProFeature.h>
#include <ProPoint.h>
#include <ProMessage.h>
#include <ProAnnotation.h>
int UsrPointGeomitemsCollect(ProSolid solid, ProGeomitem **points);

/*====================================================================*\ 
FUNCTION: UsrDimPoints() 
PURPOSE  : Command to create a table of datum points 
\*====================================================================*/ 
int UsrDimPoints() {
     ProError status;
     ProSelection *sel, csys_sel;
     int n_sel, n_points, p;
     ProSolid solid;
     ProGeomitem csys_geom;
     ProAsmcomppath csys_comppath;
     ProMatrix trf;
     ProVector csys_pos, csys_3dpos, pnt_pos, dim_pos, outline[2];
     ProGeomitem *points;
     ProDrawing drawing;
     ProSelection *attachments;
     ProDimSense *senses;
     ProDimension dimension, vbase_dim, hbase_dim;
     ProPoint point;
     ProView view;
     ProFileName msgfil;

     ProStringToWstring (msgfil, "msg_ugdrawing.txt");
    
     ProMdlCurrentGet((ProMdl*)&drawing);

/*--------------------------------------------------------------------*\ 
    Select a coordinate system. This defines the model (the top one
     in that view), and the common attachments for the dimensions 
\*--------------------------------------------------------------------*/ 
     ProMessageDisplay(msgfil,"USER Select csys");
     status = ProSelect("csys",1,NULL,NULL,NULL,NULL,&sel,&n_sel);
     if(status != PRO_TK_NO_ERROR || n_sel < 1)
         return(0);

     ProSelectionCopy(sel[0], &csys_sel);
     ProSelectionModelitemGet(csys_sel, &csys_geom);
     ProSelectionAsmcomppathGet(csys_sel, &csys_comppath);

/*--------------------------------------------------------------------*\ 
    Get the root solid 
\*--------------------------------------------------------------------*/ 
     if(csys_comppath.table_num > 0)
         solid = csys_comppath.owner;

     else
         solid = csys_geom.owner;

/*--------------------------------------------------------------------*\ 
    Get a list of datum points in the model 
\*--------------------------------------------------------------------*/ 
     UsrPointGeomitemsCollect(solid, &points);
     ProArraySizeGet(points, &n_points);
     if(n_points < 1)
         return(0);

/*--------------------------------------------------------------------*\ 
    Calculate where the csys is located on the drawing 
\*--------------------------------------------------------------------*/ 
     ProSelectionPoint3dGet(csys_sel, csys_pos);
     if(csys_comppath.table_num > 0)
     {
         ProAsmcomppathTrfGet(&csys_comppath, PRO_B_TRUE, trf);
         ProPntTrfEval(csys_pos, trf, csys_pos);
     }

     memcpy(csys_3dpos, csys_pos, sizeof(ProVector));     
     ProSelectionViewGet(csys_sel, &view);     
     ProDrawingViewTransformGet(drawing, view, PRO_B_TRUE, trf);     
     ProPntTrfEval(csys_pos, trf, csys_pos);

/*--------------------------------------------------------------------*\ 
    Get the view outline 
\*--------------------------------------------------------------------*/ 
     ProDrawingViewOutlineGet(drawing, view, outline);

/*--------------------------------------------------------------------*\ 
    Allocate the attachment arrays 
\*--------------------------------------------------------------------*/ 
     ProArrayAlloc(2, sizeof(ProSelection), 1, (ProArray*)&attachments);
     ProArrayAlloc(2, sizeof(ProDimSense), 1, (ProArray*)&senses);

/*--------------------------------------------------------------------*\ 
    For each datum point... 
\*--------------------------------------------------------------------*/ 
    for(p=0;p<n_points;p++)
     { 
         ProDimAttachment* attachmentsArr = NULL;
/*--------------------------------------------------------------------*\ 
        Calculate the position of the point on the drawing 
\*--------------------------------------------------------------------*/ 
         ProPointInit(points[p].owner, points[p].id, &point);
         ProPointCoordGet(point, pnt_pos);
         ProPntTrfEval(pnt_pos, trf, pnt_pos);

/*--------------------------------------------------------------------*\ 
        Set up the "sense" information for the point attachment
         (Specify a vertical dimension) 
\*--------------------------------------------------------------------*/ 
         senses[0].type = PRO_DIM_SNS_TYP_PNT;
         senses[0].sense = PRO_POINT_TYP_CENTER;
         senses[0].orient_hint = PRO_DIM_ORNT_VERT;

/*--------------------------------------------------------------------*\ 
        Set up the "sense" information for the csys attachment 
\*--------------------------------------------------------------------*/ 
         senses[1].type = PRO_DIM_SNS_TYP_PNT;
         senses[1].sense = PRO_POINT_TYP_CENTER;
         senses[1].orient_hint = PRO_DIM_ORNT_NONE;

/*--------------------------------------------------------------------*\ 
        Set the attachment information 
\*--------------------------------------------------------------------*/ 
         ProSelectionAlloc(NULL, &points[p], &attachments[0]);
         ProSelectionViewSet(view, &attachments[0]);
         ProSelectionCopy(csys_sel, &attachments[1]);


         ProArrayAlloc(2, sizeof(ProDimAttachment), 1, (ProArray*)&attachmentsArr);
         ProSelectionCopy(attachments[0], &attachmentsArr[0][0]);
         ProSelectionCopy(attachments[1], &attachmentsArr[1][0]);
         attachmentsArr[0][1] = NULL;
         attachmentsArr[1][1] = NULL;

/*--------------------------------------------------------------------*\ 
        Calculate the dim position to be just to the left of the
         drawing view, midway between the point and csys 
\*--------------------------------------------------------------------*/ 
         dim_pos[0] = outline[0][0] - 20.0;
         dim_pos[1] = (csys_pos[1] + pnt_pos[1]) / 2.0;
         dim_pos[2] = 0.0;

/*--------------------------------------------------------------------*\ 
        Create and display the dimension 
\*--------------------------------------------------------------------*/ 
         ProDrawingDimensionCreate(drawing, attachmentsArr, senses, PRO_DIM_ORNT_NONE, dim_pos,
                         PRO_B_FALSE, &dimension);

         ProAnnotationShow ((ProAnnotation*)&dimension, NULL, view);

/*--------------------------------------------------------------------*\ 
        If this is the first vertical dim, create an ordinate base
        line from it, else just convert it to ordinate 
\*--------------------------------------------------------------------*/ 
         if(p==0)
             ProDrawingOrdbaselineCreate(drawing, &dimension,
                         csys_3dpos, &vbase_dim);
         else
             ProDrawingDimToOrdinate(drawing, &dimension, &vbase_dim);

/*--------------------------------------------------------------------*\ 
        Set this dimension to be horizontal 
\*--------------------------------------------------------------------*/ 
         senses[0].orient_hint = PRO_DIM_ORNT_HORIZ;

/*--------------------------------------------------------------------*\ 
        Calculate the dim position to be just to the bottom of the
        drawing view, midway between the point and csys 
\*--------------------------------------------------------------------*/ 
         dim_pos[0] = (csys_pos[0] + pnt_pos[0]) / 2.0;
         dim_pos[1] = outline[0][1] - 20.0;

/*--------------------------------------------------------------------*\ 
        Create and display the dimension 
\*--------------------------------------------------------------------*/ 
         ProDrawingDimensionCreate(drawing, attachmentsArr, senses, PRO_DIM_ORNT_NONE, dim_pos,
             PRO_B_FALSE, &dimension);

         ProAnnotationShow ((ProAnnotation*)&dimension, NULL, view);

/*--------------------------------------------------------------------*\ 
        If this is the first horizontal dim, create an ordinate base line
         from it, else just convert it to ordinate 
\*--------------------------------------------------------------------*/ 
         if(p==0)
             ProDrawingOrdbaselineCreate(drawing, &dimension,
                         csys_3dpos, &hbase_dim);

         else
             ProDrawingDimToOrdinate(drawing, &dimension, &hbase_dim);

/*--------------------------------------------------------------------*\ 
        Free the attachment selection objects 
\*--------------------------------------------------------------------*/ 
         ProSelectionFree(&attachments[0]);
         ProSelectionFree(&attachments[1]);
     }

    return(1);
 }

/*====================================================================*\ 
FUNCTION : UsrPointAddAction() 
PURPOSE  : Visit action function called for each datum point 
\*====================================================================*/ 
ProError UsrPointAddAction(
     ProGeomitem *geomitem,
     ProError filt_status,
     ProAppData data) 
{ 
/*--------------------------------------------------------------------*\ 
    Add the point to the array 
\*--------------------------------------------------------------------*/ 
    ProArrayObjectAdd((ProArray*)data, -1, 1, geomitem);
    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\ 
FUNCTION : UsrFeatureGetPointsAction() 
PURPOSE: Visit action function called for each feature 
\*====================================================================*/ 
ProError UsrFeatureGetPointsAction(
     ProFeature *feature,
     ProError filt_status,
     ProAppData data)
 {
     ProFeatStatus fstatus;

/*--------------------------------------------------------------------*\ 
    If the feature is not active, skip it 
\*--------------------------------------------------------------------*/ 
     ProFeatureStatusGet(feature, &fstatus);
     if(fstatus != PRO_FEAT_ACTIVE)
         return(PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\ 
    Visit the datum points in the feature 
\*--------------------------------------------------------------------*/ 
     ProFeatureGeomitemVisit(feature, PRO_POINT, UsrPointAddAction, NULL,
                              data);

     return(PRO_TK_NO_ERROR);
 }

/*====================================================================*\ 
FUNCTION : UsrPointGeomitemsCollect() 
PURPOSE: Collect an array of datum points in the solid 
\*====================================================================*/ 
int UsrPointGeomitemsCollect(
     ProSolid solid,
     ProGeomitem **points)
 { 
   /*--------------------------------------------------------------------*\ 
    Allocate the array 
   \*--------------------------------------------------------------------*/ 
    ProArrayAlloc(0, sizeof(ProGeomitem), 1, (ProArray*)points);

   /*--------------------------------------------------------------------*\ 
    Visit the features 
   \*--------------------------------------------------------------------*/ 
    ProSolidFeatVisit(solid, UsrFeatureGetPointsAction, NULL, points);
 }