Оцените качество кода на С++
От: GhostCoders Россия  
Дата: 18.09.14 09:43
Оценка:
Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.

// SewingDlg.h 
#pragma once

#include "MainHeaders.h"
#include "afxwin.h"

#include <vector>
#include <map>

#ifdef max
#undef max
#endif

#ifdef min
#undef min
#endif

class KompasObjectHolder
{
protected:
    reference m_reference;
public:
    KompasObjectHolder() : m_reference(0) {}
    KompasObjectHolder(reference object_reference) : m_reference(object_reference) {}
    KompasObjectHolder(KompasObjectHolder& prev_holder) : m_reference(prev_holder.m_reference) { prev_holder.m_reference = 0; }
    KompasObjectHolder& operator =(KompasObjectHolder& prev_holder) {
        if (!m_reference) m_reference = prev_holder.m_reference, prev_holder.m_reference = 0; return *this; }
    ~KompasObjectHolder()
    {
        if (m_reference) DeleteObj(m_reference);
        m_reference = 0;
    }
    operator reference() { return m_reference; }
    operator bool() { return m_reference != 0; }
};

class KompasIteratorHolder : public KompasObjectHolder
{
public:
    KompasIteratorHolder() {}
    KompasIteratorHolder(reference iterator_reference) : KompasObjectHolder(iterator_reference) {}
    KompasIteratorHolder& operator =(KompasIteratorHolder& prev_holder) {
        if (!m_reference) m_reference = prev_holder.m_reference, prev_holder.m_reference = 0; return *this; }
    ~KompasIteratorHolder()
    {
        if (m_reference) DeleteIterator(m_reference);
        m_reference = 0;
    }
};


class CSewingDlg : public CDialog       // диалоговое окно CSewingDlg
{
    DECLARE_DYNAMIC(CSewingDlg)

public:
    CSewingDlg(CWnd* pParent = NULL);   // стандартный конструктор
    virtual ~CSewingDlg();

    reference Draw2DElement(reference element, bool closed = false);
    reference DrawLineSeg(reference element);
    reference DrawCircle(reference element);
    reference DrawArc(reference element);
    reference DrawEllipse(reference element);
        reference DrawEllipseArc(reference element);                    // BAD when coercing EllipseArc & Nurbs ??bag in KOMPAS
    reference DrawEllipseArcWithNurbs(reference element);               // new API7+IMath2D version - !EllipseArc as case of Nurbs
    reference DrawRectangle(reference element);
    reference DrawRegularPolygon(reference element);
        reference DrawBezier(reference element, bool closed = false);   // new API7 version - allows Bezier 2 type (Equidistants fail too)
    reference DrawBezierWithNurbs(reference element, bool closed);      // new API7+IMath2D version - !Bezier as case of Nurbs
    reference DrawEquidistant7(IDrawingObjectPtr& idcContour,
                              EquidistantParam *equiparam, bool swapped);       // new API7 version - no adv.features
    reference DrawEquidistant(EquidistantParam *equiparam, bool swapped);       // new API5 version - ?
    reference DrawPolyline(reference element, bool closed = false);
        reference DrawApproximation(reference element, int curve_type);
    reference DrawContour(reference element, bool closed = false);
    reference DrawNurbs(reference element, bool closed = false);    // new API7+IMath2D version - !works

    reference SmallNurbs3(double x1, double y1, double x2, double y2, unsigned short style);

    double CurvesDeviation(reference old_curve, ICurve2DPtr& new_curve, double precision, double* tpars, int points_count);

    inline void KompasCorrectAngles(double& dBeginAngle, double& dEndAngle, bool clockwise);

    int PseudoProcessAcceptedData(void* pInputData, EquidistantParam *equiparam, bool PseudoGroupMode);
    void PrepareContoursMakeEquidistants(reference obj_iterator, EquidistantParam* equiparam);

    void ProcessMarks(reference curve, reference contour, EquidistantParam* equiparam);

    bool CheckSwapBegPoint(double& x1, double& y1, double& x2, double& y2);
    bool CheckTipWithScratch(double& x1, double& y1);
    bool CheckSwapCurve(reference curve);
    reference DestroyContoursGroup(int tipSearch);
    double GetEquidistantPerimeter(reference element);      // using destroyObj to get true length of Equidistant
    int CheckContourSide(reference contour, bool swapped, bool issingle);
    int CheckIntersections(reference contour, bool swapped, double t);

    bool TestInterrupt(LPSTR msg, int count);

void api7test();

    bool Activated;
    PointParam m_BegPoint;
    reference m_grpAuxScratches;
    unsigned short m_curves_style;

// Данные диалогового окна
    enum { IDD = IDD_SEWINGDLG };
    enum { enCurves_All = 0, enCurves_Selected, enCurves_Unselected };

protected:
    virtual BOOL OnInitDialog();

    void ParseDoubleData(int nID);

    virtual void DoDataExchange(CDataExchange* pDX);    // поддержка DDX/DDV

    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedDrawOperation();
    afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnBnClickedCancel();
    afx_msg void OnBnClickedUndo();
    afx_msg void OnBnClickedRedo();
protected:
    int m_StockOutCheck;
    int m_StockInCheck;
    int m_MarkingCheck;
    double m_StockOut;
    double m_StockIn;
    double m_MarkingStep;
    int m_SelectType;
private:
    int m_UndoRedo;
    int m_ProcessClosedOnly;
    int m_ContourHasAnyLineStyles;
    int m_ProcessEnclosedContours;
    int m_MaxSplitNum;
    int m_MaxMarksNum;
    double m_MmToUnits;

    double m_precision;

    std::map<reference, reference> m_CurveParts;
    std::vector<reference> equi_curves;     // tmp vector needed to correct Equidistant behavior
    int equi_curves_count;                  // may differ from equi_curves.size() due to m_grpAuxScratches
    bool m_swapped;
    bool m_issingle;
    reference m_aux_scratch;
    bool m_skip_scratch;        // in API5 Contour()-mode all references are 0 = i.e. temp intrinsic objects for Contour()
public:
    afx_msg void OnBnClickedManualMarks();
    afx_msg void OnEnKillfocusPrecision();
    afx_msg void OnEnKillfocusStockout();
    afx_msg void OnEnKillfocusStockin();
    afx_msg void OnEnKillfocusMarking();
    afx_msg void OnEnChangeMarking();
};


// SewingDlg.cpp: файл реализации
//

#include "stdafx.h"
#include "SewingDlg.h"
#include "ProgressDlg.h"
#include "SewingPlugin.h"

#include "testEvents/BaseEvent.h"

#include <limits>
#include <cmath>
#include <algorithm>

const double PI2DEGREE = 180.0 / 3.14159265;
const int EQUI_STYLE = ksCSConstruction;    // 6 : вспомогательная (красная)

extern BOOL glb_Interrupt;

//   from eventsAuto.cpp
void AdviseDoc( KompasObject* kompas,
                LPDISPATCH doc, long docType,
                bool fSelectMng = true,
                bool fObject = true,
                bool fStamp = true,
                bool fDocument = true,
                bool fSpecification = true,
                bool fSpcObject = true,
                long objType = 0 /*= -1*/);

#if defined(ASSERT) && !defined(_DEBUG)
#undef ASSERT
#define FILEW2(x) L##x
#define FILEW(f) FILEW2(f)
#define ASSERT(f) {CString sss;if (!(f)){sss.Format(L"BAD ASSERT in line %d (file " FILEW(__FILE__) L")", __LINE__);MessageW((LPWSTR)sss.GetString());}}
#endif

#define MESSAGE_COMMA ,
#define MESSAGE(mesh) {   CString sss; sss.Format(mesh); MessageW((LPWSTR)sss.GetString());   }

template<typename FloatType> inline // to improve need call_traits, etc
bool approx_equals(FloatType x, FloatType y, FloatType relative_factor=FloatType(64))
{
    // default relative_factor=64 results in approximately 2 decimal digits tolerance in significand
    using std::abs; using std::max; using std::numeric_limits;
    return abs(x-y) <= ( relative_factor * numeric_limits<FloatType>::epsilon() * max(abs(x),abs(y)) );
}

static inline bool equal_points(double x1, double y1, double x2, double y2, double precision = 0.0)
{
    // double epsilon = 1e-16, so 1e9 gives real Kompas precision about 1e-7..1e-6..1e-5
    //return VTSL::Math::approx_equals<double>( x1, x2, double(1e9) ) && VTSL::Math::approx_equals<double>( y1, y2, double(1e9) );
    using std::abs; using std::max; using std::numeric_limits;

    double minerror = DBL_EPSILON * double(1e9);

    if (precision > minerror)
        return max(abs(x1 - x2), abs(y1 - y2)) <= precision;
//Message("equal_points");

//  double correction = double(1e9) * (precision <= minerror? 1.0 : precision / minerror);
    double correction = (precision <= minerror? minerror : precision) / DBL_EPSILON;
    bool bx, by;
    double absmax = max(abs(x1), abs(x2));
    if ( absmax > 1.0 ) bx = approx_equals<double>( x1, x2, correction );
    else {
        if ( absmax < minerror ) bx = true;
            else bx = approx_equals<double>( x1/absmax, x2/absmax, correction );
    }
    absmax = max(abs(y1), abs(y2));
    if ( absmax > 1.0 ) by = approx_equals<double>( y1, y2, correction );
    else {
        if ( absmax < minerror ) by = true;
            else by = approx_equals<double>( y1/absmax, y2/absmax, correction );
    }
    return bx && by;
}

static inline bool equal_values(double val1, double val2,  double precision = 0.0)
{
    const double minerror = DBL_EPSILON * double(1e9);
//  double correction = double(1e9) * (precision <= minerror? 1.0 : precision / minerror);
    double correction = (precision <= minerror? minerror : precision) / DBL_EPSILON;
    double absmax = std::max(abs(val1), abs(val2));
    if ( absmax < 1.0 )
    {
        if (absmax < minerror) return true;    // DBL_EPSILON * 64
        return approx_equals<double>( val1/absmax, val2/absmax, correction);
    }
    return approx_equals<double>( val1, val2, correction);
}

static bool IsContourInsideContour(reference contour, reference other, CSewingDlg* pThis)
{
    int type = GetObjParam(other, 0, 0, ALLPARAM);
    int side = 0;
    double t1, t2, x1, y1, x2, y2;
    ksGetCurveMinMaxParametr (contour, &t1, &t2);
    ksGetCurvePoint(contour, t1, &x1, &y1);
    ksGetCurvePoint(contour, t2, &x2, &y2);

    if (type == CONTOUR_OBJ) {
        side = ksIsPointInsideContour(other, x1, y1, 1e-6);
    }

    if (side == 0) {    // special cases for single bezier contour etc.
        reference bref = ksApproximationCurve(other, 0.1, 0, 0, 1);
        if (bref)
        {
            int type = GetObjParam(bref, 0, 0, ALLPARAM);
            if (type == CONTOUR_OBJ) {
                side = ksIsPointInsideContour(bref, x1, y1, 1e-6);
            }
            DeleteObj(bref);
        }
    }

    if (side == 0) do {    // special cases for single rectangle, circle etc.

        KompasObjectHolder decomposed_group(DecomposeObj(other, 5, 0.5, 1));
        if (!decomposed_group) break;

        KompasIteratorHolder group_iterator(CreateIterator(ALL_OBJ, decomposed_group));
        if (!group_iterator) break;

        Contour(1);

        reference cur_obj = MoveIterator(group_iterator, 'F');
        while (cur_obj)
        {
            pThis->Draw2DElement(cur_obj);
            cur_obj = MoveIterator(group_iterator, 'N');
        }

        reference contour_obj = EndObj();
        if (contour_obj)
            side = ksIsPointInsideContour(contour_obj, x1, y1, 1e-6);
        if (contour_obj) DeleteObj(contour_obj);
    } while (0);

    if (side == 3) {
Message("IsContourInsideContour");
        int kp = 0;
        IntersectCurvCurv (contour, other, &kp, 0, 0, 0);
        if (kp == 0) return true;
    }
    return false;
}

// диалоговое окно CSewingDlg

IMPLEMENT_DYNAMIC(CSewingDlg, CDialog)

CSewingDlg::CSewingDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CSewingDlg::IDD, pParent)
    , m_StockInCheck(false)
    , m_StockOutCheck(false)
    , m_MarkingCheck(false)
    , m_StockOut(0)
    , m_StockIn(0)
    , m_MarkingStep(0)
    , m_SelectType(0)
    , m_UndoRedo(0)
    , m_ProcessClosedOnly(1)
    , m_ContourHasAnyLineStyles(0)
    , m_ProcessEnclosedContours(0)      // enclosing may be too slow
    , m_MaxSplitNum(20)
    , m_MaxMarksNum(10)
    , m_precision(1.0)
{
    Activated = true;
    m_BegPoint.x = m_BegPoint.y = 0;
    m_BegPoint.style = 0;
    m_grpAuxScratches = 0; m_curves_style = 0;
    m_MmToUnits = 1.0;
    m_swapped = m_issingle = false;
    m_aux_scratch = 0; m_skip_scratch = false;
}

CSewingDlg::~CSewingDlg()
{
}

void CSewingDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Radio(pDX,      IDC_RADIO1,             m_SelectType);
    DDX_Check(pDX,      IDC_STOCKOUT_CHECK,     m_StockOutCheck);
    DDX_Check(pDX,      IDC_STOCKIN_CHECK,      m_StockInCheck);
    DDX_Check(pDX,      IDC_MARKING_CHECK,      m_MarkingCheck);
    DDX_Check(pDX,      IDC_PROCESS_CLOSED_ONLY,            m_ProcessClosedOnly);
    DDX_Check(pDX,      IDC_CONTOUR_HAS_ANY_LINE_STYLES,    m_ContourHasAnyLineStyles);
    DDX_Check(pDX,      IDC_PROCESS_ENCLOSED_CONTUORS,      m_ProcessEnclosedContours);
    DDX_Text (pDX,      IDC_STOCKOUT,           m_StockOut);
    DDX_Text (pDX,      IDC_STOCKIN,            m_StockIn);
    DDX_Text (pDX,      IDC_MARKING,            m_MarkingStep);
    DDX_Text (pDX,      IDC_CURVE_MAX_POINTS,   m_MaxSplitNum);
    DDX_Text (pDX,      IDC_MARKS_PER_CURVE,    m_MaxMarksNum);
    DDX_Text (pDX,      IDC_PRECISION,          m_precision);
}


BEGIN_MESSAGE_MAP(CSewingDlg, CDialog)
    ON_BN_CLICKED(IDC_DRAW_OPERATION, &CSewingDlg::OnBnClickedDrawOperation)
//    ON_WM_ACTIVATE()
    ON_WM_KEYDOWN()
    ON_BN_CLICKED(IDCANCEL, &CSewingDlg::OnBnClickedCancel)
    ON_BN_CLICKED(IDC_UNDO, &CSewingDlg::OnBnClickedUndo)
    ON_BN_CLICKED(IDC_REDO, &CSewingDlg::OnBnClickedRedo)
//    ON_WM_CHAR()
ON_WM_ACTIVATE()
ON_BN_CLICKED(IDC_MANUAL_MARKS, &CSewingDlg::OnBnClickedManualMarks)
ON_EN_KILLFOCUS(IDC_PRECISION, &CSewingDlg::OnEnKillfocusPrecision)
ON_EN_KILLFOCUS(IDC_STOCKOUT, &CSewingDlg::OnEnKillfocusStockout)
ON_EN_KILLFOCUS(IDC_STOCKIN, &CSewingDlg::OnEnKillfocusStockin)
ON_EN_KILLFOCUS(IDC_MARKING, &CSewingDlg::OnEnKillfocusMarking)
ON_EN_CHANGE(IDC_MARKING, &CSewingDlg::OnEnChangeMarking)
END_MESSAGE_MAP()

//-----------------------------------------------------------------------------
// Dialog initialization
BOOL CSewingDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    m_StockOutCheck = true;
    m_StockInCheck = false;
    m_MarkingCheck = true;
    m_StockOut = 10.50;
    m_StockIn  = 10.50;
    m_MarkingStep = 100;
    m_SelectType = 0;
    m_MaxSplitNum = 20;
    m_MaxMarksNum = 5;

    ((CButton*)GetDlgItem( IDC_PROCESS_CLOSED_ONLY ))->SetCheck( m_ProcessClosedOnly? 1 : 0 );
    ((CButton*)GetDlgItem( IDC_CONTOUR_HAS_ANY_LINE_STYLES ))->SetCheck( m_ContourHasAnyLineStyles? 1 : 0 );
    ((CButton*)GetDlgItem( IDC_PROCESS_ENCLOSED_CONTUORS ))->SetCheck( m_ProcessEnclosedContours? 1 : 0 );

    UpdateData(FALSE);

    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}


/*
    //reference obj = Circle(100,100,100,1);
/ *
    RectangleParam par; // структура параметров прямоугольника
    ::memset(&par, 0, sizeof(RectangleParam));

    par.x = -73.55; // базовая точка 1
    par.y = 39.95; // 
    par.ang = 0.00; // угол вектора направления от 1-ой точки ко 2-ой
    par.height = -66.68; // высота
    par.width = 79.90; // ширина
    par.pCorner = ::CreateArray(CORNER_ARR, 0); // Создание массива параметров углов
    par.style = 1; // стиль линии

    reference obj = ::ksRectangle(&par, 0); // создать прямоугольник 
* /
/ *
    reference rseg1 = LineSeg(10,10,100,100,1);
    reference rseg2 = LineSeg(100,100,200,20,1);

    reference obj = NewGroup(0);
    AddObjGroup(obj, rseg1);
    AddObjGroup(obj, rseg2);
    EndGroup();* /

    Contour(1);

    //определим группу выделения
//    reference obj0 = SelectGroup(0,2,0,0,0,0); //ksViewGetObjectArea();
    //CopyObj(obj0, 0,0,0,0,1,1);
    //CopyGroupToDocument(obj0, ksGetCurrentDocument(0), ksGetCurrentDocument(0));

//    reference group_iterator = CreateIterator(LINESEG_OBJ, 0);
    reference group_iterator = CreateIterator(SELECT_GROUP_OBJ, 0);

    reference cur_obj = MoveIterator(group_iterator, 'F');
    while (cur_obj)
    {
        ksLineSegParamPtr lspLineParam = kompasAPI->GetParamStruct(ko_LineSegParam);
//        long ksres = sewing_object->m_pKompasDoc5->ksGetObjParam(cur_obj, lspLineParam, ALLPARAM);
        long ksres = m_pKompasDoc5->ksGetObjParam(cur_obj, lspLineParam, ALLPARAM);
        if(ksres)
        {
            double x1 = lspLineParam->x1,
                   x2 = lspLineParam->x2,
                   y1 = lspLineParam->y1,
                   y2 = lspLineParam->y2;

//            LineSeg(x1,y1,x2,y2,1);
/ * задание параметров копирования * /
/ *
RequestInfo info;
memset(&info, 0, sizeof(info));
info.title = "Title";
info.prompt = " Новое положение базовой точки ";
info.dynamic = 0;
info.commands = "!test!test1";
int j=CommandWindow(&info);

double x=0,y=0,scale=1,ang=0;
if ((Cursor (&info, &x, &y, 0)) &&
(ReadDouble("Угол поворота", 0, 0, 360, &ang)) &&
(ReadDouble("Масштаб", 1, 0, 999, &scale)))
;* /
/ *
reference posLeader = ksCreateViewObject(POSLEADER_OBJ );
if (posLeader){ 
LightObj(posLeader, 1); 
Message("Позиционная линия выноски");
LightObj(posLeader, 0);

    if (ksEditViewObject(posLeader)) { 
    LightObj(posLeader, 1);
    Message("Отредактированная позиционная линия выноски"); 
    LightObj(posLeader, 0);
    } 

} 
* /
//CopyObj(0, 0, 0, x, y, ang, scale); / * копирование группы gr * /
//ksCopyObj(0, 0, 0, x, y, ang, scale); / * копирование группы gr * /
            LineSeg(x1,y1,x2,y2,1);
*/


reference CSewingDlg::Draw2DElement(reference element, bool closed)
{
    if (ReturnResult()) ResultNULL();
    if (!ExistObj(element)) return 0;

    switch (GetObjParam(element, 0, 0, ALLPARAM))
    {
    case CONTOUR_OBJ:
        return DrawContour(element);        // ONLY APPROXIMATION NOW
    case LINESEG_OBJ:
        return DrawLineSeg(element);
    case CIRCLE_OBJ:
        return DrawCircle(element);
    case ELLIPSE_OBJ:
        return DrawEllipse(element);
    case ARC_OBJ:
        return DrawArc(element);
    case ELLIPSE_ARC_OBJ:
        //return DrawEllipseArcWithNurbs(element);
        return DrawEllipseArc(element);    // NO APPROXIMATION possible - it approximates into itself!
    case RECTANGLE_OBJ:
        return DrawRectangle(element);
    case REGULARPOLYGON_OBJ:
        return DrawRegularPolygon(element);

    case BEZIER_OBJ:
        return DrawBezierWithNurbs(element, closed);
        //return DrawBezier(element, closed);
    case POLYLINE_OBJ:
        return DrawPolyline(element, closed);
    case NURBS_OBJ:
        return DrawNurbs(element, closed);
    default:
        break;
    }
    return 0;
}

reference CSewingDlg::SmallNurbs3(double x1, double y1, double x2, double y2, unsigned short style)
{
//Message("SmallNurbs3");
    reference new_curve = 0;

    do {
        const int degree = 3 + 0;       // NURBS-3 needs 3 points
        bool closed = false;

        NurbsPointParam par;
        Nurbs(degree, closed, style);

        std::vector<double> Points;
        //std::vector<double> Weights;
        //std::vector<double> Knots;

        Points.push_back(x1), Points.push_back(y1);
        Points.push_back((x1 + x2) / 2), Points.push_back((y1 + y2) / 2);
        Points.push_back(x2), Points.push_back(y2);

        int basepoint_count = Points.size();

        for (int basepoint = 0; basepoint < basepoint_count; basepoint += 2)
        {
            par.x = Points[basepoint];
            par.y = Points[basepoint + 1];
            par.weight = 1.0;
            NurbsPoint(&par);
        }
        int knot_count = basepoint_count / 2 + degree;
        for (int knot = 0; knot < knot_count; knot++)
        {
            double knotdata = double(knot / degree);    // ONLY for 3 Points on 3 degree
            ksNurbsKnot(knotdata);
        }
        new_curve = EndObj();
        if (new_curve) return new_curve;    // => new_curve may be 0! like for Bezier !?
    } while (0);

    return 0;
}

bool CSewingDlg::CheckTipWithScratch(double& x1, double& y1)
{
    if (equal_points(x1,y1, m_BegPoint.x, m_BegPoint.y, m_precision * m_MmToUnits)) {
        //if (equal_points(x1,y1, m_BegPoint.x, m_BegPoint.y) == false) {
      if (m_skip_scratch == false)
        if ( ksEqualPoints(x1, y1, m_BegPoint.x, m_BegPoint.y) == 0 ) {
            reference aux_scratch = LineSeg(m_BegPoint.x, m_BegPoint.y, x1, y1, m_curves_style);
            if (aux_scratch == 0) aux_scratch = SmallNurbs3(m_BegPoint.x, m_BegPoint.y, x1, y1, m_curves_style);
            if (aux_scratch) AddObjGroup(m_grpAuxScratches, aux_scratch);
if (aux_scratch == 0)
Message("CheckSwapBegPoint - BAD scratch!");
//else Message("Tip drawn");
            m_aux_scratch = aux_scratch;
        }
        return true;
    }
    return false;
}

bool CSewingDlg::CheckSwapBegPoint(double& x1, double& y1, double& x2, double& y2)
{
    if (CheckTipWithScratch(x1, y1)) {
        m_BegPoint.x = x2, m_BegPoint.y = y2;
        return false;
    }

    if (CheckTipWithScratch(x2, y2)) {
//Message("CheckSwapBegPoint - SWAPPED!");
        m_BegPoint.x = x1, m_BegPoint.y = y1;
        x1 = x2, y1 = y2;
        x2 = m_BegPoint.x, y2 = m_BegPoint.y;
        return true;
    }
    return false;
}

bool CSewingDlg::CheckSwapCurve(reference curve)
{
    double t1, t2;
    double x1, y1, x2, y2;
    ksGetCurveMinMaxParametr (curve, &t1, &t2);
    ksGetCurvePoint(curve, t1, &x1, &y1);
    ksGetCurvePoint(curve, t2, &x2, &y2);

    //return (equal_points(x1,y1, m_BegPoint.x, m_BegPoint.y, m_precision * m_MmToUnits) == false);
    return ( ksEqualPoints(x1, y1, m_BegPoint.x, m_BegPoint.y) == 0 );
}

bool CSewingDlg::TestInterrupt(LPSTR msg, int count)
{
    if (glb_Interrupt && YesNo(msg) == 1) return true;
//Message("TestInterrupt");
//    HWND hwnd = ::SetActiveWindow((HWND) GetHWindow());
//    PumpWaitingMessages();
    ksSetProgressBar(count, "Отрисовка эквидистант...", 1);
    if (progress_object) {
        ((CProgressCtrl*)progress_object->GetDlgItem( IDC_PROGRESS ))->SetPos(count);
        if (((CProgressCtrl*)progress_object->GetDlgItem( IDCANCEL ))->IsWindowEnabled() == FALSE) {
            ((CProgressCtrl*)progress_object->GetDlgItem( IDCANCEL ))->EnableWindow(TRUE);
            ((CProgressCtrl*)progress_object->GetDlgItem( IDCANCEL ))->SetWindowTextW(L"Отмена");
        }
    }
    glb_Interrupt = FALSE;
//    ::SetActiveWindow(hwnd);
    PumpWaitingMessages();
    return false;
}

void CSewingDlg::KompasCorrectAngles(double& dBeginAngle, double& dEndAngle, bool clockwise)
{
    // KOMPAS angles sometimes need correction!:
    if (clockwise) {
        if (dBeginAngle - dEndAngle > 360) dBeginAngle -= 360 * floor((dBeginAngle - dEndAngle) / 360.0);
    } else {
        if (dEndAngle - dBeginAngle > 360) dEndAngle -= 360 * floor((dEndAngle - dBeginAngle) / 360.0);
    }

    if (dBeginAngle < 0.0 || dEndAngle < 0.0) {
        dBeginAngle = dBeginAngle - 360 * floor(dBeginAngle / 360.0);
        dEndAngle = dEndAngle - 360 * floor(dEndAngle / 360.0);
    }
    // Kompas works with angles from 0 to 360 degrees, so may be arcs par ex. from 315 to 45 degrees. DrawArc needs starting angle be less than the ending
    if (clockwise) {
        if (dEndAngle > dBeginAngle) if (dEndAngle < 360) dBeginAngle += 360; else dEndAngle -= 360;
    } else {
        if (dEndAngle < dBeginAngle) if (dBeginAngle < 360) dEndAngle += 360; else dBeginAngle -= 360;
    }
}

reference CSewingDlg::DrawLineSeg(reference element)
{
    //?if ( m_PseudoObjectsMode ) return DrawObjectsAsPseudoVector(element);

    ksLineSegParamPtr lspLineParam = kompasAPI->GetParamStruct(ko_LineSegParam);
    ksDocument2DPtr m_pKompasDoc5  = kompasAPI->ActiveDocument2D();
    long ksres = m_pKompasDoc5->ksGetObjParam(element, lspLineParam, ALLPARAM);
    if(ksres)
    {
        double x1 = lspLineParam->x1,
               x2 = lspLineParam->x2,
               y1 = lspLineParam->y1,
               y2 = lspLineParam->y2;

        CheckSwapBegPoint(x1, y1, x2, y2);

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        return LineSeg(x1, y1, x2, y2, 1);
    }
    return 0;
}

reference CSewingDlg::DrawCircle(reference element)
{
    CircleParam cpCircleParam;
    if (GetObjParam(element, &cpCircleParam, sizeof(CircleParam), ALLPARAM))
    {
        double x = cpCircleParam.xc,
               y = cpCircleParam.yc;

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        return Circle(x, y, cpCircleParam.rad, 1);
    }
    return 0;
}

reference CSewingDlg::DrawArc(reference element)
{
//Message("DrawArc");
    ArcParam apArcParam;
    ArcParam1 apArcParam1;
    if (GetObjParam(element, &apArcParam, sizeof(ArcParam), ALLPARAM)
        && GetObjParam(element, &apArcParam1, sizeof(ArcParam1), POINT_ARC_PARAM))
    {
        double x = apArcParam.xc,
               y = apArcParam.yc;

        double dBeginAngle = apArcParam.ang1,   // as if Arc is drawed counterclockwise
               dEndAngle   = apArcParam.ang2;

        double x1 = apArcParam1.x1, y1 = apArcParam1.y1;
        double x2 = apArcParam1.x2, y2 = apArcParam1.y2;
        bool clockwise = (apArcParam.dir != 1);

        if ( CheckSwapBegPoint(x1, y1, x2, y2) ) {
            clockwise = !clockwise;
            double tmpang = dBeginAngle;
            dBeginAngle = dEndAngle; dEndAngle = tmpang;
        }

        //KompasCorrectAngles(dBeginAngle, dEndAngle, clockwise);   ?? this correction not liked by Equidistant!

        double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        return ArcByAngle(x, y, apArcParam.rad, dBeginAngle, dEndAngle, clockwise? -1 : 1, 1);
    }
    return 0;
}

reference CSewingDlg::DrawEllipse(reference element)
{
    EllipseParam epEllipseParam;
    if (GetObjParam(element, &epEllipseParam, sizeof(EllipseParam), ALLPARAM))
    {
        double x = epEllipseParam.xc,
               y = epEllipseParam.yc;
        double angle = epEllipseParam.ang;
        double a = epEllipseParam.a;
        double b = epEllipseParam.b;

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        epEllipseParam.style = 1;

        return ksEllipse(&epEllipseParam);
    }
    return 0;
}

reference CSewingDlg::DrawEllipseArcWithNurbs(reference element)
{
Message("DrawEllipseArcWithNurbs");
    return 0;
}

reference CSewingDlg::DrawEllipseArc(reference element)     // old - BAD in test with Equidistant
{
//    return 0;   // IMPOSSIBLE to make approximation! (NO WAY TOO to coerce EllipsArc & Nurbes in Equidistant)

//Message("DrawEllipseArc");
    EllipseArcParam eapEllipseArcParam;
    EllipseArcParam1 eapEllipseArcParam1;
    if (GetObjParam(element, &eapEllipseArcParam, sizeof(EllipseArcParam), ALLPARAM) &&
        GetObjParam(element, &eapEllipseArcParam1, sizeof(EllipseArcParam), POINT_ARC_PARAM))
    {
        double x = eapEllipseArcParam.xc,
               y = eapEllipseArcParam.yc;
        double angle = eapEllipseArcParam.ang;
        double ang1 = eapEllipseArcParam.angFirst;
        double ang2 = eapEllipseArcParam.angSecond;
        double a = eapEllipseArcParam.a;
        double b = eapEllipseArcParam.b;
        int dir = eapEllipseArcParam.dir;

        eapEllipseArcParam.style = eapEllipseArcParam1.style = 1;

        ASSERT(eapEllipseArcParam1.a == a && eapEllipseArcParam1.b == b)
        ASSERT(eapEllipseArcParam1.ang == angle)
        ASSERT(eapEllipseArcParam1.xc == x && eapEllipseArcParam1.yc == y)
        ASSERT(eapEllipseArcParam1.dir == dir)

        double t1, t2, t2eps;
        double x1, y1, x2, y2, x1eps, y1eps, x2eps, y2eps;
        ksGetCurveMinMaxParametr (element, &t1, &t2);

        if (dir == 1)
        ASSERT(t2 - t1 == eapEllipseArcParam1.parSecond - eapEllipseArcParam1.parFirst)
        else
        ASSERT(t1 - t2 == eapEllipseArcParam1.parSecond - eapEllipseArcParam1.parFirst)

        //ASSERT(t1 == eapEllipseArcParam.parFirst && t2 == eapEllipseArcParam.parSecond)
        //! t1 != eapEllipseArcParam.parFirst even though  (t2 - t1) == (eapEllipseArcParam.parSecond - eapEllipseArcParam.parFirst)!
        //t1 = eapEllipseArcParam.parFirst;           // or just: ksGetCurveMinMaxParametr (element, &t1, &t2);
        //t2 = eapEllipseArcParam.parSecond;
        ksGetCurvePoint(element, t1, &x1, &y1);     //? BAD instead of t1: (dir == 1? t1 : t2)!    (by the way, for contours HERE dir==1 means CLOCKWISE!?)
        ksGetCurvePoint(element, t2, &x2, &y2);

        double tstep = (t2 - t1) * 0.01  * 0;

        ksGetCurvePoint(element, t1 + tstep, &x1eps, &y1eps);
        ksGetCurvePoint(element, t2 - tstep, &x2eps, &y2eps);
        eapEllipseArcParam1.parFirst = eapEllipseArcParam1.parFirst + tstep;
        eapEllipseArcParam1.parSecond = eapEllipseArcParam1.parSecond - tstep;

        if ( CheckSwapBegPoint(x1, y1, x2, y2) ) {
            eapEllipseArcParam.dir = - eapEllipseArcParam.dir;
            double tmpang = eapEllipseArcParam.angFirst;
            eapEllipseArcParam.angFirst = eapEllipseArcParam.angSecond;
            eapEllipseArcParam.angSecond = tmpang;

            eapEllipseArcParam1.dir = eapEllipseArcParam.dir;

            double tmppar = eapEllipseArcParam1.parFirst;
            eapEllipseArcParam1.parFirst = eapEllipseArcParam1.parSecond;
            eapEllipseArcParam1.parSecond = tmppar;
        }

        double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

//        reference aux_scratch = LineSeg(x1, y1, x1eps, y1eps, m_curves_style);
//        if (aux_scratch) AddObjGroup(m_grpAuxScratches, aux_scratch);

        //reference ref = ksEllipseArc(&eapEllipseArcParam);
        reference ref = ksParEllipseArc(&eapEllipseArcParam1);

        // Equidistant stops after EllipseArc when Nurbs is the next.
        // This is workaround - drawing a scratch (LineSeg works fine - BUT must be called near Equidistant?!)
//        aux_scratch = LineSeg(x2eps, y2eps, m_BegPoint.x, m_BegPoint.y, m_curves_style);
//        if (aux_scratch) AddObjGroup(m_grpAuxScratches, aux_scratch);

        return ref;
    }
    return 0;
}

double CSewingDlg::GetEquidistantPerimeter(reference element)      // using destroyObj to get true length of Equidistant
{
    int type = GetObjParam(element, 0, 0, ALLPARAM);
    if (type != EQUID_OBJ) return 0.0;

    double t1, t2;
    double x1, y1, x2, y2;
    ksGetCurveMinMaxParametr (element, &t1, &t2);
    ksGetCurvePoint(element, t1, &x1, &y1);
    ksGetCurvePoint(element, t2, &x2, &y2);
    double perimeter = 0.0;     // ksDistancePntPntOnCurve(element, x1, y1, x2, y2);

    ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document       (for KAPI5 usage)

    IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
    if (!doc7) { Message("No document open - approx"); return 0; }

    reference a_group = NewGroup(1);
    EndGroup();

    if (a_group && AddObjGroup(a_group, element) )
    {
        // Creating doc for building of nurbs approximation
        DocumentParamT parDocument;
        memset( &parDocument, 0, sizeof( parDocument ) );
        parDocument.regim = 1;  // hidden mode
        parDocument.type = 3;
        reference tmp_doc = CreateDocumentT( &parDocument ); // fragment creation

        reference b_group = CopyGroupToDocument(a_group, m_pKompasDoc5->reference, tmp_doc);

        StoreTmpGroup( b_group );

        if (ExistGroupObj(b_group)) {

            reference elem = 0;
            do {    // pseudo-cycle to destruct tempRasters BEFORE doc-switching & CloseDocument()
                KompasIteratorHolder tempApprox(CreateIterator(ALL_OBJ, 0));    // GetViewReference(0)));
                if(!tempApprox) break;
                elem = MoveIterator(tempApprox, 'F');
            } while (0);

            ksDestroyObjects(elem);
            if (b_group) DeleteObj(b_group);
        }

        reference c_group = NewGroup(1);
        EndGroup();
        SelectGroup(c_group, 2, 0,0,0,0);

        reference n_group = 0;
        if (ExistGroupObj(c_group))
        {
            KompasIteratorHolder contour_iterator(CreateIterator(ALL_OBJ, c_group));

            reference cur_obj_reference = MoveIterator(contour_iterator, 'F');
            while (cur_obj_reference)
            {
                int type = GetObjParam(cur_obj_reference, 0, 0, ALLPARAM);
                perimeter += ksGetCurvePerimeter (cur_obj_reference, ST_MIX_MM);
                cur_obj_reference = MoveIterator(contour_iterator, 'N');
            }
        }
        if (c_group) DeleteObj(c_group);

        //doc7->Active = TRUE;
        doc7->Application->ActiveDocument = doc7;

        if (tmp_doc) CloseDocument(tmp_doc);
    }
    return perimeter;
}

reference CSewingDlg::DrawEquidistant(EquidistantParam *equiparam, bool swapped)                  // new API5 version
{
Message("DrawEquidistant");
    return 0;
}

reference CSewingDlg::DrawEquidistant7(IDrawingObjectPtr& idcContour, EquidistantParam *equiparam, bool swapped)    // new API7 version
{
//return Equidistant(equiparam);
Message("DrawEquidistant7 -> ");

    if (idcContour == 0) return 0;

    IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
    IKompasDocument2DPtr pkdDocument = 0;
    doc7->QueryInterface(&pkdDocument);

    IViewPtr ivpView = pkdDocument->ViewsAndLayersManager->Views->View[0];
    IDrawingContainerPtr pdcContainer = 0;
    ivpView->QueryInterface(&pdcContainer);

    IDrawingObjectPtr pdoDrawingObject = 0;
    ivpView->QueryInterface(&pdoDrawingObject);

    IEquidistantsPtr Equidistant_pool = pdcContainer->Equidistants;
    IEquidistantPtr Equidistant_curve = Equidistant_pool->Add();

    IDrawingObjectPtr idoDrawingContour = idcContour;
    reference base_object = idoDrawingContour->Reference;
    //reference base_object = equiparam->geoObj;
    //IDrawingObjectPtr drawing_object = ksTransferReference( base_object, 0 );

    bool bad_state = false;

    int type = idoDrawingContour->Type;
    if (type == ksObjectDrawingContour)
    {
        IContourPtr icontour = idoDrawingContour;   // ksTransferReference(p_equiparam->geoObj, 0);
        if (icontour) {
            int icount = icontour->Count;
            if (icount < equi_curves_count) bad_state = true;
if (bad_state)
Message("DrawEquidistant7: ERROR building contour!");
//            if (bad_state == false && ref5 && (m_issingle ||
//                (ksIsCurveClosed(ref5) && ksIsCurveClosed(p_equiparam->geoObj)) )) return ref5;
        }
    }

    BOOL isok = false;
    BOOL test_isok = false;
    Equidistant_curve->DegenerateSegment = equiparam->degState == 0? FALSE : TRUE;
    do {
        Equidistant_curve->BaseObject = idoDrawingContour;
        Equidistant_curve->CutMode = equiparam->cutMode == 0? FALSE : TRUE;
        Equidistant_curve->LeftRadius = equiparam->radLeft;
        Equidistant_curve->RightRadius = equiparam->radRight;
        Equidistant_curve->Side = equiparam->side == 2? ksETBoth :
            equiparam->side == 0? ksETLeft : equiparam->side == 1? ksETRight : ksETUnknown;
        Equidistant_curve->Style = equiparam->style;        // = ksCSConstruction; // = 6

        isok = Equidistant_curve->Update();

    //pdoDrawingObject->LayerNumber = pdoDrawingObject->LayerNumber;
    //if (!pdoDrawingObject->Update()) Message("NO update");

        if (!isok) {
            Equidistant_curve->DegenerateSegment = TRUE;
            //Equidistant_curve->CutMode = TRUE;
        }
        isok = isok || test_isok;
        test_isok = true;
    } while (!isok);

    reference ref = Equidistant_curve->Reference;

    //if (type == ksObjectDrawingContour || m_issingle)
    if (m_issingle)
    {
        if (bad_state == false && ref && (m_issingle || ksIsCurveClosed(ref))) return ref;
    }

    double radWorked = Equidistant_curve->Side == ksETLeft? Equidistant_curve->LeftRadius :
        Equidistant_curve->Side == ksETRight? Equidistant_curve->RightRadius :
        std::max(Equidistant_curve->LeftRadius, Equidistant_curve->RightRadius);

//Message("BUILD equidistant -> ");
    if (isok && ref != 0 && bad_state == false) {
        double perimeter = ksGetCurvePerimeter (ref, ST_MIX_MM);   // always 0!
        double summed_len = 0.0;
        if (perimeter == 0)
            perimeter = GetEquidistantPerimeter(ref);
        for (int i = 0; i < equi_curves.size(); i++)
            summed_len += ksGetCurvePerimeter (equi_curves[i], ST_MIX_MM);
    // may be stuff dealing with wrong perimeter...
        if (Equidistant_curve->Side != ksETBoth)
            bad_state = std::abs(perimeter - summed_len) > equi_curves_count * (2.*3.20) * radWorked;   //about 2*pi
        else    // ksETBoth
            bad_state = std::abs(perimeter - 2 * summed_len) > 2. * 1 * (2.*3.20) * radWorked;
            //bad_state = std::abs(perimeter - 2 * summed_len) > 2. * equi_curves_count * (2.*3.20) * radWorked;
    }

    // API7 version writes Equidistant into object level! (as it looks?)
    if (bad_state)      // redrawing separately
    {
        //if (Equidistant_curve) Equidistant_curve->Delete();       //? KEEP it for detecting Contours nesting...
        if (Equidistant_curve && ref) AddObjGroup(m_grpAuxScratches, ref);

        double t1, t2;
        double x1, y1, x2, y2;
        ksGetCurveMinMaxParametr (equi_curves[0], &t1, &t2);
        ksGetCurvePoint(equi_curves[0], t1, &x1, &y1);
        ksGetCurvePoint(equi_curves[0], t2, &x2, &y2);
        m_BegPoint.x = x1, m_BegPoint.y = y1;
        if (swapped) m_BegPoint.x = x2, m_BegPoint.y = y2;
        reference ret_ref = 0;
        m_skip_scratch = true;
        for (int i = 0; i < equi_curves.size(); i++)
        {
            //m_pKompasDoc5->ksContour(1);
            //Contour(1);
            reference obj = 0;
            obj = Draw2DElement(equi_curves[i]);
            //reference ref5 = m_pKompasDoc5->ksEndObj();
            IDrawingObjectPtr idoObject = obj? ksTransferReference(obj, 0) : 0;
            if (obj && idoObject) {
                IEquidistantPtr Equid_curve = Equidistant_pool->Add();

                Equid_curve->BaseObject = idoObject;
                Equid_curve->CutMode = equiparam->cutMode == 0? FALSE : TRUE;
                Equid_curve->LeftRadius = equiparam->radLeft;
                Equid_curve->RightRadius = equiparam->radRight;
                Equid_curve->Side = equiparam->side == 2? ksETBoth :
                    equiparam->side == 0? ksETLeft : equiparam->side == 1? ksETRight : ksETUnknown;
                Equid_curve->Style = equiparam->style;        // = ksCSConstruction; // = 6

                Equid_curve->DegenerateSegment = equiparam->degState == 0? FALSE : TRUE;
                isok = Equid_curve->Update();
                if (isok == false) {
                    Equid_curve->BaseObject = idoObject;
                    Equid_curve->CutMode = equiparam->cutMode == 0? FALSE : TRUE;
                    Equid_curve->LeftRadius = equiparam->radLeft;
                    Equid_curve->RightRadius = equiparam->radRight;
                    Equid_curve->Side = equiparam->side == 2? ksETBoth :
                        equiparam->side == 0? ksETLeft : equiparam->side == 1? ksETRight : ksETUnknown;
                    Equid_curve->Style = equiparam->style;        // = ksCSConstruction; // = 6

                    Equid_curve->DegenerateSegment = TRUE;
                    isok = Equid_curve->Update();
                }
                ref = Equid_curve->Reference;
                DeleteObj(obj);
                if (ref == 0) Equid_curve->Delete();
            }
            if (ret_ref == 0 && ref) ret_ref = ref;
        }
        m_skip_scratch = false;
        return ret_ref;
    }

    return ref;         //? if (!ref) Message("ref == 0"); => ref may be 0!
}

reference CSewingDlg::DrawBezierWithNurbs(reference element, bool closed)        // new API7 version
{
#if defined(DO_DEBUG)
//Message("DrawBezierWithNurbs");
#endif
    IBezierPtr pBezier = ksTransferReference(element, 0);
    if (!pBezier) return 0;

/*    VARIANT varAllPoints;
    VariantInit(&varAllPoints);
    varAllPoints = pBezier->GetPoints(TRUE);
    V_VT(&varAllPoints) = VT_ARRAY | VT_R8;*/

    //AllPoints = pBezier->GetPoints(AllPoints);
    //VARIANT_BOOL boo = AllPoints.boolVal;

    BezierParam bpBezierParam;
    if (GetObjParam(element, &bpBezierParam, sizeof(BezierParam), ALLPARAM))
    {
        const int basepoint_count = GetArrayCount(bpBezierParam.pMathPoint);
        if (bpBezierParam.pMathPoint == 0 || basepoint_count == 0) return 0;

        ASSERT(pBezier->PointsCount == basepoint_count)

        std::vector<double> old_Points;

        MathPointParam mpMathPoint;
        for (int i = 0; i < basepoint_count; i++) {
            GetArrayItem(bpBezierParam.pMathPoint, i, &mpMathPoint, sizeof(MathPointParam));
            old_Points.push_back(mpMathPoint.x);
            old_Points.push_back(mpMathPoint.y);
        }

        GetArrayItem(bpBezierParam.pMathPoint, 0, &mpMathPoint, sizeof(MathPointParam));
        double x = mpMathPoint.x,
               y = mpMathPoint.y;
        double xn, yn;
        bool swapped = false;

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);
        const bool closed_path = (bpBezierParam.closed != 0 && closed);

        if (!closed_path) {
            GetArrayItem(bpBezierParam.pMathPoint, basepoint_count - 1, &mpMathPoint, sizeof(MathPointParam));
            xn = mpMathPoint.x, yn = mpMathPoint.y;
            swapped = CheckSwapBegPoint(x, y, xn, yn);
        }

        const int degree = 3 + 1;

        NurbsPointParam npPoint;

        //double base1X, base1Y, left1X, left1Y, right1X, right1Y;
        double base2X, base2Y, left2X, left2Y, right2X, right2Y, Weight;

        //BezierPointParam par;
        //Bezier(closed, 1);
        //_Bezier() may be better?

        int step = 1;
        int split_number = std::max(m_MaxSplitNum, degree);

        IMath2DPtr mathp = newKompasAPI->Application->Math2D;

        int real_count = 0;
        std::vector<double> Points;
        std::vector<double> Weights;
        std::vector<double> Knots;

        //SAFEARRAY * pSrc = V_ARRAY(&varAllPoints);

        do {
            if (basepoint_count > split_number) step = basepoint_count / split_number;

            NurbsPointParam par;

//swapped = false;
            if (swapped == false || closed_path)
            {
                for (int basepoint = 0; basepoint < basepoint_count + step-1; basepoint += step)
                {
                    if (basepoint >= basepoint_count) basepoint = basepoint_count - 1;
                    GetArrayItem(bpBezierParam.pMathPoint, basepoint, &mpMathPoint, sizeof(MathPointParam));

                    // this works too!
                    pBezier->GetPoint(basepoint,   &base2X, &base2Y, &left2X, &left2Y, &right2X, &right2Y);
/*
                    LONG i = 6 * basepoint + 0, j = 6 * basepoint + 1;      // B,L,R -> L,B,R !
                    ::SafeArrayGetElement( pSrc, &i, &left2X);
                    ::SafeArrayGetElement( pSrc, &j, &left2Y);
                    i += 2, j += 2;
                    ::SafeArrayGetElement( pSrc, &i, &base2X);
                    ::SafeArrayGetElement( pSrc, &j, &base2Y);
                    i += 2, j += 2;
                    ::SafeArrayGetElement( pSrc, &i, &right2X);
                    ::SafeArrayGetElement( pSrc, &j, &right2Y);
*/
                    ASSERT(mpMathPoint.x == base2X && mpMathPoint.y == base2Y)

                    //real_count++;
                    if (basepoint == 0)
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),
                        Points.push_back(right2X), Points.push_back(right2Y);
                    else if (basepoint == basepoint_count - 1 && closed_path == false)
                        Points.push_back(left2X), Points.push_back(left2Y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y);
                    else
                        Points.push_back(left2X), Points.push_back(left2Y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),   // doubling inner point!
                        Points.push_back(right2X), Points.push_back(right2Y),
                        Weights.push_back(1.0), Weights.push_back(1.0);   // doubling inner point!
                    Weights.push_back(1.0);
                    Weights.push_back(1.0);
                }
                if (closed_path) {
                    pBezier->GetPoint(0,   &base2X, &base2Y, &left2X, &left2Y, &right2X, &right2Y);
                    //real_count++;
                    Points.push_back(left2X), Points.push_back(left2Y),
                    Points.push_back(base2X), Points.push_back(base2Y);
                    Weights.push_back(1.0);
                    Weights.push_back(1.0);
                }
            } else {
//Message("Bezier swapped");
                for (int basepoint = basepoint_count - 1; basepoint > -step; basepoint -= step)
                {
                    if (basepoint < 0) basepoint = 0;

                    GetArrayItem(bpBezierParam.pMathPoint, basepoint, &mpMathPoint, sizeof(MathPointParam));

                    pBezier->GetPoint(basepoint,   &base2X, &base2Y, &left2X, &left2Y, &right2X, &right2Y);
/*
                    LONG i = 6 * basepoint + 0, j = 6 * basepoint + 1;      // B,L,R -> L,R,B !
                    ::SafeArrayGetElement( pSrc, &i, &left2X);
                    ::SafeArrayGetElement( pSrc, &j, &left2Y);
                    i += 2, j += 2;
                    ::SafeArrayGetElement( pSrc, &i, &base2X);
                    ::SafeArrayGetElement( pSrc, &j, &base2Y);
                    i += 2, j += 2;
                    ::SafeArrayGetElement( pSrc, &i, &right2X);
                    ::SafeArrayGetElement( pSrc, &j, &right2Y);
*/
                    ASSERT(mpMathPoint.x == base2X && mpMathPoint.y == base2Y)

                    //real_count++;
                    if (basepoint == 0)
                        Points.push_back(right2X), Points.push_back(right2Y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y);
                    else if (basepoint == basepoint_count - 1)
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),
                        Points.push_back(left2X), Points.push_back(left2Y);
                    else
                        Points.push_back(right2X), Points.push_back(right2Y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),
                        Points.push_back(mpMathPoint.x), Points.push_back(mpMathPoint.y),   // doubling inner point!
                        Points.push_back(left2X), Points.push_back(left2Y),
                        Weights.push_back(1.0), Weights.push_back(1.0);   // doubling inner point!
                    Weights.push_back(1.0);
                    Weights.push_back(1.0);
                }
            }
            real_count = Weights.size();    // = Points.size() / 2;

            SAFEARRAYBOUND sabNewArray;
            sabNewArray.cElements = real_count * 2;
            sabNewArray.lLbound = 0;
            SAFEARRAY * pSafe = ::SafeArrayCreate( VT_R8, 1, &sabNewArray );
            for (LONG i = 0; i < (LONG)sabNewArray.cElements; i += 2)
            {
                LONG i0 = i;
                ::SafeArrayPutElement( pSafe, &i0, &Points[i + 0]); i0++;
                ::SafeArrayPutElement( pSafe, &i0, &Points[i + 1]);
            }
            VARIANT varRow;
            VariantInit(&varRow);
            V_VT(&varRow) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow) = pSafe;

            SAFEARRAYBOUND sabNewArray1;
            sabNewArray1.cElements = real_count;
            sabNewArray1.lLbound = 0;
            SAFEARRAY * pSafe1 = ::SafeArrayCreate( VT_R8, 1, &sabNewArray1 );
            for (LONG i = 0; i < (LONG)sabNewArray1.cElements;)
            {
                ::SafeArrayPutElement( pSafe1, &i, &Weights[ i ]); i++;
            }
            VARIANT varRow1;
            VariantInit(&varRow1);
            V_VT(&varRow1) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow1) = pSafe1;

            VARIANT varRow2;
            VariantInit(&varRow2);
            SAFEARRAYBOUND sabNewArray2;
            SAFEARRAY * pSafe2 = 0;
//Message("test0");
            if (Knots.size() == 0 && real_count >= degree) {    // always
                sabNewArray2.cElements = real_count + degree;
                sabNewArray2.lLbound = 0;
                pSafe2 = ::SafeArrayCreate( VT_R8, 1, &sabNewArray2 );
                for (LONG i = 0; i < (LONG)sabNewArray2.cElements; i++)
                {
//                    double data = i < degree? 0.0 : i >= real_count ? 1.0 : double(i - degree + 1) / (real_count - degree + 1) ;
                    double data = (i / 4);      // 0, 1, ... , max = [(real_count + degree) / 4 - 1]
                    ::SafeArrayPutElement( pSafe2, &i, &data);
                    Knots.push_back(data);
                }
            }
            V_VT(&varRow2) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow2) = pSafe2;

            //ICurve2DPtr temp_curve = mathp->Nurbs(closed_path, degree, varRow, varRow1, varRow2);
            ICurve2DPtr temp_curve;
            //? Closed bezier gives fault!
            temp_curve = mathp->Nurbs((closed_path? FALSE : FALSE), degree, varRow, varRow1, varRow2);

/*            VARIANT uvarRow;
            VariantInit(&uvarRow);
            VARIANT uvarRow1;
            VariantInit(&uvarRow1);
            VARIANT uvarRow2;
            VariantInit(&uvarRow2);
            double tmin, tmax;
            temp_curve->GetNurbsParams(FALSE, &uvarRow, &uvarRow1, &uvarRow2, &tmin, &tmax);
*/
            reference rr = temp_curve->Reference; //0!
            //temp_curve->Release(); BAD!

            double delta = CurvesDeviation(element, temp_curve, m_precision * m_MmToUnits, &old_Points[0], basepoint_count);
            if (delta <= m_precision * m_MmToUnits || step == 1) break;
//Message("test");
            split_number = std::max(split_number * 2, degree);
            {
                real_count = 0;
                Points.clear();
                Weights.clear();
                Knots.clear();
            }
        } while (step > 1);

        reference new_curve = 0;

        do {
            NurbsPointParam par;
            //Nurbs(degree, closed_path, 1);
            Nurbs(degree, false, 1);            //? Closed bezier gives error in Equidistant!

//swapped = true;
            if (swapped == false || closed_path) {
                for (int i = 0; i < real_count; i++)
                {
                    par.x = Points[2 * i];
                    par.y = Points[2 * i + 1];
                    par.weight = Weights[i];
                    NurbsPoint(&par);
                }
                if (step == 1 && Knots.size() > 0)
                    for (int knot = 0; knot < (int)Knots.size(); knot ++)
                    {
                        ksNurbsKnot(Knots[knot]);
                    }
            }
            else {
//Message("NURBS swapped");
                for (int i = 0; i < real_count; i++)
                {
                    par.x = Points[2 * i];
                    par.y = Points[2 * i + 1];
                    par.weight = Weights[i];
                    NurbsPoint(&par);
                }
                if (step == 1 && Knots.size() > 0) {
                    double knotmax = Knots.back();
                    for (int knot = Knots.size() - 1; knot >= 0; knot --)
                    {
                        double knotdata = Knots[knot];
                        int res = ksNurbsKnot(knotmax - knotdata);
                        if (!res) Message("BAD knot");
                    }
                }
            }
            new_curve = EndObj();

#if defined(DO_DEBUG)
//if (new_curve == 0) Message("DrawBezierWithNurbs returns ref == 0!");
#endif
            if (new_curve) return new_curve;    // => new_curve may be 0! like for Bezier !?
        } while (0);
    }
    return 0;
}

reference CSewingDlg::DrawBezier(reference element, bool closed)        // new API7 version
{
//Message("DrawBezier");
    IBezierPtr pBezier = ksTransferReference(element, 0);
    if (!pBezier) return 0;

    BezierParam bpBezierParam;
    int step = 1;
    bool swapped = false;
    if (GetObjParam(element, &bpBezierParam, sizeof(BezierParam), ALLPARAM))
    {
        const int basepoint_count = GetArrayCount(bpBezierParam.pMathPoint);
        if (bpBezierParam.pMathPoint == 0 || basepoint_count == 0) return 0;

        //ASSERT(AllPointsCount == basepoint_count)

        MathPointParam mpMathPoint;
        GetArrayItem(bpBezierParam.pMathPoint, 0, &mpMathPoint, sizeof(MathPointParam));
        double x = mpMathPoint.x,
               y = mpMathPoint.y;
        double xn, yn;
        bool swapped = false;

        if (!closed) {
            GetArrayItem(bpBezierParam.pMathPoint, basepoint_count - 1, &mpMathPoint, sizeof(MathPointParam));
            xn = mpMathPoint.x, yn = mpMathPoint.y;
            swapped = CheckSwapBegPoint(x, y, xn, yn);
        }

        const int split_number = std::max(m_MaxSplitNum, 4);
        if (basepoint_count > split_number) step = basepoint_count / split_number;
    }

    const BOOL Bezier_mode = (step > 1)? FALSE : TRUE;

    ULONG AllPointsCount = pBezier->PointsCount,
         OutPointsCount = (step == 1)? AllPointsCount :
         int((AllPointsCount + step - 1) / step) + ((AllPointsCount % step == 1)? 0 : 1);
    //variant_t AllPoints = pBezier->GetPoints(FALSE);
    //AllPoints = pBezier->GetPoints(AllPoints);
    VARIANT varRow;
    VariantInit(&varRow);
    varRow = pBezier->GetPoints(Bezier_mode);
    V_VT(&varRow) = VT_ARRAY | VT_R8;

   // IMath2DPtr MathDrawer = pBezier->Application->Math2D;
   // ICurve2DPtr MathCurve = MathDrawer->Bezier(closed, Bezier_mode, varRow);

    ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document       (for KAPI5 usage)
    IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
    IKompasDocument2DPtr pkdDocument = 0;
    doc7->QueryInterface(&pkdDocument);

    IViewPtr ivpView = pkdDocument->ViewsAndLayersManager->Views->View[0];
    IDrawingContainerPtr pdcContainer = 0;
    ivpView->QueryInterface(&pdcContainer);

    IDrawingObjectPtr pdoDrawingObject = 0;
    ivpView->QueryInterface(&pdoDrawingObject);

    IBeziersPtr Bezier_pool = pdcContainer->Beziers;
    IBezierPtr Bezier_curve = Bezier_pool->Add();

    Bezier_curve->Closed = closed;
    Bezier_curve->Style = 1;

    SAFEARRAYBOUND sabNewArray;
    sabNewArray.cElements = OutPointsCount * (Bezier_mode? 6 : 2);
    sabNewArray.lLbound = 0;

    SAFEARRAY * pSafe = ::SafeArrayCreate( VT_R8, 1, &sabNewArray );

//if (step > 1)
//Message("step > 1");

//swapped = true;
    if (swapped == false || closed)//_path)
    {
//Message("swapped == false");
        SAFEARRAY * pSrc = V_ARRAY(&varRow);
        double arrdata;
        if (Bezier_mode == FALSE)
            for (ULONG i0 = 0, j0 = 0; j0 < sabNewArray.cElements; i0 += 2 * step, j0 += 2)
            {
                if (i0 >= 2 * AllPointsCount) i0 = 2 * (AllPointsCount - 1);
                LONG i = i0, j = j0;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
            }
        else
        {
            for (ULONG i0 = 0, j0 = 0; j0 < sabNewArray.cElements; i0 += 6 * step, j0 += 6)      // B,L,R -> L,B,R !
            {
                if (i0 >= 6 * AllPointsCount) i0 = 6 * (AllPointsCount - 1);
                LONG i = i0, j = j0 + 2;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 2, j = j0;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 4, j = j0 + 4;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
            }
        }

        VARIANT varRow0;
        VariantInit(&varRow0);
        V_VT(&varRow0) = VT_ARRAY | VT_R8;
        V_ARRAY(&varRow0) = pSafe;

        long OldPointsCount = Bezier_curve->PointsCount;
        Bezier_curve->PutPoints(Bezier_mode, varRow0);
        long NewPointsCount = Bezier_curve->PointsCount;
        BOOL istemp = Bezier_curve->Temp;
        BOOL isok = Bezier_curve->Update();
    }
    else
    {
//Message("Swapped");
        SAFEARRAY * pSrc = V_ARRAY(&varRow);
        double arrdata;
        if (Bezier_mode == FALSE)
            for (ULONG i0 = 0, j0 = 0; j0 < sabNewArray.cElements; i0 += 2 * step, j0 += 2)
            {
                if (i0 >= 2 * AllPointsCount) i0 = 2 * (AllPointsCount - 1);
                LONG i = i0, j = sabNewArray.cElements - j0 - 2;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
            }
        else
        {
            for (ULONG i0 = 0, j0 = 0; j0 < sabNewArray.cElements; i0 += 6 * step, j0 += 6)      // B,L,R -> L,R,B !
            {
                if (i0 >= 6 * AllPointsCount) i0 = 6 * (AllPointsCount - 1);
                LONG i = i0, j = sabNewArray.cElements - j0 - 2;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 2, j = sabNewArray.cElements - j0 - 6;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 4, j = sabNewArray.cElements - j0 - 4;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
            }
        }

        VARIANT varRow0;
        VariantInit(&varRow0);
        V_VT(&varRow0) = VT_ARRAY | VT_R8;
        V_ARRAY(&varRow0) = pSafe;

        long OldPointsCount = Bezier_curve->PointsCount;
        Bezier_curve->PutPoints(Bezier_mode, varRow0);
        long NewPointsCount = Bezier_curve->PointsCount;
        BOOL istemp = Bezier_curve->Temp;
        BOOL isok = Bezier_curve->Update();
    }
/*
    IUnknownPtr pUnk0 = ksTransferReference( element, 0 );

    IDrawingObjectPtr doDrawingObject = NULL;
    pUnk0->QueryInterface(&doDrawingObject);

    doDrawingObject->LayerNumber = doDrawingObject->LayerNumber;
    if (!doDrawingObject->Update()) Message("NO update object");

    IDrawingObjectPtr doDrawingObject1 = NULL;
    Bezier_curve->QueryInterface(&doDrawingObject1);

    doDrawingObject1->LayerNumber = doDrawingObject1->LayerNumber;
    if (!doDrawingObject1->Update()) Message("NO update object1");

    if (!pdoDrawingObject->Update()) Message("NO update view");*/
    reference ref = Bezier_curve->Reference;

    PumpWaitingMessages();

    //pdoDrawingObject->LayerNumber = pdoDrawingObject->LayerNumber;
    //if (!pdoDrawingObject->Update()) Message("NO update object");
    //PumpWaitingMessages();

    /*    VARIANT varRow1;
    VariantInit(&varRow1);
    varRow1 = pBezier->GetPoints(FALSE);
    V_VT(&varRow1) = VT_ARRAY | VT_R8;

    std::vector<double> old_points(AllPointsCount * 2);

    SAFEARRAY * pSrc1 = V_ARRAY(&varRow1);
    for (LONG i = 0; i < (LONG)(2 * AllPointsCount); i++)
    {
        ::SafeArrayGetElement( pSrc1, &i, &old_points[i]);
    }

    double delta = CurvesDeviation(IDrawingObjectPtr(pBezier), IDrawingObjectPtr(Bezier_curve), &old_points[0], AllPointsCount);
*/
#if defined(DO_DEBUG)
//if (ref == 0) Message("DrawBezier returns ref == 0!");
#endif
    return ref;         //? if (!ref) Message("ref == 0"); => ref may be 0!
}

reference CSewingDlg::DrawRectangle(reference element)
{
    RectangleParam rpRectangleParam;
    if (GetObjParam(element, &rpRectangleParam, sizeof(RectangleParam), ALLPARAM))
    {
        double x = rpRectangleParam.x,
               y = rpRectangleParam.y;
        double angle = rpRectangleParam.ang;
        double w = rpRectangleParam.width,
               h = rpRectangleParam.height;

        rpRectangleParam.style = 1;

        double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        //rpRectangleParam.pCorner = ::CreateArray(CORNER_ARR, 0); // Создание массива параметров углов 

        return ksRectangle(&rpRectangleParam, 0);
    }
    return 0;
}

reference CSewingDlg::DrawRegularPolygon(reference element)
{
    RegularPolygonParam rppRegularPolygonParam;
    if (GetObjParam(element, &rppRegularPolygonParam, sizeof(RegularPolygonParam), ALLPARAM))
    {
        double xc = rppRegularPolygonParam.xc,
               yc = rppRegularPolygonParam.yc;
        double angle = rppRegularPolygonParam.ang;
        double r = rppRegularPolygonParam.radius;
        int sides = rppRegularPolygonParam.count;
        int inscribed = rppRegularPolygonParam.describe;

        rppRegularPolygonParam.style = 1;

        double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);

        //rppRegularPolygonParam.pCorner = ::CreateArray(CORNER_ARR, 0); // Создание массива параметров углов 

        return ksRegularPolygon(&rppRegularPolygonParam, 0);
    }
    return 0;
}

reference CSewingDlg::DrawPolyline(reference element, bool closed)
{
    PolylineParamEx ppPolylineParam;

    if (GetObjParam(element, &ppPolylineParam, sizeof(PolylineParamEx), ALLPARAM))
    {
        const int vertex_count = GetArrayCount(ppPolylineParam.pMathPoint);
        if (ppPolylineParam.pMathPoint == 0 || vertex_count == 0) return 0;

        MathPointParam mpMathPoint;
        GetArrayItem(ppPolylineParam.pMathPoint, 0, &mpMathPoint, sizeof(MathPointParam));
        double x = mpMathPoint.x,
               y = mpMathPoint.y;
        double xn, yn;
        bool swapped = false;

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);
        const bool closed_path = (ppPolylineParam.closed != 0);

        if (!closed_path) {
            GetArrayItem(ppPolylineParam.pMathPoint, vertex_count - 1, &mpMathPoint, sizeof(MathPointParam));
            xn = mpMathPoint.x, yn = mpMathPoint.y;
            swapped = CheckSwapBegPoint(x, y, xn, yn);
        }

        ksPolyline(1);

        if (swapped == false || closed_path)
            for (int vertex = 0; vertex < vertex_count; vertex++)
            {
                GetArrayItem(ppPolylineParam.pMathPoint, vertex, &mpMathPoint, sizeof(MathPointParam));
                Point(mpMathPoint.x, mpMathPoint.y, 0);
            }
        else
            for (int vertex = vertex_count - 1; vertex >= 0; vertex--)
            {
                GetArrayItem(ppPolylineParam.pMathPoint, vertex, &mpMathPoint, sizeof(MathPointParam));
                Point(mpMathPoint.x, mpMathPoint.y, 0);
            }
        return EndObj();
    }
    return 0;
}

reference CSewingDlg::DrawContour(reference element, bool closed)
{
    return 0;
    return DrawApproximation(element, CONTOUR_OBJ);
    //DrawProtoContour(element, DeferDrawing, parentDrawingInView);
}

reference CSewingDlg::DrawNurbs(reference element, bool closed)     // new API7+IMath2D
{
//Message("DrawNURBS");
    INurbsPtr pNurbs = ksTransferReference(element, 0);
    if (!pNurbs) return 0;

    NurbsParam npNurbsParam;
    if (GetObjParam(element, &npNurbsParam, sizeof(NurbsParam), ALLPARAM))
    {
        std::vector<double> old_Points;

        const int basepoint_count = GetArrayCount(npNurbsParam.pPoint);
        const int knot_count = GetArrayCount(npNurbsParam.pKnot);
        if (npNurbsParam.pPoint == 0 || basepoint_count == 0) return 0;

        int degree = npNurbsParam.degree;

        NurbsPointParam npPoint;

        for (int i = 0; i < basepoint_count; i++) {
            GetArrayItem(npNurbsParam.pPoint, i, &npPoint, sizeof(npPoint));
            old_Points.push_back(npPoint.x);
            old_Points.push_back(npPoint.y);
        }

        GetArrayItem(npNurbsParam.pPoint, 0, &npPoint, sizeof(npPoint));
        double x = npPoint.x,
               y = npPoint.y,
               w = npPoint.weight;
        double xn, yn;
        bool swapped = false;

        const double perimeter =  ksGetCurvePerimeter (element, ST_MIX_MM);
        const bool closed_path = (npNurbsParam.close != 0 && closed);

        bool knotted  = (npNurbsParam.pKnot != 0);

        if (!closed_path) {
            GetArrayItem(npNurbsParam.pPoint, basepoint_count - 1, &npPoint, sizeof(npPoint));
            xn = npPoint.x, yn = npPoint.y;
            swapped = CheckSwapBegPoint(x, y, xn, yn);
        }

        int step = 1;
        int split_number = std::max(m_MaxSplitNum, degree);

        IMath2DPtr mathp = newKompasAPI->Application->Math2D;

        do {
            if (basepoint_count > split_number) step = basepoint_count / split_number;

            //double base1X, base1Y, left1X, left1Y, right1X, right1Y;
            double base2X, base2Y, Weight;

            NurbsPointParam par;
            //Nurbs(degree, closed, 1);

            int real_count = 0;
            std::vector<double> Points;
            std::vector<double> Weights;
            std::vector<double> Knots;

//swapped = true;
            if (swapped == false || closed_path) {
                for (int basepoint = 0; basepoint < basepoint_count + step-1; basepoint += step)
                {
                    if (basepoint >= basepoint_count) basepoint = basepoint_count - 1;

                    GetArrayItem(npNurbsParam.pPoint, basepoint, &npPoint, sizeof(npPoint));

                    pNurbs->GetPoint(basepoint,   &base2X, &base2Y, &Weight);

                    ASSERT(npPoint.x == base2X && npPoint.y == base2Y && npPoint.weight == Weight)
                    par.x = base2X;
                    par.y = base2Y;
                    par.weight = Weight;

                    real_count++;
                    Points.push_back(par.x), Points.push_back(par.y);
                    Weights.push_back(Weight);
                }
                if (step == 1 && knotted && knot_count > 0)
                    for (int knot = 0; knot < knot_count + step-1; knot += step)
                    {
                        double knotdata;
                        GetArrayItem(npNurbsParam.pKnot, knot, &knotdata, sizeof(knotdata));
                        Knots.push_back(knotdata);
                    }
            }
            else {
//Message("NURBS swapped");
                for (int basepoint = basepoint_count - 1; basepoint > -step; basepoint -= step)
                {
                    if (basepoint < 0) basepoint = 0;

                    GetArrayItem(npNurbsParam.pPoint, basepoint, &npPoint, sizeof(npPoint));

                    pNurbs->GetPoint(basepoint,   &base2X, &base2Y, &Weight);

                    ASSERT(npPoint.x == base2X && npPoint.y == base2Y && npPoint.weight == Weight)
                    par.x = base2X;
                    par.y = base2Y;
                    par.weight = Weight;

                    real_count++;
                    Points.push_back(par.x), Points.push_back(par.y);
                    Weights.push_back(Weight);
                }
                if (step == 1 && knotted && knot_count > 0) {
                    double knotmax;
                    GetArrayItem(npNurbsParam.pKnot, knot_count - 1, &knotmax, sizeof(knotmax));
                    for (int knot = knot_count - 1; knot > -step; knot -= step)
                    {
                        double knotdata;
                        GetArrayItem(npNurbsParam.pKnot, knot, &knotdata, sizeof(knotdata));
                        Knots.push_back(knotmax - knotdata);
                    }
                }
            }

            SAFEARRAYBOUND sabNewArray;
            sabNewArray.cElements = real_count * 2;
            sabNewArray.lLbound = 0;
            SAFEARRAY * pSafe = ::SafeArrayCreate( VT_R8, 1, &sabNewArray );
            for (LONG i = 0; i < (LONG)sabNewArray.cElements; i += 2)
            {
                LONG i0 = i;
                ::SafeArrayPutElement( pSafe, &i0, &Points[i + 0]); i0++;
                ::SafeArrayPutElement( pSafe, &i0, &Points[i + 1]);
            }
            VARIANT varRow;
            VariantInit(&varRow);
            V_VT(&varRow) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow) = pSafe;

            SAFEARRAYBOUND sabNewArray1;
            sabNewArray1.cElements = real_count;
            sabNewArray1.lLbound = 0;
            SAFEARRAY * pSafe1 = ::SafeArrayCreate( VT_R8, 1, &sabNewArray1 );
            for (LONG i = 0; i < (LONG)sabNewArray1.cElements;)
            {
                ::SafeArrayPutElement( pSafe1, &i, &Weights[ i ]); i++;
            }
            VARIANT varRow1;
            VariantInit(&varRow1);
            V_VT(&varRow1) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow1) = pSafe1;

            VARIANT varRow2;
            VariantInit(&varRow2);
            SAFEARRAYBOUND sabNewArray2;
            SAFEARRAY * pSafe2 = 0;
//Message("test0");
            if (Knots.size() > 0) {
                sabNewArray2.cElements = Knots.size();
                sabNewArray2.lLbound = 0;
                pSafe2 = ::SafeArrayCreate( VT_R8, 1, &sabNewArray2 );
                for (LONG i = 0; i < (LONG)sabNewArray2.cElements;)
                {
                    ::SafeArrayPutElement( pSafe2, &i, &Knots[ i ]); i++;
                }
            } else {
                sabNewArray2.cElements = real_count + degree;
                sabNewArray2.lLbound = 0;
                pSafe2 = ::SafeArrayCreate( VT_R8, 1, &sabNewArray2 );
                for (LONG i = 0; i < (LONG)sabNewArray2.cElements; i++)
                {
                    double data = i < degree? 0.0 : i > real_count ? 1.0 : double(i) / real_count ;
                    ::SafeArrayPutElement( pSafe2, &i, &data);
                }
            }
            V_VT(&varRow2) = VT_ARRAY | VT_R8;
            V_ARRAY(&varRow2) = pSafe2;

            //ICurve2DPtr temp_curve = mathp->Nurbs(closed_path, degree, varRow, varRow1, varRow2);
            ICurve2DPtr temp_curve;
            temp_curve = mathp->Nurbs(closed_path, degree, varRow, varRow1, varRow2);

/*            VARIANT uvarRow;
            VariantInit(&uvarRow);
            VARIANT uvarRow1;
            VariantInit(&uvarRow1);
            VARIANT uvarRow2;
            VariantInit(&uvarRow2);
            double tmin, tmax;
            temp_curve->GetNurbsParams(FALSE, &uvarRow, &uvarRow1, &uvarRow2, &tmin, &tmax);
*/
            reference rr = temp_curve->Reference; //0!
            //temp_curve->Release(); BAD!

            double delta = CurvesDeviation(element, temp_curve, m_precision * m_MmToUnits, &old_Points[0], basepoint_count);
            if (delta <= m_precision * m_MmToUnits) break;
//Message("test");
            split_number = std::max(split_number * 2, degree);
        } while (step > 1);

        reference new_curve = 0;

        do {
            //double base1X, base1Y, left1X, left1Y, right1X, right1Y;
            double base2X, base2Y, Weight;

            NurbsPointParam par;
            Nurbs(degree, closed, 1);

            int real_count = 0;

//swapped = true;
if (swapped == false || closed_path) {
                for (int basepoint = 0; basepoint < basepoint_count + step-1; basepoint += step)
                {
                    if (basepoint >= basepoint_count) basepoint = basepoint_count - 1;

                    GetArrayItem(npNurbsParam.pPoint, basepoint, &npPoint, sizeof(npPoint));

                    pNurbs->GetPoint(basepoint,   &base2X, &base2Y, &Weight);

                    ASSERT(npPoint.x == base2X && npPoint.y == base2Y && npPoint.weight == Weight)
                    par.x = base2X;
                    par.y = base2Y;
                    par.weight = Weight;
                    NurbsPoint(&par);

                    real_count++;
                }
                if (step == 1 && knotted && knot_count > 0)
                    for (int knot = 0; knot < knot_count + step-1; knot += step)
                    {
                        double knotdata;
                        GetArrayItem(npNurbsParam.pKnot, knot, &knotdata, sizeof(knotdata));
                        ksNurbsKnot(knotdata);
                    }
            }
            else {
//Message("NURBS swapped");
                for (int basepoint = basepoint_count - 1; basepoint > -step; basepoint -= step)
                {
                    if (basepoint < 0) basepoint = 0;

                    GetArrayItem(npNurbsParam.pPoint, basepoint, &npPoint, sizeof(npPoint));

                    pNurbs->GetPoint(basepoint,   &base2X, &base2Y, &Weight);

                    ASSERT(npPoint.x == base2X && npPoint.y == base2Y && npPoint.weight == Weight)
                    par.x = base2X;
                    par.y = base2Y;
                    par.weight = Weight;
                    NurbsPoint(&par);

                    real_count++;
                }
                if (step == 1 && knotted && knot_count > 0) {
                    double knotmax;
                    GetArrayItem(npNurbsParam.pKnot, knot_count - 1, &knotmax, sizeof(knotmax));
                    for (int knot = knot_count - 1; knot > -step; knot -= step)
                    {
                        double knotdata;
                        GetArrayItem(npNurbsParam.pKnot, knot, &knotdata, sizeof(knotdata));
                        int res = ksNurbsKnot(knotmax - knotdata);
                        if (!res) Message("BAD knot");
                    }
                }
            }
            new_curve = EndObj();
#if defined(DO_DEBUG)
//if (new_curve == 0) Message("DrawNurbs returns ref == 0!");
#endif
            if (new_curve) return new_curve;    // => new_curve may be 0! like for Bezier !?
        } while (0);
    }
    return 0;

    //return DrawApproximation(element, NURBS_OBJ);
    //DrawNurbsAsContour(element);
}

double CSewingDlg::CurvesDeviation(reference old_curve, ICurve2DPtr& new_curve, double precision, double* tpars, int points_count)
{
//    return 0;
//Message("CurvesDeviation!");
    double delta = 0.0, average = 0.0;
    double x, y, kx, ky, t, angle, data;
    int count = 0;
    for (int i = 0; i < points_count; i++) {
        x = tpars[2 * i];
        y = tpars[2 * i + 1];
        ::ksGetCurvePointProjection (old_curve, x, y, &x, &y);
        //if (new_curve->PointProjection(x, y, &kx, &ky, &t, &angle))   BAD KOPAS - returns FALSE when success
        new_curve->PointProjection(x, y, &kx, &ky, &t, &angle);
            data = DistancePntPnt(x, y, kx, ky),
            delta = std::max(delta, data),
            average += data, count++;
        if (delta > precision) return delta;    // to speed up this loop
    }
    if (count > 0)average /= count;
    return delta;
}

reference CSewingDlg::DrawApproximation(reference element, int curve_type)
{
Message("DrawApproximation");
    if (curve_type != CONTOUR_OBJ) return 0;
    return 0;
}

// structs declared on local level to debug in VC-debugger (MS bug)
struct Edge {
    double x1; double y1;
    double x2; double y2;
    reference curve;
    size_t node_index1;     // aux field denotes Index of vertex 1 (ordered from 1; 0 means UNDEFINED)
    size_t node_index2;     // aux field denotes Index of vertex 2 (ordered from 1; 0 means UNDEFINED)
    size_t link_index;      // aux vertex/edge component index, used later as work field (1-ordered; 0 means UNDEFINED)
    size_t back_index1, back_index2, back_count;       // back indexes for special case
    Edge(double ux1, double uy1, double ux2, double uy2, reference ucurve)
        : x1(ux1), y1(uy1), x2(ux2), y2(uy2), curve(ucurve), link_index(0), node_index1(0), node_index2(0)
          ,back_count(0), back_index1(0), back_index2(0) {}
};
struct CurveType {
    unsigned short style;
    unsigned long color;
    double width;
    std::vector<Edge> Curves;
    CurveType(unsigned short ustyle, unsigned long ucolor, double uwidth)
        : style(ustyle), color(ucolor), width(uwidth) {}
};
struct LineEnd {
    double x; double y;
    size_t index;   // index into Curves (ordered from 1; 0 means UNDEFINED)
    size_t single_loop;             // special case
    LineEnd(double ux, double uy, size_t uindex) : x(ux), y(uy), index(uindex), single_loop(0) {}
    //static bool SortedX (const LineEnd & lthis, const LineEnd & lend) { return lthis.x < lend.x; }
    static bool SortedYpostX (const LineEnd & lthis, const LineEnd & lend) { return equal_values(lthis.x, lend.x)? (lthis.y < lend.y) : (lthis.x < lend.x); }
};
struct Node {
    double x; double y;
    size_t edge_index;      // (ordered from 1; 0 means UNDEFINED)
    size_t node_index;      // aux field denotes Index of vertex (ordered from 1; 0 means UNDEFINED)
    size_t link_index;      // aux field used later to detect components (ordered from 1; 0 means UNDEFINED)
    Node(double ux, double uy, size_t uindex) : x(ux), y(uy), edge_index(uindex), node_index(0), link_index(0) {}
    Node(double ux, double uy, size_t uindex, size_t uNindex, size_t uLindex) : x(ux), y(uy), edge_index(uindex), node_index(uNindex), link_index(uLindex) {}
};
struct NodeLinks {
    Node thisNode;
    size_t edge_count;      // aux count
    size_t parent_index;    // aux index (ordered from 1; 0 means UNDEFINED)
    size_t inner_edge_index;  // aux index (ordered from 1; 0 means UNDEFINED)
    std::vector<Node> Nodes;
    NodeLinks(Node& uNode) : thisNode(uNode.x, uNode.y, uNode.edge_index, uNode.node_index, uNode.link_index),
                             edge_count(0), parent_index(0), inner_edge_index(0) {}
};

struct equi_contour {
    reference contour;
    reference parent;
    bool issingle;
    bool swapped_curve;
    std::vector <reference> equi_curves;
    int equi_curves_count;      // may differ from equi_curves.size() due to m_grpAuxScratches
    int enclose_count;      // testing or SLOW VERSION
    static CSewingDlg* pThis;
    equi_contour(reference r, bool single, bool swapped, std::vector <reference>& curves, int curves_count)
        : contour(r), issingle(single), swapped_curve(swapped), parent(0), enclose_count(0), equi_curves_count(curves_count)
    {
        if (curves.size() > 0) equi_curves.insert(equi_curves.begin(), curves.begin(), curves.end());
    }
    static bool SortedContours (const equi_contour & lthis, const equi_contour & lend) {
        if (lthis.parent && !lend.parent) return true;
        //if (lthis.parent && lend.parent) return IsContourInsideContour(lthis.parent, lend.parent, pThis);
        return IsContourInsideContour(lthis.contour, lend.contour, pThis); }
};
CSewingDlg* equi_contour::pThis = 0;

void CSewingDlg::PrepareContoursMakeEquidistants(reference obj_iterator, EquidistantParam *equiparam)
{
    std::vector<CurveType> locCurvesPool;

    //ATTENTION - decomposed_reference group & iterator MUST be kept int tmp group HERE for docomposed objects be valid!
//    reference rGroup = NewGroup(1);
//    EndGroup();

    do {    // cycle to collect from view objects (no need if part_reference is some else but view)

        reference cur_object_reference = MoveIterator(obj_iterator, 'F');
        ksCurveStyleParamPtr styleParam = kompasAPI->GetParamStruct(ko_CurveStyleParam);
        while (cur_object_reference)
        {
            int type = GetObjParam(cur_object_reference, 0, 0, ALLPARAM);
            int obj_style = ksGetObjectStyle(cur_object_reference);
            //bool accepted = (type == LINESEG_OBJ || type == ARC_OBJ) && obj_style != CURVE_AXIS3_SPECIAL;       // decomposition produces only these types!
            bool accepted = (type != 0 && type != EQUID_OBJ && (type != LINESEG_OBJ || obj_style != EQUI_STYLE));
            bool approxed = (type == CONTOUR_OBJ);//?? || type == BEZIER_OBJ); // || type == NURBS_OBJ);

            do {    // pseudocycle to handle special breakes
                if (!ExistObj( cur_object_reference ) || !IsGeomObject( cur_object_reference )) break;
                if (accepted == false || approxed) break;

                ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document       (for KAPI5 usage)
                if (m_pKompasDoc5->ksGetStyleParam(CURVE_STYLE_EX, (short)obj_style, styleParam) == 0) break;

                double t1, t2, x1, y1, x2, y2;
                ksGetCurveMinMaxParametr (cur_object_reference, &t1, &t2);
                ksGetCurvePoint(cur_object_reference, t1, &x1, &y1);
                ksGetCurvePoint(cur_object_reference, t2, &x2, &y2);
                //if ((m_SaveViewMatricesPdfMode > 0 || m_EMULATION_state == false))      //? && m_CurrentViewIndex != 0)
                {
                    ksPointIntoMtr (x1, y1, &x1, &y1);
                    ksPointIntoMtr (x2, y2, &x2, &y2);
                }

                if (m_ContourHasAnyLineStyles != 0) {
                    if (locCurvesPool.size() == 0) locCurvesPool.push_back(CurveType(0, 0, 0));
                    locCurvesPool[0].Curves.push_back(Edge(x1, y1, x2, y2, cur_object_reference));
                    continue;
                }

                bool found = false;
                for (size_t i = 0; i < locCurvesPool.size(); i++)
                {
                    if (obj_style == locCurvesPool[i].style && styleParam->color == locCurvesPool[i].color && styleParam->paperWidth == locCurvesPool[i].width)
                    {
                        locCurvesPool[i].Curves.push_back(Edge(x1, y1, x2, y2, cur_object_reference));
                        found = true; break;
                    }
                }
                if (!found) {
                    locCurvesPool.push_back(CurveType(obj_style, styleParam->color, styleParam->paperWidth));
                    locCurvesPool[locCurvesPool.size()-1].Curves.push_back(Edge(x1, y1, x2, y2, cur_object_reference));
                }
            } while (0);

            if (!IsGeomObject( cur_object_reference ) || accepted == false)
            {
                //SKIP!     //Draw2DElement(cur_object_reference);        // drawing texts
            }

            cur_object_reference = MoveIterator(obj_iterator, 'N');
        }

    } while (0);    //while (needIterator && part_reference != 0);

    CWnd * pCWnd = NULL;
    pCWnd = CWnd::FromHandlePermanent( (HWND) GetHWindow() );

    if (! pCWnd) pCWnd = CWnd::FromHandle( (HWND) GetHWindow() );     // GetActiveWindow() ?
    if (! pCWnd) pCWnd = CWnd::FromHandle( ::GetActiveWindow() );     // (HWND)GetHWindow()

    progress_object = new CProgressDlg( pCWnd );
    glb_Interrupt = FALSE;

    progress_object->Create(IDD_PROGRESSDLG, pCWnd); // Show dialog
    progress_object->ShowWindow(SW_SHOWNORMAL);      // Show dialog
//    progress_object->ShowWindow(SW_HIDE);      // Show dialog

    ((CProgressCtrl*)progress_object->GetDlgItem( IDC_PROGRESS ))->SetRange32(0, std::max(0, 1));

Message("DONE COLLECTING...");
    ksSetProgressText("Обработка эквидистант...");
    int contours_count = PseudoProcessAcceptedData(&locCurvesPool, 0, false);
//Message("DONE COUNT...");

    if (contours_count == 0)
    {
        progress_object->DestroyWindow();
        progress_object = NULL;
        PumpWaitingMessages();
        Message("Ничего не выбрано или чертеж пуст.");
        return;
    }

#if defined(DO_DEBUG) == 0      //LICENCING!
//MESSAGE(L"LICENCING contours_count = %d" MESSAGE_COMMA contours_count)
    if (contours_count > 10 || m_SelectType == enCurves_All)
    {
        PumpWaitingMessages();
        Message("Данная демо-версия плагина не имеет блока определения\n"
            "множества контуров и будет работать только с 10 контурами\n"
            "или связанными компонентами.\n"
            "Для работы с многими контурами (полнофункциональным плагином)\n"
            "вам необходимо получить лицензию в компании Gkmsoft (gkmsoft.ru)");
        if (m_SelectType == enCurves_All) {
            progress_object->DestroyWindow();
            progress_object = NULL;
            return;
        }
    }
#endif

    ((CProgressCtrl*)progress_object->GetDlgItem( IDC_PROGRESS ))->SetRange32(0, std::max(0, contours_count-1));

    ksStartProgressBar(0, contours_count, "Обработка эквидистант...", 1);
    PseudoProcessAcceptedData(&locCurvesPool, equiparam, false);
//Message("DONE ALL...");
    ksStopProgressBar("Операция завершена.", 1);
    PumpWaitingMessages();

    progress_object->DestroyWindow();
    progress_object = NULL;
}

int CSewingDlg::PseudoProcessAcceptedData(void* pInputData, EquidistantParam *equiparam, bool PseudoGroupMode)
{
    std::vector<CurveType>& locCurvesPool = *(std::vector<CurveType>*)pInputData;
//PARSING TEST
        for (size_t i = 0; i < locCurvesPool.size(); i++)
        {
            unsigned short style = locCurvesPool[i].style;
            unsigned long color = locCurvesPool[i].color;
            double width = locCurvesPool[i].width;
            //std::vector<Edge>& Edges = locCurvesPool[i].Curves;
            size_t nodes_size = locCurvesPool[i].Curves.size();
            for (size_t j = 0; j < locCurvesPool[i].Curves.size(); j++)
            {
                //if (locCurvesPool[i].Curves[j].curve == 0) continue;
                double x1 = locCurvesPool[i].Curves[j].x1;
                double y1 = locCurvesPool[i].Curves[j].y1;
                double x2 = locCurvesPool[i].Curves[j].x2;
                double y2 = locCurvesPool[i].Curves[j].y2;
                reference curve  = locCurvesPool[i].Curves[j].curve;
                int type = GetObjParam(curve, 0, 0, ALLPARAM);
                curve = curve;
            }
        }

    bool contours_left = true;
    int contours_count = 0;
    bool count_mode = (equiparam == 0);

    // optimizing vertices (sorting)
    for (size_t ii0 = 0, contours_left = true; ii0 < locCurvesPool.size(); ii0++, contours_left = true)
    {
/*      struct equi_contour {
        reference contour;
        bool issingle;
        equi_contour(reference r, bool single) : contour(r), issingle(single) {}
        static bool SortedContours (const equi_contour & lthis, const equi_contour & lend) {
            return IsContourInsideContour(lthis.contour, lend.contour); }
      };*/
      std::vector<Edge> CurvesCopy;
      if (count_mode)
        CurvesCopy.insert(CurvesCopy.begin(), locCurvesPool[ii0].Curves.begin(), locCurvesPool[ii0].Curves.end());

      std::vector <equi_contour> equi_contours;
      //std::vector <reference> equi_curves;      // tmp vector

      m_curves_style = 1;   // = locCurvesPool[i].style;
      m_grpAuxScratches = NewGroup(0);
      EndGroup();

      for (size_t ii = 0; contours_left; ii++)    // additional passes to resolve lost branches and draw one contour in a pass (no more than 1+CONTOURS)
      {                                           // where CONTOURS =  (EDGES + COMPONENTS - VERTICES) by Euler formula
/*        struct LineEnd {
            double x; double y;
            size_t index;   // index into Curves (ordered from 1; 0 means UNDEFINED)
            LineEnd(double ux, double uy, size_t uindex) : x(ux), y(uy), index(uindex) {}
            //static bool SortedX (const LineEnd & lthis, const LineEnd & lend) { return lthis.x < lend.x; }
            static bool SortedYpostX (const LineEnd & lthis, const LineEnd & lend) { if (equal_values(lthis.x, lend.x)) return lthis.y < lend.y; return lthis.x < lend.x; }
        };*/

        std::vector<Edge>& LineEnds = count_mode? CurvesCopy : locCurvesPool[ii0].Curves;
        std::vector<LineEnd> EndsX;
//        std::vector<LineEnd> EndsY;
        for (size_t j = 0; j < LineEnds.size(); j++)
        {
            //LineEnds[j].curve = 0;
            LineEnds[j].link_index = LineEnds[j].node_index1 = LineEnds[j].node_index2 = 0;
            LineEnds[j].back_count = LineEnds[j].back_index1 = LineEnds[j].back_index2 = 0;
            double x1 = LineEnds[j].x1;
            double y1 = LineEnds[j].y1;
            EndsX.push_back(LineEnd(x1, y1, (j + 1)));      // (ordered from 1!)
            double x2 = LineEnds[j].x2;
            double y2 = LineEnds[j].y2;
            EndsX.push_back(LineEnd(x2, y2, (j + 1)));      // (ordered from 1!)
        }

        if (ii == 0 && ii0==1)
        {
for (size_t j = 0; j < LineEnds.size(); j++)
{
//    if (LineEnds[j].link_index == 0) 
    double x1 = LineEnds[j].x1, y1 = LineEnds[j].y1;
    double x2 = LineEnds[j].x2, y2 = LineEnds[j].y2;
//if (j+1 == 30 || j+1 == 28 || j+1 == 31)
//    LineSeg(x1+360, y1-5, x2+360, y2-5, 6);
}
        }





//        EndsY.insert(EndsY.begin(), EndsX.begin(), EndsX.end());

        //?std::sort(EndsX.begin(), EndsX.end(), LineEnd::SortedX);
//        std::sort(EndsY.begin(), EndsY.end(), LineEnd::SortedYpostX);
        std::sort(EndsX.begin(), EndsX.end(), LineEnd::SortedYpostX);

        for (size_t j = 0; j < EndsX.size(); j++)
        {
            size_t edge = EndsX[j].index;
            if (edge == 0) continue;
            if (LineEnds[edge - 1].back_count++ == 0)
                LineEnds[edge - 1].back_index1 = (j + 1);
            else LineEnds[edge - 1].back_index2 = (j + 1);
        }

//PARSING SORT
size_t sx = EndsX.size();
//size_t sy = EndsY.size();
size_t sxy = LineEnds.size();
            for (size_t j = 0; j < LineEnds.size(); j++)
            {
                size_t ind1 = LineEnds[j].back_index1;
if (ind1 == 0)
Message("ERROR ind1 == 0");
                double x1 = EndsX[ind1 - 1].x;
                double y1 = EndsX[ind1 - 1].y;
                size_t edge = EndsX[ind1 - 1].index;
                //double x2 = sy? EndsY[j].x : 0;
                //double y2 = sy? EndsY[j].y : 0;
                //size_t ind2 = sy? EndsY[j].index : 0;
                reference curve  = locCurvesPool[ii0].Curves[j].curve;
                curve = curve;
            }

    // detecting nodes among vertices
/*        struct Node {
            double x; double y;
            size_t edge_index;      // (ordered from 1; 0 means UNDEFINED)
            size_t node_index;      // aux field denotes Index of vertex (ordered from 1; 0 means UNDEFINED)
            size_t link_index;      // aux field used later to detect components (ordered from 1; 0 means UNDEFINED)
            Node(double ux, double uy, size_t uindex) : x(ux), y(uy), edge_index(uindex), node_index(0), link_index(0) {}
            Node(double ux, double uy, size_t uindex, size_t uNindex, size_t uLindex) : x(ux), y(uy), edge_index(uindex), node_index(uNindex), link_index(uLindex) {}
        };
        struct NodeLinks {
            Node thisNode;
            size_t edge_count;      // aux count
            size_t parent_index;    // aux index (ordered from 1; 0 means UNDEFINED)
            size_t inner_edge_index;  // aux index (ordered from 1; 0 means UNDEFINED)
            std::vector<Node> Nodes;
            NodeLinks(Node& uNode) : thisNode(uNode.x, uNode.y, uNode.edge_index, uNode.node_index, uNode.link_index),
                                     edge_count(0), parent_index(0), inner_edge_index(0) {}
        };*/
        std::vector<NodeLinks> locNodesPool;

//Message("test input EndsX");
        // checking & proceeding all single-loops
        for (size_t j = 0; j < LineEnds.size(); j++)
        {
            if (equal_points(LineEnds[j].x1, LineEnds[j].y1, LineEnds[j].x2, LineEnds[j].y2, m_precision * m_MmToUnits)) {
                size_t ind1 = LineEnds[j].back_index1 - 1,
                       ind2 = LineEnds[j].back_index2 - 1;
                EndsX[ind1].single_loop = EndsX[ind2].single_loop = 1;
                locNodesPool.push_back(Node(EndsX[ind1].x, EndsX[ind1].y, EndsX[ind1].index));    //, last_node, 0));
                std::vector<Node>& Nodes = locNodesPool.back().Nodes;
                Nodes.push_back(Node(EndsX[ind2].x, EndsX[ind2].y, EndsX[ind2].index));
            }
        }

        bool prev_loaded = false;
        for (size_t j = 0, jprev = 0; j < EndsX.size(); j++)
        {
            if (EndsX[j].single_loop != 0) continue;
            if (/*j == jprev ||*/ prev_loaded == false) {
                //locNodesPool.push_back(Node(EndsX[jprev].x, EndsX[jprev].y, EndsX[jprev].index));
                locNodesPool.push_back(Node(EndsX[j].x, EndsX[j].y, EndsX[j].index));    //, last_node, 0));
                prev_loaded = true;
            }
            else if (equal_points(EndsX[j].x, EndsX[j].y, EndsX[jprev].x, EndsX[jprev].y, m_precision * m_MmToUnits) == false)
                locNodesPool.push_back(Node(EndsX[j].x, EndsX[j].y, EndsX[j].index));    //, last_node, 0));
            else
            {
                //node found
                Node& lastNode = locNodesPool.back().thisNode;
                if (equal_points(lastNode.x, lastNode.y, EndsX[j].x, EndsX[j].y, m_precision * m_MmToUnits) == false)
                {
                    locNodesPool.push_back(Node(EndsX[j].x, EndsX[j].y, EndsX[j].index));    //, last_node, 0));  // MUST BE NOT
                }
                else
                {
                    std::vector<Node>& Nodes = locNodesPool.back().Nodes;
                    Nodes.push_back(Node(EndsX[j].x, EndsX[j].y, EndsX[j].index));
                }
            }
            jprev = j;
        }

//PARSING NODES
size_t sn = locNodesPool.size();
int linesegs = 0;
            for (size_t j = 0; j < locNodesPool.size(); j++)
            {
                Node& node = locNodesPool[j].thisNode;
                double x0 = node.x;
                double y0 = node.y;
                size_t ind0 = node.edge_index;
                std::vector<Node>& Nodes = locNodesPool[j].Nodes;
size_t snodes = Nodes.size();
  if (snodes == 0) linesegs ++;
                for (size_t jj = 0; jj < Nodes.size(); jj++)
                {
                    double x1 = Nodes[jj].x;
                    double y1 = Nodes[jj].y;
                    size_t ind1 = Nodes[jj].edge_index;
                    ind1 = ind1;
                }
            }

    // detecting components in the graph
        std::vector <size_t> link_map;
        std::map <size_t, size_t> comp_map;
        std::map <size_t, size_t> :: iterator map_Iter;
        typedef std::pair <size_t, size_t> KeyValPair;
        for (size_t j = 0; j < locNodesPool.size(); j++)
        {
            Node& node = locNodesPool[j].thisNode;
            node.node_index = (j + 1);      // (ordered from 1!)
            size_t ind0 = node.edge_index - 1;  // (ordered from 1!)
            size_t comp_index = node.node_index;
            if (LineEnds[ind0].link_index == 0)
                LineEnds[ind0].link_index = comp_index;
            else
                comp_index = LineEnds[ind0].link_index;
            if (node.link_index == 0) node.link_index = comp_index;
            if (comp_map.count(comp_index) == 0)
            {
                bool need_insert = true;
                if (node.node_index != comp_index && comp_index <= link_map.size())      // special case!
                {
                    size_t index = link_map[ comp_index - 1 ],
                           prev_index = 0;
                    while ( comp_map.find(index) == comp_map.end() && index != prev_index )
                    {
                        prev_index = index;
                        index = link_map[index - 1];
                    }
                    map_Iter = comp_map.find(index);
                    if (map_Iter != comp_map.end() && prev_index != 0)
                    {
                        map_Iter->second = node.node_index;
                        comp_index = node.link_index = index;
                        need_insert = false;
                    }
                }
                if (need_insert) comp_map.insert(KeyValPair(node.link_index, node.node_index));
            }
            //else { map_Iter = comp_map.find(node.link_index); }

            std::vector<Node>& Nodes = locNodesPool[j].Nodes;
            for (size_t jj = 0; jj < Nodes.size(); jj++)
            {
                size_t ind1 = Nodes[jj].edge_index - 1;     // (ordered from 1!)
                if (LineEnds[ind1].link_index == 0)
                    LineEnds[ind1].link_index = comp_index;
                else
                    if (LineEnds[ind1].link_index != comp_index)
                    {   // merging bushes with different comp_index by help of the map
                        size_t comp_index1 = LineEnds[ind1].link_index;
                        size_t comp_index0 = std::min(comp_index, comp_index1);
                        map_Iter = comp_map.find(comp_index);
                        if (map_Iter != comp_map.end() && comp_index != comp_index0) comp_map.erase(comp_index);
                        map_Iter = comp_map.find(comp_index1);
                        if (map_Iter != comp_map.end() && comp_index1 != comp_index0) comp_map.erase(comp_index1);
                        map_Iter = comp_map.find(comp_index0);
                        bool need_insert = true;
                        if (map_Iter == comp_map.end())
                        {
                            if (node.node_index != comp_index0 && comp_index0 <= link_map.size())      // special case!
                            {
                                size_t index = link_map[ comp_index0 - 1 ],
                                       prev_index = 0;
                                while ( comp_map.find(index) == comp_map.end() && index != prev_index )
                                {
                                    prev_index = index;
                                    index = link_map[index - 1];
                                }
                                map_Iter = comp_map.find(index);
                                if (map_Iter != comp_map.end())
                                {
                                    comp_index0 = node.link_index = index;
                                    need_insert = false;
                                }
                            }
                        }
                        if (link_map.size() >= comp_index) {
                            size_t next_link = link_map[comp_index - 1];
                            link_map[comp_index - 1] = node.node_index;
                            if (link_map.size() >= next_link) link_map[next_link - 1] = node.node_index;
                        }
                        if (link_map.size() >= comp_index1) {
                            size_t next_link = link_map[comp_index1 - 1];
                            link_map[comp_index1 - 1] = node.node_index;
                            if (link_map.size() >= next_link) link_map[next_link - 1] = node.node_index;
                        }
                        if (need_insert) comp_map.insert(KeyValPair(comp_index0, node.node_index));
                        else
                            map_Iter->second = node.node_index;
                        node.link_index = comp_index = comp_index0;
                        LineEnds[ind1].link_index = comp_index;
                        LineEnds[ind0].link_index = comp_index;
                    }
            }
            if (link_map.size() < node.node_index) link_map.push_back(node.link_index);     // same as comp_index here
            else link_map[node.node_index - 1] = node.link_index;
        }

    // writing components' indices to Nodes
        for (size_t j = 0; j < locNodesPool.size(); j++)
        {
            Node& node = locNodesPool[j].thisNode;
            size_t index = node.link_index,
                   prev_index = 0;
//if (index != link_map[ j ])
//Message("MAY BE DIFFERENT HERE!");
            index = link_map[ j ];
            while ( comp_map.find(index) == comp_map.end() && index != prev_index )
            {
                prev_index = index;
                index = link_map[index - 1];
            }
            if (comp_map.find(index) != comp_map.end() && prev_index != 0)
            {
                size_t new_index = index;
                index = node.link_index;
                prev_index = 0;
                while (comp_map.find(index) == comp_map.end() && index != prev_index )
                {
                    prev_index = index;
                    size_t tmp_index = link_map[index - 1];
                    link_map[index - 1] = new_index;
                    index = tmp_index;
                }
                link_map[ j ] = node.link_index = new_index;
            }
        }

        for (size_t j = 0; j < locNodesPool.size(); j++)
        {
            Node& node = locNodesPool[j].thisNode;
            size_t new_index = link_map[ j ];
            if (node.link_index != new_index) node.link_index = new_index;
            //std::vector<Edge>& LineEnds = locCurvesPool[i].Curves;
            if (node.edge_index != 0)
            {
                size_t index = node.edge_index - 1;
                if (LineEnds[index].link_index != new_index) LineEnds[index].link_index = new_index;
            }
        }

//** Here -
//**    EDGES = LineEnds.size();
//**    VERTICES = locNodesPool.size();
//**    COMPONENTS = comp_map.size();
//**    Contours =  (EDGES + COMPONENTS - VERTICES);

#if defined(DO_DEBUG)
//MESSAGE(L"TEST")
#endif
    // separating from the mesh the different branches and contours to prepare the drawing
        for (size_t j = 0; j < locNodesPool.size(); j++)
        {
            Node& node = locNodesPool[j].thisNode;
            //std::vector<Edge>& LineEnds = locCurvesPool[i].Curves;
            if (node.edge_index != 0)
            {
                size_t index = node.edge_index - 1;
                if (LineEnds[index].node_index1 == 0) LineEnds[index].node_index1 = node.node_index;
                else
                    if (LineEnds[index].node_index2 == 0) LineEnds[index].node_index2 = node.node_index;
                    //else Message("ERROR");
            }
            std::vector<Node>& Nodes = locNodesPool[j].Nodes;
            for (size_t jj = 0; jj < Nodes.size(); jj++)
            {
                if (Nodes[jj].edge_index != 0)
                {
                    size_t index = Nodes[jj].edge_index - 1;
                    if (LineEnds[index].node_index1 == 0) LineEnds[index].node_index1 = node.node_index;
                    else
                        if (LineEnds[index].node_index2 == 0) LineEnds[index].node_index2 = node.node_index;
                        //else Message("ERROR");
                }
            }

            locNodesPool[j].edge_count = 1 + locNodesPool[j].Nodes.size();
            locNodesPool[j].parent_index = (1 + j);      // (ordered from 1!)
        }

//MESSAGE(L"TEST")
//PARSE!
    for (size_t j = 0; j < LineEnds.size(); j++)
    {
        if (LineEnds[j].node_index1 == 0 || LineEnds[j].node_index2 == 0)
        {
size_t ni1 = LineEnds[j].node_index1;
size_t ni2 = LineEnds[j].node_index2;
MESSAGE(L"ERROR edge %d:\n\n ni1 = %d; ni2 = %d" MESSAGE_COMMA j+1 MESSAGE_COMMA ni1 MESSAGE_COMMA ni2)
        }
        if (LineEnds[j].node_index1 == LineEnds[j].node_index2)
        {
size_t ni1 = LineEnds[j].node_index1;
size_t ni2 = LineEnds[j].node_index2;
//MESSAGE(L"WARN (suspicion NOT A LINESEG?) edge %d:\n\n ni1 = %d; ni2 = %d" MESSAGE_COMMA j+1 MESSAGE_COMMA ni1 MESSAGE_COMMA ni2)
        }
    }
/*    for (size_t j = 0; j < locNodesPool.size(); j++)
if (locNodesPool[j].thisNode.node_index == 188 || locNodesPool[j].thisNode.node_index == 208)
{
    double x1 = locNodesPool[j].thisNode.x, y1 = locNodesPool[j].thisNode.y;
    Point(x1, y1, 3);
}*/

        typedef std::map <size_t,size_t> Branches;      // indices into locNodesPool
        Branches locBranchesPool,
                 locBranchesBegs;
        std::map <size_t,size_t> locEdgesPool;          // indices into LineEnds
        std::map <size_t,size_t> locEdgesRegistered;    // back-indices into LineEnds

        // first shear the bush (take away all branches to left a pure mesh of contours
        std::vector<NodeLinks> locNodesPrev(locNodesPool);
        std::vector<NodeLinks> locNodesWork;
        do {
            size_t prev_size = locBranchesPool.size();
            for (size_t j = 0; j < locNodesPrev.size(); j++)
            {
                Node& node = locNodesPrev[j].thisNode;
                std::vector<Node>& Nodes = locNodesPrev[j].Nodes;
                size_t parent_index = locNodesPrev[j].parent_index;

                if (locNodesPool[parent_index - 1].edge_count > 1) locNodesWork.push_back(locNodesPrev[j]);
                else    // if (locNodesPrev[j].edge_count <= 1)     // same as Nodes.size() == 0
                {
                    size_t inner_edge_index = locNodesPool[parent_index - 1].inner_edge_index;
                    size_t node_index = node.node_index;
                    size_t edge_index = inner_edge_index == 0? node.edge_index : Nodes[inner_edge_index - 1].edge_index;

                    while (locEdgesRegistered.find(edge_index) != locEdgesRegistered.end())
                    {
                        if (inner_edge_index >= Nodes.size()) break;
                        inner_edge_index++;
                        edge_index = Nodes[inner_edge_index - 1].edge_index;
                    }

//                    if (edge_index > 0)     // MUST BE
                    if (LineEnds[edge_index - 1].node_index1 == node_index)
                        node_index = LineEnds[edge_index - 1].node_index2;
                    else node_index = LineEnds[edge_index - 1].node_index1;

                    bool need_relink = false;
//                    if (node_index > 0)     // MUST BE
                        if (locNodesPool[node_index - 1].edge_count > 1)
                        {
                            Node& node0 = locNodesPool[node_index - 1].thisNode;
                            std::vector<Node>& Nodes0 = locNodesPool[node_index - 1].Nodes;
                            size_t inner_edge_index = locNodesPool[node_index - 1].inner_edge_index;
                            size_t edge_index0 = inner_edge_index == 0? node0.edge_index : Nodes0[inner_edge_index - 1].edge_index;

                            if (edge_index0 == edge_index) locNodesPool[node_index - 1].inner_edge_index++;
                            locNodesPool[node_index - 1].edge_count--;
                            //edge_index = edge_index0;
                        }
                        else need_relink = true;

//if (need_relink && edge_index == 4 && i == 0)
//Message("GOTCHA need_relink!");
      if (locEdgesRegistered.find(edge_index) == locEdgesRegistered.end())
      {
                    //need_relink = need_relink && (locBranchesPool.count(node.node_index) != 0);
                    need_relink = need_relink && (locBranchesBegs.count(node_index) != 0);
                    if (need_relink == false) {
                        locBranchesPool.insert(KeyValPair(node.node_index, node_index));
                        //locBranchesPool.insert(KeyValPair(node.node_index, edge_index));
                        locBranchesBegs.insert(KeyValPair(node_index, node.node_index));     // aux map to seek for branch beginnings
                    }
      }

                    //if (locEdgesRegistered.find(edge_index) == locEdgesRegistered.end())
                    if (need_relink == false)
                    {
                        locEdgesPool.insert(KeyValPair(node.node_index, edge_index));
                        locEdgesRegistered.insert(KeyValPair(edge_index, node.node_index));
                    }

//if (need_relink && i == 0)
//Message("GOTCHA need_relink!");
                    if (need_relink
                        && locBranchesBegs.count(node.node_index) != 0 && locBranchesBegs.count(node_index) != 0
                        && (locBranchesBegs.find(node.node_index)->second != node_index)
                        && (locBranchesBegs.find(node_index)->second != node.node_index))
                    {
                        size_t prev_index = node_index;
                        size_t node_index = node.node_index;
                        size_t new_index = locBranchesBegs.find(node_index)->second;
//                                locBranchesPool.erase(node.node_index);
                        if (prev_index != new_index) {
                            locBranchesBegs.erase(node_index);
                            locBranchesBegs.insert(KeyValPair(node_index, prev_index));
                        }
                        if (locBranchesPool.count(prev_index) != 0) locBranchesPool.erase(prev_index);
                        locBranchesPool.insert(KeyValPair(prev_index, node_index));
                        //if (locNodesPool[node_index - 1].edge_count > 1)
                        size_t etmp_index = edge_index;
                        if (locNodesPool[node_index - 1].Nodes.size() > 0)
                        do {
                            Node& node0 = locNodesPool[node_index - 1].thisNode;
                            std::vector<Node>& Nodes0 = locNodesPool[node_index - 1].Nodes;
                            size_t& inner_edge_index = locNodesPool[node_index - 1].inner_edge_index;
                            size_t edge_index0 = inner_edge_index == 0? node0.edge_index : Nodes0[inner_edge_index - 1].edge_index;

                            if (edge_index0 == edge_index) inner_edge_index++;
                            if (inner_edge_index > Nodes0.size()) inner_edge_index = 0;
                            etmp_index = edge_index0;
                        } while (etmp_index == edge_index);
                        //size_t new_index0 = 0;

                        if (new_index != prev_index)
                            locEdgesPool.erase(prev_index);
                        if (locEdgesPool.count(prev_index) == 0)
                            locEdgesPool.insert(KeyValPair(prev_index, edge_index));
                        if (locEdgesRegistered.count(edge_index) != 0) locEdgesRegistered.erase(edge_index);
                        locEdgesRegistered.insert(KeyValPair(edge_index, prev_index));

                        do {
                            locBranchesPool.erase(new_index);
                            locBranchesPool.erase(node_index);
                            locBranchesPool.insert(KeyValPair(node_index, new_index));
                            if (new_index != prev_index)
                                locEdgesPool.erase(node_index);
                            if (locEdgesPool.count(node_index) == 0)
                                locEdgesPool.insert(KeyValPair(node_index, etmp_index));
                            if (locEdgesRegistered.count(etmp_index) != 0) locEdgesRegistered.erase(etmp_index);
                            locEdgesRegistered.insert(KeyValPair(etmp_index, node_index));
                            prev_index = node_index;
                            node_index = new_index;
                            if (locBranchesBegs.count(node_index) == 0)
                            {
                                locBranchesBegs.erase(new_index);
                                locBranchesBegs.insert(KeyValPair(node_index, prev_index));
                                break;
                            }
                            new_index = locBranchesBegs.find(node_index)->second;
                            if (locEdgesPool.count(new_index) != 0)
                                etmp_index = locEdgesPool.find(new_index)->second;
//                            locBranchesBegs.erase(new_index);
//                            locBranchesBegs.insert(KeyValPair(new_index, node_index));
                            locBranchesBegs.erase(node_index);
                            locBranchesBegs.insert(KeyValPair(node_index, prev_index));
                        }
                        while (1);//(locBranchesBegs.count(new_index) != 0);      // && new_index0 != 0);
                    }
                }
            }
            //if (locNodesWork.size() == locNodesPrev.size()) break;
            if (prev_size == locBranchesPool.size()) break;
            locNodesPrev.clear();
            locNodesPrev.insert(locNodesPrev.begin(), locNodesWork.begin(), locNodesWork.end());
            locNodesWork.clear();
        } while (locNodesPrev.size() > 0);

        locNodesWork.clear();
        //locEdgesRegistered.clear();

for (size_t j = 0; j < locNodesPrev.size(); j++)
{
    Node& node = locNodesPrev[j].thisNode;
    double x = node.x, y = node.y;
/*    if (m_CurrentViewIndex != 0)
    {
        SetViewMtr(m_CurrentViewIndex,true);
        ksPointFromMtr (x, y, &x, &y);
        _DeleteMtr(), _DeleteMtr();
    }*/
//    Point(x, y+0, 5);
}

size_t BRunches0 = locBranchesPool.size();      // all bare branches
size_t BRunches1 = locNodesPrev.size();         // all contours
//MESSAGE(L"Nodes \n\nBRunches0 = %d\nBRunches1 = %d" MESSAGE_COMMA BRunches0 MESSAGE_COMMA BRunches1)

        std::map <size_t,size_t> DrawnEdges;      // indices into LineEnds to register all drawn edges (find the lost ones)

        ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document

        IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
        IKompasDocument2DPtr pkdDocument = 0;
        doc7->QueryInterface(&pkdDocument);
        IViewPtr ivpView = pkdDocument->ViewsAndLayersManager->Views->View[0];
        IDrawingContainerPtr pdcContainer = 0;
        ivpView->QueryInterface(&pdcContainer);

        bool contour_state = false;

        equi_curves.clear();

        // second we draw the bush branches left after shearing
        while (locBranchesPool.size() > 0)
        {
            IDrawingContoursPtr idcContours = pdcContainer->DrawingContours;
            IDrawingObjectPtr idoObject = 0;
            IDrawingContourPtr idcContour = 0;
            IContourPtr pContour = 0;

            map_Iter = locBranchesPool.begin();
            size_t index = map_Iter->first;
            size_t index0 = index;
            while (locBranchesBegs.find(index) != locBranchesBegs.end())
            {
                index = locBranchesBegs.find(index)->second;
                if (locBranchesPool.count(index) != 0)
                    if (index0 != index) continue;
                    else break;

                std::map <size_t, size_t> :: iterator test_Iter = map_Iter;
                if (++test_Iter == locBranchesPool.end())
                {
                    break;    // BE NEVER but may occur once per each component!
                }
                else map_Iter = test_Iter;
                index = map_Iter->first;
                index0 = index;
            }
            if (locBranchesPool.count(index) == 0) break;       // still may occur ?! NEVER now

            map_Iter = locBranchesPool.find(index);
            index = map_Iter->second;
            size_t tmp_index = map_Iter->first;
            size_t etmp_index = 0;
            if (locEdgesPool.count(map_Iter->first) > 0)
                etmp_index = locEdgesPool.find(map_Iter->first)->second;
            if (etmp_index != 0)
                index = (LineEnds[etmp_index - 1].node_index1 == tmp_index)? LineEnds[etmp_index - 1].node_index2 : LineEnds[etmp_index - 1].node_index1;
            //?  index = (LineEnds[index - 1].node_index1 == tmp_index)? LineEnds[index - 1].node_index2 : LineEnds[index - 1].node_index1;
            double x1 = locNodesPool[map_Iter->first - 1].thisNode.x;
            double y1 = locNodesPool[map_Iter->first - 1].thisNode.y;
            double x2 = locNodesPool[index - 1].thisNode.x;     // locNodesPool[map_Iter->second - 1].thisNode.x;
            double y2 = locNodesPool[index - 1].thisNode.y;     // locNodesPool[map_Iter->second - 1].thisNode.y;
            reference curve = (etmp_index == 0)? 0 : LineEnds[etmp_index - 1].curve;

            // setting color for page
            {
                unsigned short style = locCurvesPool[ii0].style;
                unsigned long color = locCurvesPool[ii0].color;
                double width = locCurvesPool[ii0].width;

/*                SetCurrentColor(color);
                double widthTuning = (m_CurrentViewScale > 0.5)? 0.5 / m_CurrentViewScale : 1.0;      // this isn't nessessary but makes drawins more fine and readable!
                widthTuning = 1.0;      // better for stamps etc. / views be with widthTuning != 1?
                if (PseudoGroupMode == true &&
                    (m_SaveViewMatricesPdfMode == 0 || m_GenObject != 0) && m_CurrentViewIndex != 0)
                    SetCurrentLineWidth(width * m_CurrentViewScale * widthTuning);
                else
                    SetCurrentLineWidth(width * widthTuning);*/
            }

            bool needStroke = false;
            while (etmp_index != 0)     //while (1) // while (map_Iter != locBranchesPool.end())
            {
//PseudoGroupMode = false;
/*                if (PseudoGroupMode == false)
                    if (needStroke == false) m_pPainter->MoveTo(x1, y1);*/
//int bbb =  ExistGroupObj(rGroup); 
                if ( DrawnEdges.count(etmp_index) == 0 )  //? doesn't work
                {
                    bool accepted = true;
                    if (PseudoGroupMode == false)
                    {
                        m_issingle = (contour_state == false);
                        if (contour_state == false)
                        {
//Message("0");
                            contour_state = true;
                            m_BegPoint.x = x1, m_BegPoint.y = y1;
                            m_swapped = CheckSwapCurve(curve);
                            equi_curves.clear();
                            equi_curves_count = 0;
                        }
                        if (m_ProcessClosedOnly == 0 && count_mode == false)
                        {
                            reference obj = 0;
                            m_aux_scratch = 0;
//Message("0 - branch");
                            obj = Draw2DElement(curve);
                            if (m_issingle && m_aux_scratch == 0)
                                idoObject = ksTransferReference(obj, 0);
                            else if (obj) {
                                m_issingle = false;
                                if (idcContour == 0) {
                                    //Contour(1);
                                    //m_pKompasDoc5->ksContour(1);
                                    idcContour = idcContours->Add();
                                    idcContour->QueryInterface(&pContour);
                                }
                                if (idoObject) {
                                    pContour->CopyCurve(idoObject, FALSE);
                                    idoObject->Delete(); idoObject = 0;
                                }
                                IDrawingObjectPtr pCurve = 0;
                                if (m_aux_scratch) {
                                    pCurve = ksTransferReference(m_aux_scratch, 0);
                                    if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                    m_aux_scratch = 0;
                                }
                                pCurve = obj? ksTransferReference(obj, 0) : 0;
                                if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                if (obj) DeleteObj(obj);
                            }
                            equi_curves.push_back(curve);
                            equi_curves_count++;
                        }
                    }
                    else if (etmp_index > 0)
                    {
/*                        m_PseudoGroup.push_back(LineEnds[etmp_index - 1].curve);
                        m_PseudoGroupStartPoints.push_back(std::pair<double,double>(x1,y1));*/
                    }
                    needStroke = needStroke || accepted;

                    /*? doesn't work
                        DrawnEdges.insert(KeyValPair(etmp_index,map_Iter->first));
                        locEdgesRegistered.erase(etmp_index);
                    }*/
                }
                else if (needStroke) {
                    needStroke = false;
                    if (PseudoGroupMode == false) {   // m_pPainter->Stroke();

                        if (contour_state == true)
                        {
                            contour_state = false;
                            if (m_ProcessClosedOnly == 0)
                            {
                                if (contours_count++, count_mode == false)
                                {
                                    //reference contour = EndObj();
                                    //reference contour = m_pKompasDoc5->ksEndObj();
                                    if (pContour) {
                                        int pcount = pContour->Count;
                                        if (pContour->Count > 0)
                                        {
                                            idcContour->Update();
                                            PumpWaitingMessages();
                                        }
                                    }
#if defined(DO_DEBUG)
//Message("1");
#endif
                                    reference contour = idoObject? idoObject->Reference : idcContour->Reference;

                                    //equi_contours.push_back(equi_contour(contour, issingle, m_swapped, equi_curves));

                                    if (!count_mode) equiparam->geoObj = contour;
                                    if (TestInterrupt("Прервать операцию?", contours_count)) return contours_count;

                                    /*if (Equidistant(equiparam) == 0) //параметры эквидистанты
                                        Message("Error drawing Equidistant");*/
                                    EquidistantParam loc_equiparam = *equiparam;
                                    //if (DrawEquidistant(&loc_equiparam, m_swapped) == 0) //параметры эквидистанты
                                    if (m_issingle == false) idoObject = idcContour;
                                    if (DrawEquidistant7(idoObject, &loc_equiparam, m_swapped) == 0) //параметры эквидистанты
                                        Message("Error drawing Equidistant");
                                    if (equi_curves.size() == 0) ProcessMarks(contour, 0, &loc_equiparam);
                                    else
                                        for (int i = 0; i < equi_curves.size(); i++)
                                            ProcessMarks(equi_curves[i], contour, &loc_equiparam);

                                    equi_curves.clear();

                                    //if (contour) DeleteObj(contour);
                                    if (idcContour) idcContour->Delete();
                                    if (idoObject) idoObject->Delete();
                                }
                            }
                        }
                    } else {
/*                        DrawProtoContour2(false);
                        m_PseudoGroup.clear();
                        m_PseudoGroupStartPoints.clear();*/
                    }
                }

                std::map <size_t, size_t> :: iterator imap = locEdgesPool.find(map_Iter->first);
                if (needStroke && imap != locEdgesPool.end()) {
                    DrawnEdges.insert(KeyValPair(imap->second,imap->first));
                    locEdgesRegistered.erase(imap->second);
                }
                locBranchesBegs.erase(map_Iter->first);
                locBranchesPool.erase(map_Iter->first);
                map_Iter = locBranchesPool.find(index);
                if (map_Iter == locBranchesPool.end()) break;
                index = map_Iter->second;
                size_t tmp_index = map_Iter->first;
                /*size_t*/ etmp_index = 0;          //! BUG in C++ (while(etmp_index) ABOVE is misunderstood with this declaration)
                if (locEdgesPool.count(map_Iter->first) > 0)
                    etmp_index = locEdgesPool.find(map_Iter->first)->second;
                if (etmp_index != 0)
                    index = (LineEnds[etmp_index - 1].node_index1 == tmp_index)? LineEnds[etmp_index - 1].node_index2 : LineEnds[etmp_index - 1].node_index1;
                //? index = (LineEnds[index - 1].node_index1 == tmp_index)? LineEnds[index - 1].node_index2 : LineEnds[index - 1].node_index1;
                x1 = locNodesPool[map_Iter->first - 1].thisNode.x;
                y1 = locNodesPool[map_Iter->first - 1].thisNode.y;
                x2 = locNodesPool[index - 1].thisNode.x;
                y2 = locNodesPool[index - 1].thisNode.y;
                curve = (etmp_index == 0)? 0 : LineEnds[etmp_index - 1].curve;
            }
            if (needStroke)
                if (PseudoGroupMode == false) {     // m_pPainter->Stroke();
                    if (contour_state == true)
                    {
                        contour_state = false;
                        if (m_ProcessClosedOnly == 0)
                        {
                            if (contours_count++, count_mode == false)
                            {
                                //reference contour = EndObj();
                                //reference contour = m_pKompasDoc5->ksEndObj();
                                if (pContour) {
                                    int pcount = pContour->Count;
                                    if (pContour->Count > 0)
                                    {
                                        idcContour->Update();
                                        PumpWaitingMessages();
                                    }
                                }
#if defined(DO_DEBUG)
//Message("2");
#endif
                                reference contour = idoObject? idoObject->Reference : idcContour->Reference;

                                //equi_contours.push_back(equi_contour(contour, issingle, m_swapped, equi_curves));

                                if (!count_mode) equiparam->geoObj = contour;
                                if (TestInterrupt("Прервать операцию?", contours_count)) return contours_count;

                                /*if (Equidistant(equiparam) == 0) //параметры эквидистанты
                                    Message("Error drawing Equidistant");*/
                                EquidistantParam loc_equiparam = *equiparam;
                                //if (DrawEquidistant(&loc_equiparam, m_swapped) == 0) //параметры эквидистанты
                                if (m_issingle == false) idoObject = idcContour;
                                if (DrawEquidistant7(idoObject, &loc_equiparam, m_swapped) == 0) //параметры эквидистанты
                                    Message("Error drawing Equidistant");
                                if (equi_curves.size() == 0) ProcessMarks(contour, 0, &loc_equiparam);
                                else
                                    for (int i = 0; i < equi_curves.size(); i++)
                                        ProcessMarks(equi_curves[i], contour, &loc_equiparam);

                                equi_curves.clear();

                                //if (contour) DeleteObj(contour);
                                if (idcContour) idcContour->Delete();
                                if (idoObject) idoObject->Delete();
                            }

    /*                        RefreshKompasActiveDocument();
                            ksExecuteKompasCommand(ksCMRefresh, 1);
                            kompasAPI->ksPumpWaitingMessages();*/
                        }
                    }
                } else {
/*                    DrawProtoContour2(false);
                    m_PseudoGroup.clear();
                    m_PseudoGroupStartPoints.clear();*/
                }
        }

        typedef std::map <size_t,size_t> Contours;      // indices into locNodesPool
        Contours locContoursPool,
                 locContoursEdges,
                 locContoursPassed;

        locEdgesRegistered.clear();

        // finally draw the contours by pulling together all closed paths
        for (size_t j = 0; j < locNodesPrev.size(); j++)
        {
            NodeLinks& node_elem = locNodesPool[locNodesPrev[j].parent_index - 1];
            locContoursPool.insert(KeyValPair(locNodesPrev[j].thisNode.node_index, locNodesPrev[j].parent_index));
            locContoursEdges.insert(KeyValPair(locNodesPrev[j].thisNode.node_index, 0));
            node_elem.inner_edge_index = 0;
            node_elem.edge_count = 1 + node_elem.Nodes.size();    // = locNodesPrev[j].edge_count;
        }

        std::vector <size_t> edge_map;

//MESSAGE(L"DRAW CONT")
        while (locContoursPool.size() > 0)
        {
            IDrawingContoursPtr idcContours = pdcContainer->DrawingContours;
            //IDrawingObjectPtr idoObject = 0;
            IDrawingContourPtr idcContour = 0;
            IContourPtr pContour = 0;

            bool need_break = false;
            map_Iter = locContoursPool.begin();
            locContoursPassed.clear();
            locContoursPassed.insert(KeyValPair(map_Iter->first, 0));

            //bool issingle = false;
            m_issingle = false;
            reference singleton = 0;
            double beg_x1, beg_y1, beg_x2, beg_y2;

            size_t node_index0 = map_Iter->first;
            size_t parent_index = map_Iter->second;

            size_t node_index = node_index0,
                   prev_index = node_index0;
            do {
                map_Iter = locContoursPool.find(node_index);
                if (need_break || map_Iter == locContoursPool.end()) {need_break = true; break;}   // ?NEVER
                parent_index = map_Iter->second;
                Node& node = locNodesPool[parent_index - 1].thisNode;
                std::vector<Node>& Nodes = locNodesPool[parent_index - 1].Nodes;
                size_t& inner_edge_index = locNodesPool[parent_index - 1].inner_edge_index;

                size_t last_index = prev_index;
                size_t edge_index = 0;
                //bool need_break = false;
                do {
                    last_index = prev_index;
                    prev_index = node_index = node.node_index;    // == node_index0
                    do {
                        if (inner_edge_index > Nodes.size()) {need_break = true; break;}
                        edge_index = (inner_edge_index == 0)? node.edge_index : Nodes[inner_edge_index - 1].edge_index;
                        inner_edge_index++;
                    } while (DrawnEdges.count(edge_index) != 0);
                    if (need_break) break;
    //                if (edge_index > 0)     // MUST BE
                    if (LineEnds[edge_index - 1].node_index1 == node_index)
                           node_index = LineEnds[edge_index - 1].node_index2;
                    else node_index = LineEnds[edge_index - 1].node_index1;
                } while (inner_edge_index <= Nodes.size() &&
                    ( (node_index != node_index0 && locContoursPool.find(node_index) == locContoursPool.end())
                 || ( last_index == node_index && locEdgesRegistered.count(edge_index) != 0 ) ));
                 //|| (last_index == node_index && (locContoursEdges.count(prev_index) != 0 && locContoursEdges.find(prev_index)->second != 0)) ));

                if (need_break) break;      // no cycle found

                if (locContoursEdges.count(prev_index) != 0)
                    locContoursEdges.find(prev_index)->second = edge_index;
                locEdgesRegistered.insert(KeyValPair(edge_index, 0));

                if (locContoursPassed.find(node_index) == locContoursPassed.end())
                {
                    if (locContoursPassed.count(prev_index) != 0)
                        locContoursPassed.find(prev_index)->second = node_index;
                    locContoursPassed.insert(KeyValPair(node_index, 0));
                    continue;
                }

                m_issingle = locContoursPassed.size() == 1;
                singleton = 0;

                map_Iter = locContoursPassed.find(node_index);
                prev_index = node_index0 = map_Iter->first;
                node_index = map_Iter->second;
                while (locContoursPassed.size() > 0 && map_Iter != locContoursPassed.end())    // && node_index != 0)
                {
                    prev_index = map_Iter->first;
                    node_index = map_Iter->second;

                    double x1 = locNodesPool[prev_index - 1].thisNode.x;
                    double y1 = locNodesPool[prev_index - 1].thisNode.y;
                    double x2 = locNodesPool[(node_index == 0? node_index0 : node_index) - 1].thisNode.x;
                    double y2 = locNodesPool[(node_index == 0? node_index0 : node_index) - 1].thisNode.y;
                    if (m_issingle && prev_index == node_index0)
                        x2 = locNodesPool[prev_index - 1].Nodes[0].x,
                        y2 = locNodesPool[prev_index - 1].Nodes[0].y;

                    map_Iter = locContoursPassed.find(node_index);

                    if (prev_index == node_index0)
                    {
                        // setting color for page
                        {
                            unsigned short style = locCurvesPool[ii0].style;
                            unsigned long color = locCurvesPool[ii0].color;
                            double width = locCurvesPool[ii0].width;

/*                            SetCurrentColor(color);
                            double widthTuning = (m_CurrentViewScale > 0.5)? 0.5 / m_CurrentViewScale : 1.0;      // this isn't nessessary but makes drawins more fine and readable!
                            widthTuning = 1.0;      // better for stamps etc. / views be with widthTuning != 1?
                            if (PseudoGroupMode == true &&
                                (m_SaveViewMatricesPdfMode == 0 || m_GenObject != 0) && m_CurrentViewIndex != 0)
                                SetCurrentLineWidth(width * m_CurrentViewScale * widthTuning);
                            else
                                SetCurrentLineWidth(width * widthTuning);*/
                        }
/*                        if (PseudoGroupMode == false)
                            m_pPainter->MoveTo(x1, y1);*/
                    }

                    if (locContoursEdges.count(prev_index) != 0)
                        edge_index = locContoursEdges.find(prev_index)->second;
                    reference curve = (edge_index == 0)? 0 : LineEnds[edge_index - 1].curve;
                    //if ( DrawnEdges.count(etmp_index) == 0 )  //? doesn't work
                    if (PseudoGroupMode == false)
                    {
                        if (contour_state == false)
                        {
                            contour_state = true;
                            m_BegPoint.x = x1, m_BegPoint.y = y1;
                            beg_x1 = x1, beg_y1 = y1;
                            beg_x2 = x2, beg_y2 = y2;
//Message("000000000");
                            m_swapped = CheckSwapCurve(curve);
                            equi_curves.clear();
                            equi_curves_count = 0;
                            //if (m_issingle) {
                            //    int type = GetObjParam(curve, 0, 0, ALLPARAM);
                            //    m_issingle = (type != CONTOUR_OBJ);
                            //}
                            //if (!issingle) Contour(1);
                            //if (!m_issingle) m_pKompasDoc5->ksContour(1);
                        }
                        reference obj = 0;
                        m_aux_scratch = 0;
                        if (count_mode == false)
                        {
//int type = GetObjParam(curve, 0, 0, ALLPARAM);
//bool iscontour = type == CONTOUR_OBJ;
                            if (m_issingle && m_aux_scratch == 0) singleton = curve;
                            else {
//Message("00000 - contour");
                                obj = Draw2DElement(curve, m_issingle);
                                if (obj) {
                                    m_issingle = false;
                                    if (idcContour == 0) {
                                        //Contour(1);
                                        //m_pKompasDoc5->ksContour(1);
                                        idcContour = idcContours->Add();
                                        idcContour->QueryInterface(&pContour);
                                    }
                                    IDrawingObjectPtr pCurve = 0;
                                    if (m_aux_scratch) {
                                        pCurve = ksTransferReference(m_aux_scratch, 0);
                                        if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                        m_aux_scratch = 0;
                                    }
                                    pCurve = obj? ksTransferReference(obj, 0) : 0;
                                    if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                    if (obj) DeleteObj(obj);
                                }
                            }
                            equi_curves.push_back(curve);
                            equi_curves_count++;
                        }
                    }

                    if (edge_index != 0) DrawnEdges.insert(KeyValPair(edge_index, prev_index));
                    if (PseudoGroupMode == true && edge_index > 0)
                    {
/*                        m_PseudoGroup.push_back(LineEnds[edge_index - 1].curve);
                        m_PseudoGroupStartPoints.push_back(std::pair<double,double>(x1,y1));*/
                    }
                    locContoursPool.erase(prev_index);
                }

            } while (node_index != 0 && node_index != node_index0);

            if (need_break) break;
            locContoursPool.erase(node_index);
            if (PseudoGroupMode == false) {
                if (contour_state == true)
                {
                //m_pPainter->ClosePath();
                //m_pPainter->Stroke();
                    m_aux_scratch = 0;
                    if (count_mode == false)
                    {
//Message("000");
                        if (m_issingle && m_swapped == false) m_BegPoint.x = beg_x2, m_BegPoint.y = beg_y2;
                        //CheckTipWithScratch(beg_x1, beg_y1);
                        if (m_swapped == false)
                            CheckSwapBegPoint(beg_x1, beg_y1, beg_x2, beg_y2);
                        else
                            CheckSwapBegPoint(beg_x2, beg_y2, beg_x1, beg_y1);
                        if (m_aux_scratch) {
                            if (idcContour == 0) {
                                //Contour(1);
                                //m_pKompasDoc5->ksContour(1);
                                idcContour = idcContours->Add();
                                idcContour->QueryInterface(&pContour);
                            }
                            IDrawingObjectPtr pCurve = 0;
                            if (m_aux_scratch) {
                                pCurve = ksTransferReference(m_aux_scratch, 0);
                                if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                m_aux_scratch = 0;
                            }
                            reference obj = 0;
                            if (m_issingle) {
                                m_BegPoint.x = (m_swapped == false)? beg_x1 : beg_x2;   // NO MORE scratches!
                                m_BegPoint.y = (m_swapped == false)? beg_y1 : beg_y2;
                                obj = Draw2DElement(singleton);    //, m_issingle);
                            }
                            if (obj) {
                                pCurve = obj? ksTransferReference(obj, 0) : 0;
                                if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                                if (obj) DeleteObj(obj);
                                m_issingle = false;
                            }
                        }
                    }
/*
                    if (equal_points(m_BegPoint.x, m_BegPoint.y, beg_x1, beg_y1, m_precision * m_MmToUnits)
                        && equal_points(m_BegPoint.x, m_BegPoint.y, beg_x1, beg_y1) == false) {
                        reference aux_scratch = LineSeg(m_BegPoint.x, m_BegPoint.y, beg_x1, beg_y1, m_curves_style);
                        AddObjGroup(m_grpAuxScratches, aux_scratch);
                    }
*/
                    contour_state = false;
                    reference contour = 0;
                    //contour = (!issingle)? EndObj() : singleton;
                    //contour = (!m_issingle)? m_pKompasDoc5->ksEndObj() : singleton;

                    if (contours_count++, count_mode == false)
                    {
                        if (pContour) {
                            int pcount = pContour->Count;
                            BOOL Closed = pContour->Closed;
                            pContour->Closed = TRUE;
                            if (pContour->Count > 0)
                            {
                                idcContour->Update();
                                PumpWaitingMessages();
                            }
                        }
                        contour = m_issingle? singleton : idcContour->Reference;
                    }

                    equi_contour::pThis = this;

                    if (count_mode == false)
                        equi_contours.push_back(equi_contour(contour, m_issingle, m_swapped, equi_curves, equi_curves_count));
                    equi_curves.clear();

                    // moved for later!
                    //equiparam->side = CheckContourSide(contour, issingle);
                    //equiparam->geoObj = contour;
                    //Equidistant(equiparam); //параметры эквидистанты
                    //if (contour) DeleteObj(contour);

                    break;      // IMPORTANT! after each contour
                }
            } else {
/*                DrawProtoContour2(true);
                m_PseudoGroup.clear();
                m_PseudoGroupStartPoints.clear()*/
            }

/*            RefreshKompasActiveDocument();
            ksExecuteKompasCommand(ksCMRefresh, 1);
            kompasAPI->ksPumpWaitingMessages();*/
        }

        size_t EDGES = LineEnds.size();
        size_t VERTICES = locNodesPool.size();
        size_t COMPONENTS = comp_map.size();
        size_t CONTOURS = EDGES + COMPONENTS - VERTICES;

        if (count_mode) {
            //contours_count += CONTOURS; - may be counted as so too (but no interactivity in dialog)
            //break;      // no need in ii-cycle
        }
if(0)
MESSAGE(L"Map (line type %d, subcycle = %d) \n\nEDGES = %d\nVERTICES = %d\nCOMPONENTS = %d\n\nContours = %d" \
        MESSAGE_COMMA ii0 MESSAGE_COMMA ii MESSAGE_COMMA EDGES MESSAGE_COMMA VERTICES MESSAGE_COMMA COMPONENTS MESSAGE_COMMA CONTOURS)

        //if (ii == 0)
        {
            size_t LineEndsSize = LineEnds.size();
            for (size_t j = LineEndsSize; j > 0; j--)
            {
                size_t index = j - 1;
                size_t node1 = LineEnds[index].node_index1;
                size_t node2 = LineEnds[index].node_index2;
                map_Iter = DrawnEdges.find(index + 1);      // (ordered from 1!)
                if (map_Iter != DrawnEdges.end() && (map_Iter->second == node1 || map_Iter->second == node2))
                    LineEnds.erase(LineEnds.begin() + index);
            }
        }

#if defined(DO_DEBUG) == 0   //LICENCING!
        if (count_mode == false && contours_count >= 10) { contours_left = false; continue; break; }
#endif
        contours_left = (ii == 0) || (EDGES + COMPONENTS - VERTICES > 0);   // may be insufficient?
        contours_left = contours_left || LineEnds.size() > 0;
      }

if (0)
        if (equi_contours.size() > 0)     // drawing equidistants and clearing
        {
#if defined(DO_DEBUG)
MESSAGE(L"equi_contours.size() = %d" MESSAGE_COMMA equi_contours.size())
#endif
//MESSAGE(L"equi_contours.size() > 0")
            // WRONG!?:
            //std::sort(equi_contours.begin(), equi_contours.end(), equi_contour::SortedContours);

            std::sort(equi_contours.begin(), equi_contours.end(), equi_contour::SortedContours);

            int enclosed_count = 0;
            bool enclosed = false;
            reference enclosed_contour = 0;
            for (int i = (int)equi_contours.size() - 1; i >= 0; i--)
            {
                if (enclosed_contour)
                    enclosed = IsContourInsideContour(equi_contours[i].contour, enclosed_contour, this);
                if (!enclosed) {
                    if (enclosed_contour) DeleteObj(enclosed_contour);
                    enclosed_contour = 0;
                }
                if (enclosed)
                    enclosed_count += 1;
                else enclosed_count = 0;
                reference contour = equi_contours[i].contour;
                m_issingle = equi_contours[i].issingle;
                bool trigger_inside = (m_ProcessEnclosedContours != 0) && (enclosed_count % 2) != 0;
                bool right_ort = true;
                int inside = CheckContourSide(contour, equi_contours[i].swapped_curve, m_issingle);
                int side = (inside == 3)? (m_StockOutCheck != 0? 1 : 0) :       // left side or both!
                           (inside == 1)? (m_StockOutCheck != 0? 0 : 1) : 0;    // right side or both!
    char buf[128];
    ::sprintf(buf, "inside : %d, side : %d", inside, side);
//    ::Message(buf);
                if (!count_mode)
                {
                  if (equiparam->side < 2) {
                    equiparam->side = side;
                    if (trigger_inside) equiparam->side = equiparam->side == 1? 0 : 1;
                    if (equiparam->side == 0) {
                        equiparam->radLeft = std::max(0.0, ((inside == 3) == trigger_inside)? m_StockOut : m_StockIn);
                        equiparam->radLeft *= m_MmToUnits;
                    } else {
                        equiparam->radRight = std::max(0.0, ((inside == 3) == trigger_inside)? m_StockIn : m_StockOut);
                        equiparam->radRight *= m_MmToUnits;
                    }
                  } else {
                    if ((side == 0) == trigger_inside) {
                        equiparam->radRight = std::max(0.0, m_StockOut); // радиус эквидистанты справа по направлению кривой
                        equiparam->radLeft = std::max(0.0, m_StockIn);  // радиус эквидистанты слева
                    } else {
                        equiparam->radRight = std::max(0.0, m_StockIn); // радиус эквидистанты справа по направлению кривой
                        equiparam->radLeft = std::max(0.0, m_StockOut); // радиус эквидистанты слева
                    }
                    equiparam->radRight *= m_MmToUnits;
                    equiparam->radLeft *= m_MmToUnits;
                  }
                  equiparam->geoObj = contour;
                }
                equi_curves.clear();
                if (contours_count++, count_mode == false)
                {
                    equi_curves.insert(equi_curves.begin(),equi_contours[i].equi_curves.begin(),equi_contours[i].equi_curves.end());
                    equi_contours[i].equi_curves.clear();
                    if (TestInterrupt("Прервать операцию?", contours_count)) return contours_count;

                    /*if (Equidistant(equiparam) == 0) //параметры эквидистанты
                        Message("Error drawing Equidistant");*/
                    equi_curves_count = equi_contours[i].equi_curves_count;
                    if (DrawEquidistant(equiparam, equi_contours[i].swapped_curve) == 0) //параметры эквидистанты
                        Message("Error drawing Equidistant");
                    for (int ic = 0; ic < (int)equi_curves.size(); ic++) {
                        if (ic == 0 && m_CurveParts.count(equi_curves[0]) > 0) {
                            ProcessMarks(m_CurveParts.find( equi_curves[0] )->second, equi_contours[i].contour, equiparam);
                            break;
                        }
                        ProcessMarks(equi_curves[ic], equi_contours[i].contour, equiparam);
                    }
                    equi_curves.clear();
                }
//    char buf[128];
//    ::sprintf(buf, "контур : %d", i);
//    ::Message(buf);
                if (!enclosed_contour) enclosed_contour = equi_contours[i].contour;
                if (contour && enclosed_contour != contour) DeleteObj(contour);
                //if (enclosed)
                //    enclosed_count += 1;
                //else enclosed_count = 0;
            }
            if (enclosed_contour) DeleteObj(enclosed_contour);
            equi_contours.clear();
        }

if (1)  // SLOW ENCLOSING VERSION!!
        if (equi_contours.size() > 0)     // drawing equidistants and clearing
        {
#if defined(DO_DEBUG)
MESSAGE(L"SLOW equi_contours.size() > 0 \n equi_contours.size() = %d" MESSAGE_COMMA equi_contours.size())
#endif
            // WRONG!?:
            //std::sort(equi_contours.begin(), equi_contours.end(), equi_contour::SortedContours);

            for (int i = 0; i < (int)equi_contours.size(); i++)
                for (int j = 0; j < i; j++)
            {
                bool enclosed = IsContourInsideContour(equi_contours[j].contour, equi_contours[i].contour, this);
                if (enclosed) equi_contours[j].enclose_count++;
                else if (IsContourInsideContour(equi_contours[i].contour, equi_contours[j].contour, this))
                    equi_contours[i].enclose_count++;
            }

            //std::sort(equi_contours.begin(), equi_contours.end(), equi_contour::SortedContours);

            if (count_mode) contours_count += equi_contours.size();
            else
#if defined(DO_DEBUG)   //LICENCING!
            for (int i = (int)equi_contours.size() - 1; i >= 0; i--)
#else                   //LICENCING!
                for (int i = std::min((int)(equi_contours.size() - 1), 10 - 1); i >= 0; i--)
#endif
            {
                int enclosed_count = equi_contours[i].enclose_count;
                reference contour = equi_contours[i].contour;
                m_issingle = equi_contours[i].issingle;
                bool trigger_inside = (m_ProcessEnclosedContours != 0) && (enclosed_count % 2) != 0;
                bool right_ort = true;
                EquidistantParam loc_equiparam = *equiparam;
#if defined(DO_DEBUG)
//::Message("Prepare equiparam");
#endif
                int inside = CheckContourSide(contour, equi_contours[i].swapped_curve, m_issingle);
#if defined(DO_DEBUG)
//if (inside == 1)::Message("Prepare equiparam = inside == 1!");
//if (inside == 3)::Message("Prepare equiparam = inside == 3!");
//if (inside == 2)::Message("Prepare equiparam = inside == 2!");
//if (inside == 0)::Message("Prepare equiparam = inside == 0!");
#endif
                int side = (inside == 1)? (m_StockOutCheck != 0? 1 : 0) :       // left side or both!
                           (inside == 3)? (m_StockOutCheck != 0? 0 : 1) : 0;    // right side or both!
                if (loc_equiparam.side < 2) {
                    loc_equiparam.side = side;
                    if (trigger_inside) loc_equiparam.side = loc_equiparam.side == 1? 0 : 1;
                    if (loc_equiparam.side == 0) {
                        loc_equiparam.radLeft = std::max(0.0, ((inside == 1) == trigger_inside)? m_StockOut : m_StockIn);
                        loc_equiparam.radLeft *= m_MmToUnits;
                    } else {
                        loc_equiparam.radRight = std::max(0.0, ((inside == 1) == trigger_inside)? m_StockIn : m_StockOut);
                        loc_equiparam.radRight *= m_MmToUnits;
                    }
                } else {
                    if ((side == 0) == trigger_inside) {
                        loc_equiparam.radRight = std::max(0.0, m_StockOut); // радиус эквидистанты справа по направлению кривой
                        loc_equiparam.radLeft = std::max(0.0, m_StockIn);  // радиус эквидистанты слева
                    } else {
                        loc_equiparam.radRight = std::max(0.0, m_StockIn); // радиус эквидистанты справа по направлению кривой
                        loc_equiparam.radLeft = std::max(0.0, m_StockOut); // радиус эквидистанты слева
                    }
                    loc_equiparam.radRight *= m_MmToUnits;
                    loc_equiparam.radLeft *= m_MmToUnits;
                }
                loc_equiparam.geoObj = contour;

                if (TestInterrupt("Прервать операцию?", contours_count)) return contours_count;

                if (equi_contours[i].swapped_curve) {
#if defined(DO_DEBUG)
//::Message("Prepare equiparam = SWAPPED!");
#endif
                    if (loc_equiparam.side != 2) loc_equiparam.side = loc_equiparam.side == 0? 1 : 0;
                    double tmp = loc_equiparam.radLeft;
                    loc_equiparam.radLeft = loc_equiparam.radRight;
                    loc_equiparam.radRight = tmp;
                }
                equi_curves.clear();
                equi_curves.insert(equi_curves.begin(),equi_contours[i].equi_curves.begin(),equi_contours[i].equi_curves.end());
                equi_contours[i].equi_curves.clear();
                /*if (Equidistant(&loc_equiparam) == 0) //параметры эквидистанты
                    Message("Error drawing Equidistant");*/
                equi_curves_count = equi_contours[i].equi_curves_count;
                IDrawingContourPtr idcContour = 0;
                IDrawingObjectPtr idoObject = 0;
                if (m_issingle) idoObject = ksTransferReference(contour, 0);
                else idcContour = ksTransferReference(contour, 0);
                if (m_issingle == false) idoObject = idcContour;
                if (DrawEquidistant7(idoObject, &loc_equiparam, equi_contours[i].swapped_curve) == 0) //параметры эквидистанты
                    Message("Error drawing Equidistant");
                for (int ic = 0; ic < (int)equi_curves.size(); ic++) {
                    if (ic == 0 && m_CurveParts.count(equi_curves[0]) > 0) {
                        ProcessMarks(m_CurveParts.find( equi_curves[0] )->second, equi_contours[i].contour, &loc_equiparam);
                        break;
                    }
                    ProcessMarks(equi_curves[ic], equi_contours[i].contour, &loc_equiparam);
                }
                equi_curves.clear();
//    char buf[128];
//    ::sprintf(buf, "контур : %d", i);
//    ::Message(buf);
                //if (contour) DeleteObj(contour);
                if (idcContour) idcContour->Delete();
                //if (idoObject) idoObject->Delete();       // NEVER!
            }
            equi_contours.clear();
        }



        if (m_grpAuxScratches && ExistGroupObj(m_grpAuxScratches))
            DeleteObj(m_grpAuxScratches);
        m_grpAuxScratches = 0;
    }

//    if (rGroup) DeleteObj(rGroup);
//    if (rGroup) DeleteObj(rGroup);
    return contours_count;
}

void CSewingDlg::ProcessMarks(reference curve, reference contour, EquidistantParam* equiparam)
{
    if (m_MarkingCheck == 0 || !curve || !equiparam || m_MaxMarksNum < 1) return;
#if defined(DO_DEBUG)
//Message("ProcessMarks");
#endif

    if (contour == 0) contour = curve;

    const double perimeter =  ksGetCurvePerimeter (curve, ST_MIX_MM);
    bool closed = ksIsCurveClosed (curve) == 1;
//    if (perimeter < m_MaxMarksNum * m_MarkingStep) return;
    if (perimeter < m_MarkingStep) return;

    int type = GetObjParam(curve, 0, 0, ALLPARAM);
    double t1, t2, x1, y1, x2, y2;
    ksGetCurveMinMaxParametr (curve, &t1, &t2);
    ksGetCurvePoint(curve, t1, &x1, &y1);
    ksGetCurvePoint(curve, t2, &x2, &y2);

ksGetCurvePoint(curve, t1*0.8+t2*0.2, &x1, &y1);
Point (x1, y1, 5);

    reference pointArr = ksPointsOnCurve (curve, m_MaxMarksNum + (closed? 0 : 1+1));
    if (!pointArr) return;

    for (int i = (closed? 0 : 1); i < m_MaxMarksNum + (closed? 0 : 1); i++)
    {
        //double t = t1 + i * ((t2 - t1) / m_MaxMarksNum);      // doesn't give equal steps!
        MathPointParam par;
        if (GetArrayItem (pointArr, i, &par, sizeof (MathPointParam)))
        {
            double kx = par.x, ky = par.y, norm;
            //ksGetCurvePoint(curve, t, &kx, &ky);
            double kx0 = kx, ky0 = ky;
            norm = ksGetCurvePerpendicular(curve, kx, ky);

            int type = GetObjParam(curve, 0, 0, ALLPARAM);
            double nx = kx0, ny = ky0;
            MovePoint(&nx, &ny, norm, 0.1);
            double tx = kx0, ty = ky0;
            ksGetCurvePointProjection(contour, tx, ty, &tx, &ty);
            double tx0 = tx, ty0 = ty;
            bool right_ort = true;
            int dir = 1;
            if (ksMovePointOnCurve (contour, &tx, &ty, 0.01, dir))
            {
                right_ort = 0 <= ( (tx - tx0) * (ny - ky0) - (nx - kx0) * (ty - ty0) );
            }

            if (equiparam->side%2 == 0) {   // 0 or 2
                MovePoint(&kx, &ky, norm + (right_ort? 0 : 180), equiparam->radLeft);
                LineSeg(kx0, ky0, kx, ky, EQUI_STYLE);
            }
            if (equiparam->side >= 1) {     // 1 or 2
                kx = kx0, ky = ky0;
                MovePoint(&kx, &ky, norm + (right_ort? 180 : 0), equiparam->radRight);
                LineSeg(kx0, ky0, kx, ky, EQUI_STYLE);
            }
        }
    }
    ::ClearArray(pointArr);
    ::DeleteArray(pointArr);
}

int CSewingDlg::CheckContourSide(reference contour, bool swapped, bool issingle)
{
//    if (m_StockOutCheck != 0 && m_StockInCheck != 0) return 2;
    if (contour)
    {
        int type = GetObjParam(contour, 0, 0, ALLPARAM);
        double t1, t2, x1, y1, x2, y2;
        double perimeter =  ksGetCurvePerimeter (contour, ST_MIX_MM);
        ksGetCurveMinMaxParametr (contour, &t1, &t2);
        ksGetCurvePoint(contour, t1, &x1, &y1);
        ksGetCurvePoint(contour, t2, &x2, &y2);
if (ksIsCurveClosed(contour) == 0 && equal_points(x1, y1, x2, y2) == false)
Message("Equidistant: ERROR build contour - CURVE not closed!");

        reference tmp_ref = 0;
        if (issingle && type != CONTOUR_OBJ) {
            Contour(1);
            reference robj = Draw2DElement(contour, true);
            tmp_ref = EndObj();
            if (robj) DeleteObj(robj);
            if (tmp_ref) contour = tmp_ref;
        }

        const int idiv = 5;
        double step = (t2 - t1) / idiv;
        double t = t1;
        int inside = 0;
        for (int i = 0; i < idiv; i++, t += step)
        {
#if defined(DO_DEBUG)
//::Message("entering CheckIntersections");
#endif
            inside = CheckIntersections(contour, swapped, t);
char buf[128];
::sprintf(buf, "координаты %d-й точки : %d", i, inside);
//::Message(buf);
            if (inside == 3) break;
            if (inside == 1) break;
        }
        if (tmp_ref) DeleteObj(tmp_ref);
        //if (inside == 1) return (m_StockOutCheck != 0)? 1 : 0;  // left side or both!
        //if (inside == 3) return (m_StockOutCheck != 0)? 0 : 1;  // right side or both!
        return inside;
    }
    return 0;
}

int CSewingDlg::CheckIntersections(reference contour, bool swapped, double t)
{
    double kx, ky, norm;
    ksGetCurvePoint(contour, t, &kx, &ky);
    double kx0 = kx, ky0 = ky;
    norm = ksGetCurvePerpendicular(contour, kx, ky);
    int ret = 0;
    //MovePoint(&kx, &ky, norm, 1);
    reference norm_line = Line(kx, ky, norm);
    reference intersections = ::CreateArray(POINT_ARR, 0); // создать пустой массив точек пересечения
    if (::ksIntersectCurvCurv(norm_line, contour, intersections) > 0)
    {
        int count = ::GetArrayCount(intersections); // количество элементов в массиве
        MathPointParam par;
        double dist = -1.0;
        for (int i = 0; i < count; i++)
        {
            if (!::GetArrayItem(intersections, i, &par, sizeof(MathPointParam))) continue;
            if (!equal_points(kx0, ky0, par.x, par.y)) {
                double test_dist = DistancePntPnt(kx0, ky0, par.x, par.y);
                if (dist <= 0.0) kx = par.x, ky = par.y, dist = test_dist;
                else if (test_dist < dist) kx = par.x, ky = par.y, dist = test_dist;
            }
        }
        const double kxmid = (kx + kx0) / 2, kymid = (ky + ky0) / 2;
        double ort = 0.1, kxort = kxmid, kyort = kymid;
        if (dist > 0.0) ::ksGetCurvePointProjection (contour, kxort, kyort, &kxort, &kyort);
        int type = GetObjParam(contour, 0, 0, ALLPARAM);
        int side = 0;
        if (dist <= 0.0) side = 2;
        else if (DistancePntPnt(kxmid, kymid, kxort, kyort) < ort * m_MmToUnits) side = 2;
        else if (type != RECTANGLE_OBJ && type != REGULARPOLYGON_OBJ)
            side = ksIsPointInsideContour(contour, kxmid, kymid, 1e-6);
        else {  // special cases
            if (type == RECTANGLE_OBJ) {
                RectangleParam rpRectangleParam;
                if (GetObjParam(contour, &rpRectangleParam, sizeof(RectangleParam), ALLPARAM))
                {
                    double x = rpRectangleParam.x,
                           y = rpRectangleParam.y;
                    double angle = rpRectangleParam.ang;
                    double w = rpRectangleParam.width,
                           h = rpRectangleParam.height;
                    side = 3;
                }
            }
            if (type == REGULARPOLYGON_OBJ) {
                RegularPolygonParam rppRegularPolygonParam;
                if (GetObjParam(contour, &rppRegularPolygonParam, sizeof(RegularPolygonParam), ALLPARAM))
                {
                    double xc = rppRegularPolygonParam.xc,
                           yc = rppRegularPolygonParam.yc;
                    double angle = rppRegularPolygonParam.ang;
                    double r = rppRegularPolygonParam.radius;
                    int sides = rppRegularPolygonParam.count;
                    int inscribed = rppRegularPolygonParam.describe;

                    r = (inscribed == 0)? r/2 : r;
                    side = (DistancePntPnt(xc, yc, kxmid, kymid) < r)? 3 : 1;
                }
            }
        }
/*        MovePoint(&kx0, &ky0, norm, dist);
        if (equal_points(kx, ky, kx0, ky0)) ret = side;
        else ret = (side == 1)? 3 : (side == 3)? 1 : side;*/
        double tx = kx0, ty = ky0;
        int dir = swapped? -1 : 1;
        if (ksMovePointOnCurve (contour, &tx, &ty, 0.01, dir))
        {
            bool right_ort = 0 <= ( (kx - kx0) * (ty - ky0) - (tx - kx0) * (ky - ky0) );
#if defined(DO_DEBUG)
//if (right_ort)
//::Message("CheckIntersections : right_ort == true");
//else
//::Message("CheckIntersections : right_ort == false");
#endif
            if (!right_ort) side = (side == 1)? 3 : (side == 3)? 1 : side;
            //right = right_ort;
        }
        ret = side;
    }
    ::ClearArray(intersections);
    ::DeleteArray(intersections);
    if (norm_line) DeleteObj(norm_line);
    return ret;
}

reference CSewingDlg::DestroyContoursGroup(int tipSearch)
{
    ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document       (for KAPI5 usage)

    IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
    if (!doc7) { Message("No document open - destroy"); return 0; }

//return 0;
    std::vector<reference> locContours;    // destroyed from CONTOUR_OBJ
    do {
        KompasIteratorHolder contour_iterator(CreateIterator(tipSearch, 0));

        reference cur_obj_reference = MoveIterator(contour_iterator, 'F');
        while (cur_obj_reference)
        {
            int type = GetObjParam(cur_obj_reference, 0, 0, ALLPARAM);
            if (type != 0 && IsGeomObject( cur_obj_reference ) && (type == CONTOUR_OBJ))     // ONLY for CONTOURs!
            {
                //if (!ksIsCurveClosed(cur_obj_reference))    // !only not closed (skip singletons)
                    locContours.push_back(cur_obj_reference);
            }
            cur_obj_reference = MoveIterator(contour_iterator, 'N');
        }
    } while (0);

    if (locContours.size() == 0) return 0;

    reference a_group = 0, n_group = 0;

    // Creating doc for building of nurbs approximation
    DocumentParamT parDocument;
    memset( &parDocument, 0, sizeof( parDocument ) );
    parDocument.regim = 1;  // hidden mode
    parDocument.type = 3;
    reference tmp_doc = CreateDocumentT( &parDocument ); // fragment creation

    IKompasDocumentPtr tmp_doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
    doc7->Application->ActiveDocument = doc7;

    n_group = NewGroup(0);
    EndGroup();
    a_group = NewGroup(1);
    EndGroup();
    reference n_group0 = 0;

    for (int i = 0; i < (int)locContours.size(); i++)
    {
        //locContours[i] = ksCopyObj(locContours[i],0,0,0,0,1,0);
        AddObjGroup(a_group, locContours[i]);
//int iii = ExistGroupObj(a_group);

        if (a_group && ExistGroupObj(a_group))
        {
            doc7->Application->ActiveDocument = tmp_doc7;

            reference b_group = CopyGroupToDocument(a_group, m_pKompasDoc5->reference, tmp_doc);

            StoreTmpGroup( b_group );
            ksDestroyObjects(b_group);
            if (b_group) DeleteObj(b_group);

            reference c_group = NewGroup(1);
            EndGroup();
            SelectGroup(c_group, 2, 0,0,0,0);

            if (ExistGroupObj(c_group))
            {
                n_group0 = CopyGroupToDocument(c_group, tmp_doc, m_pKompasDoc5->reference);
                //ClearGroup(c_group);  - ! WRONG : this clears the group and DeleteObj(c_group) DOESN'T delete any objects!
            }
            if (c_group) DeleteObj(c_group);

            //doc7->Active = TRUE;
            doc7->Application->ActiveDocument = doc7;

            if (!n_group0) continue;

            StoreTmpGroup( n_group0 );

            do {
                KompasIteratorHolder contour_iterator(CreateIterator(ALL_OBJ, n_group0));

                reference cur_obj = MoveIterator(contour_iterator, 'F');
                while (cur_obj)
                {
                    int type = GetObjParam(cur_obj, 0, 0, ALLPARAM);
                    m_CurveParts.insert(std::pair <reference, reference> (cur_obj, locContours[i]));
                    AddObjGroup(n_group, cur_obj);
                    cur_obj = MoveIterator(contour_iterator, 'N');
                }
            } while (0);

            ClearGroup(n_group0);
        }
        ClearGroup(a_group);
    }
    if (tmp_doc) CloseDocument(tmp_doc);
    DeleteObj(a_group);
    if (n_group0) DeleteObj(n_group0);

    if (!ExistGroupObj(n_group)) { DeleteObj(n_group); n_group = 0; }

    return n_group;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// обработчики сообщений CSewingDlg
void CSewingDlg::api7test()
{
    UpdateData(TRUE);

    if (m_StockOutCheck == 0 && m_StockInCheck == 0) return;

    sewing_object->ShowWindow(SW_HIDE);
    EnableTaskAccess( 0 );          // Disable Kompas access
    ksUndoContainer(true);

    EquidistantParam equidParam;
    memset(&equidParam, 0, sizeof(equidParam));

    equidParam.side = m_StockOutCheck != 0 && m_StockInCheck != 0?
        2 : m_StockOutCheck != 0? 1 : 0;    // признак, с какой стороны строить эквидистанту
    equidParam.cutMode = 0;//1;  // тип обхода углов контура: 0-обход срезом, 1- обход дугой
    equidParam.degState = 0; // флаг разрешения вырожденных сегментов эквидистанты:
                             // 0-вырожденные сегменты запрещены, 1-вырожденные сегменты разрешены

    equidParam.radRight = std::max(0.0, m_StockOut); // радиус эквидистанты справа по направлению кривой
    equidParam.radLeft = std::max(0.0, m_StockIn); // радиус эквидистанты слева

    equidParam.radRight *= m_MmToUnits;
    equidParam.radLeft *= m_MmToUnits;

    equidParam.style = EQUI_STYLE;  // 2; // тип линии

    int tipSearch = SELECT_GROUP_OBJ;   // : ALL_OBJ;

    KompasIteratorHolder group_iterator(CreateIterator(tipSearch, 0));

    reference cur_obj_reference = MoveIterator(group_iterator, 'F');
    if (cur_obj_reference == 0) Message("Nothing selected");
    else
    {
/*        while (cur_obj_reference)
        {
            equi_curves.clear();
            int type = GetObjParam(cur_obj_reference, 0, 0, ALLPARAM);
            if (type != 0 && IsGeomObject( cur_obj_reference ))
            {
                equi_curves_count = 1;
                equi_curves.push_back(cur_obj_reference);
                equidParam.geoObj = cur_obj_reference;
                DrawEquidistant(&equidParam, false);
                equi_curves.clear();
            }
            cur_obj_reference = MoveIterator(group_iterator, 'N');
        }*/

        equi_curves.clear();
        equi_curves_count = 0;
        while (cur_obj_reference)
        {
            int type = GetObjParam(cur_obj_reference, 0, 0, ALLPARAM);
            if (type != 0 && IsGeomObject( cur_obj_reference ))
            {
                equi_curves.push_back(cur_obj_reference);
                equi_curves_count++;
            }
            cur_obj_reference = MoveIterator(group_iterator, 'N');
        }

        IKompasDocumentPtr doc7 = newKompasAPI->ActiveDocument; // ksTransferReference( m_pKompasDoc5->reference, 0 );
        IKompasDocument2DPtr pkdDocument = 0;
        doc7->QueryInterface(&pkdDocument);
        IViewPtr ivpView = pkdDocument->ViewsAndLayersManager->Views->View[0];
        IDrawingContainerPtr pdcContainer = 0;
        ivpView->QueryInterface(&pdcContainer);

        IDrawingContoursPtr idcContours = pdcContainer->DrawingContours;
        IDrawingContourPtr idcContour = 0;
        IContourPtr pContour = 0;

        idcContour = idcContours->Add();
        idcContour->QueryInterface(&pContour);

        IMath2DPtr mathp = newKompasAPI->Application->Math2D;

        int contour_count = pContour->Count;

        //ksDocument2DPtr m_pKompasDoc5  = kompasAPI->ActiveDocument2D();

        double t1, t2;
        double x1, y1, x2, y2;
        
        ksGetCurveMinMaxParametr (equi_curves[0], &t1, &t2);
        ksGetCurvePoint(equi_curves[0], t1, &x1, &y1);
        ksGetCurvePoint(equi_curves[0], t2, &x2, &y2);
        m_BegPoint.x = x1, m_BegPoint.y = y1;
        m_swapped = CheckSwapCurve(equi_curves[0]);
        if (m_swapped) m_BegPoint.x = x2, m_BegPoint.y = y2;
        //m_pKompasDoc5->ksContour(1);
        for (int i = 0; i < equi_curves.size(); i++)
        {
            //Contour(1);
            reference obj = 0;
            reference curve = equi_curves[i];
            //obj = Draw2DElement(equi_curves[i]);

            int type = GetObjParam(curve, 0, 0, ALLPARAM);
            if (type != 0 && IsGeomObject( curve ))
            {
//                IContourSegmentPtr icsSegment = 0;
                //ICurve2DPtr temp_curve = 0;
Message("case ELLIPSE_ARC_OBJ:");
                reference obj = Draw2DElement(curve);
                IDrawingObjectPtr pCurve = obj? ksTransferReference(obj, 0) : 0;
                if (pCurve) pContour->CopyCurve(pCurve, FALSE);
                contour_count = pContour->Count;
                IContourSegmentPtr icsSegment = pContour->Segment[0];

                if (obj) DeleteObj(obj);
            }
        }

        if (contour_count > 0)
        {
            idcContour->Update();
            PumpWaitingMessages();
        }


        //reference ref = m_pKompasDoc5->ksEndObj();
        reference ref = idcContour->Reference;
        if (ref == 0)  ref = pContour->Reference;

        /*equidParam.geoObj = ref;

        DrawEquidistant(&equidParam, m_swapped);
        if (ref) DeleteObj(ref);*/

        //if (ref == 0)
        {
            IEquidistantsPtr Equidistant_pool = pdcContainer->Equidistants;
            IEquidistantPtr Equidistant_curve = Equidistant_pool->Add();

            IDrawingObjectPtr drawing_object = idcContour;

            BOOL isok = false;
            BOOL test_isok = false;
            do {
                Equidistant_curve->BaseObject = drawing_object;
                Equidistant_curve->CutMode = equidParam.cutMode == 0? FALSE : TRUE;
                Equidistant_curve->DegenerateSegment = equidParam.degState == 0? FALSE : TRUE;
                Equidistant_curve->LeftRadius = equidParam.radLeft;
                Equidistant_curve->RightRadius = equidParam.radRight;
                Equidistant_curve->Side = equidParam.side == 2? ksETBoth :
                    equidParam.side == 0? ksETLeft : equidParam.side == 1? ksETRight : ksETUnknown;
                Equidistant_curve->Style = equidParam.style;

                isok = Equidistant_curve->Update();
            //if (!isok)
            // for (int i = 0; i < 10; i++) { PumpWaitingMessages(); isok = Equidistant_curve->Update(); if (isok) break; }
        //Message("Bad Equi->Update()");

            //pdoDrawingObject->LayerNumber = pdoDrawingObject->LayerNumber;
            //if (!pdoDrawingObject->Update()) Message("NO update");

                if (!isok) {
                    Equidistant_curve->DegenerateSegment = TRUE;
                    //Equidistant_curve->CutMode = TRUE;
                }
                isok = isok || test_isok;
                test_isok = true;
            } while (!isok);

            ref = Equidistant_curve->Reference;
        }

        if (idcContour) idcContour->Delete();

        equi_curves.clear();
        equi_curves_count = 0;
    }


    EnableTaskAccess( 1 );          // Enable Kompas access
    ksExecuteKompasCommand(ksCMRefresh, 1);
}


void CSewingDlg::OnBnClickedDrawOperation()
{
//return api7test();

    UpdateData(TRUE);

    if (m_StockOutCheck == 0 && m_StockInCheck == 0) return;

    sewing_object->ShowWindow(SW_HIDE);
    EnableTaskAccess( 0 );          // Disable Kompas access
    ksUndoContainer(true);

//  IKompasDocumentPtr m_pKompasDoc7;   // Current Kompas document    (for KAPI7/KAPI5 usage)
    ksDocument2DPtr m_pKompasDoc5 = kompasAPI->ActiveDocument2D();  // Current Kompas document       (for KAPI5 usage)

    m_CurveParts.clear();

    int tipSearch = (m_SelectType == enCurves_All)? ALL_OBJ_SHOW_ORDER :
        (m_SelectType == enCurves_Selected)? SELECT_GROUP_OBJ : ALL_OBJ;

    reference ex_group = CSewingDlg::DestroyContoursGroup(tipSearch);
    std::vector<reference> locApproxedGroups;

    if (m_SelectType == enCurves_Selected)
        AddObjGroup(0, ex_group);   // выделение!

    do {
        KompasIteratorHolder all_iterator(CreateIterator(tipSearch, 0));
        std::vector<reference> locApproxedCurves;

        reference cur_obj_reference = MoveIterator(all_iterator, 'F');
        while (cur_obj_reference)
        {
            int type = GetObjParam(cur_obj_reference, 0, 0, ALLPARAM);
            if (type != 0 && IsGeomObject( cur_obj_reference )
                && (type == CONTOUR_OBJ))//?? || type == BEZIER_OBJ))     // || type == NURBS_OBJ))
            {
                if (type != CONTOUR_OBJ)
                    locApproxedCurves.push_back(cur_obj_reference);
            }
            cur_obj_reference = MoveIterator(all_iterator, 'N');
        }

        for (int i = 0; i < (int)locApproxedCurves.size(); i++) {
            int type = GetObjParam(locApproxedCurves[i], 0, 0, ALLPARAM);
            reference tmp_grp = DrawApproximation(locApproxedCurves[i], type);
            if (tmp_grp && ExistGroupObj(tmp_grp))
            {
                locApproxedGroups.push_back( tmp_grp );
                do {
                    KompasIteratorHolder contour_iterator(CreateIterator(ALL_OBJ, tmp_grp));

                    reference cur_obj = MoveIterator(contour_iterator, 'F');
                    while (cur_obj)
                    {
                        int type = GetObjParam(cur_obj, 0, 0, ALLPARAM);
                        m_CurveParts.insert(std::pair <reference, reference> (cur_obj, locApproxedCurves[i]));
                        cur_obj = MoveIterator(contour_iterator, 'N');
                    }
                } while (0);

                if (m_SelectType == enCurves_Selected)
                    AddObjGroup(0, tmp_grp);   // выделение!
            }
        }
    } while (0);

    EquidistantParam equidParam;
    memset(&equidParam, 0, sizeof(equidParam));

//    equidParam.geoObj = obj;    //-базовая кривая эквидистанты

    equidParam.side = m_StockOutCheck != 0 && m_StockInCheck != 0?
        2 : m_StockOutCheck != 0? 1 : 0;    // признак, с какой стороны строить эквидистанту
    equidParam.cutMode = 0;//1;  // тип обхода углов контура: 0-обход срезом, 1- обход дугой
    equidParam.degState = 0; // флаг разрешения вырожденных сегментов эквидистанты:
                             // 0-вырожденные сегменты запрещены, 1-вырожденные сегменты разрешены

    equidParam.radRight = std::max(0.0, m_StockOut); // радиус эквидистанты справа по направлению кривой
    equidParam.radLeft = std::max(0.0, m_StockIn); // радиус эквидистанты слева

    equidParam.radRight *= m_MmToUnits;
    equidParam.radLeft *= m_MmToUnits;

    equidParam.style = EQUI_STYLE;  // 2; // тип линии

    KompasIteratorHolder group_iterator(CreateIterator(tipSearch, 0));

    PrepareContoursMakeEquidistants(group_iterator, &equidParam);

    for (int i = 0; i < (int)locApproxedGroups.size(); i++) DeleteObj(locApproxedGroups[i]);

    if (ex_group) {
        //if (ExistGroupObj(ex_group)) ClearGroup(ex_group);    // SKIP THIS to delete STORED group!
        DeleteObj(ex_group);
    }

    m_CurveParts.clear();

    ksUndoContainer(false);

    RefreshKompasActiveDocument();
    m_UndoRedo = 0;

    EnableTaskAccess( 1 );          // Enable Kompas access
    ((CButton*)GetDlgItem( IDC_UNDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditUndo) != 0 );
    ((CButton*)GetDlgItem( IDC_REDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditRedo) != 0 );
    sewing_object->ShowWindow(SW_NORMAL);
    sewing_object->SetActiveWindow();

    ksExecuteKompasCommand(ksCMRefresh, 1);
}

void CSewingDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
//    MessageBox(L"OnKeyDown");
}

extern void DrawRectNULL();
extern void DrawRectCallBack();

void CSewingDlg::OnBnClickedCancel()
{
    if (stateManualDrawMarks == FALSE)
        return OnCancel();

    stateManualDrawMarks = FALSE;
    ((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->SetWindowTextW( L"Ввод засечек" );

    ((CButton*)GetDlgItem( IDC_DATAEDIT ))->ShowWindow(SW_HIDE);

    ((CButton*)GetDlgItem( IDC_STATIC ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_STATIC2 ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_STATIC3 ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_STATIC4 ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_STATIC5 ))->ShowWindow(SW_SHOWNOACTIVATE);

    ((CButton*)GetDlgItem( IDC_STOCKOUT ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_STOCKIN ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_MARKING ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_MARKS_PER_CURVE ))->ShowWindow(SW_SHOWNOACTIVATE);
    ((CButton*)GetDlgItem( IDC_CURVE_MAX_POINTS ))->ShowWindow(SW_SHOWNOACTIVATE);
}

void CSewingDlg::OnBnClickedManualMarks()
{
    //bool res = sewing_object->ShowWindow(SW_HIDE) != FALSE; // Show dialog

    IDispatchPtr doc = kompasAPI->ksGetDocumentByReference(0);
    //if (1)
    if ( !BaseEvent::FindEvent( DIID_ksDocumentFileNotify, doc ) )
    {
        // Advising to Document etc. Events - DOESNT advise DocumentFrameEvent!
        AdviseDoc( kompasAPI, doc, kompasAPI->ksGetDocumentType( 0 ) );
    }
    //((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->EnableWindow( 0 );
    stateManualDrawMarks = stateManualDrawMarks == FALSE? TRUE : FALSE;
    if (stateManualDrawMarks == TRUE)
        ((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->SetWindowTextW( L"Сброс режима" );
    else
        ((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->SetWindowTextW( L"Ввод засечек" );

    ((CButton*)GetDlgItem( IDC_STATIC ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_STATIC2 ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_STATIC3 ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_STATIC4 ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_STATIC5 ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);

    ((CButton*)GetDlgItem( IDC_STOCKOUT ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_STOCKIN ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_MARKING ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_MARKS_PER_CURVE ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);
    ((CButton*)GetDlgItem( IDC_CURVE_MAX_POINTS ))->ShowWindow(stateManualDrawMarks == FALSE? SW_SHOWNOACTIVATE : SW_HIDE);

    ((CButton*)GetDlgItem( IDC_DATAEDIT ))->ShowWindow(stateManualDrawMarks == TRUE? SW_SHOWNOACTIVATE : SW_HIDE);

    //DrawRectNULL();
if (0)
    DrawRectCallBack();
if (0) {
//void CommandWindow_Example (void)
    RequestInfo info;
    memset(&info, 0, sizeof(info)); 
    info.commands = "!Окружность !Отрезок ";
    info.title = "Объекты";

    int j=CommandWindow(&info);
    switch (j) { 
    case 1: 
    Circle(10,10,10,1); 
    break; 
    case 2: 
    LineSeg(10,10, 20, 10, 1); 
    break; 
    }
}   // CommandWindow_Example
    //res = (sewing_object->ShowWindow(SW_NORMAL) != FALSE); // Show dialog
}

void CSewingDlg::OnBnClickedUndo()
{
    //bool res = sewing_object->ShowWindow(SW_HIDE) != FALSE; // Show dialog

    int cUndoRedo = ksCMEditUndo;   // m_UndoRedo == 0? ksCMEditUndo : ksCMEditRedo;
    //m_UndoRedo = m_UndoRedo == 0? 1 : 0;
    m_UndoRedo += 1;

    ksExecuteKompasCommand(cUndoRedo, 0);
    RefreshKompasActiveDocument();
    ((CButton*)GetDlgItem( IDC_UNDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditUndo) != 0 );
    ((CButton*)GetDlgItem( IDC_REDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditRedo) != 0 );
    ksExecuteKompasCommand(ksCMRefresh, 1);
}

void CSewingDlg::OnBnClickedRedo()
{
    int cUndoRedo = ksCMEditRedo;   // m_UndoRedo == 0? ksCMEditUndo : ksCMEditRedo;
    m_UndoRedo -= 1;

    ksExecuteKompasCommand(cUndoRedo, 0);
    RefreshKompasActiveDocument();
    ((CButton*)GetDlgItem( IDC_UNDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditUndo) != 0 );
    ((CButton*)GetDlgItem( IDC_REDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditRedo) != 0 );
    ksExecuteKompasCommand(ksCMRefresh, 1);
}

void CSewingDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
    CDialog::OnActivate(nState, pWndOther, bMinimized);

    if (nState == WA_INACTIVE) return;

    int doctype = ksGetDocumentType(0);
    int dd1 = kompasAPI->ksGetDocumentType(0);
    IKompasDocumentPtr ppp = (IKompasDocumentPtr)kompasAPI->ksGetDocumentByReference(0);
    int ddd2 = ppp? ppp->DocumentType : 0;
    //if (doctype == 0) return;
    if (doctype == 0 ||
        (doctype != lt_DocSheetStandart && doctype != lt_DocSheetUser && doctype != lt_DocFragment))
    {
        bool actitest = ((CButton*)GetDlgItem( IDC_DRAW_OPERATION ))->IsWindowEnabled() != FALSE;
        ((CButton*)GetDlgItem( IDC_DRAW_OPERATION ))->EnableWindow( 0 );
        ((CButton*)GetDlgItem( IDC_UNDO ))->EnableWindow( 0 );
        ((CButton*)GetDlgItem( IDC_REDO ))->EnableWindow( 0 );
        ((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->EnableWindow( 0 );
        if (actitest)   // || doctype == 0)
            Message("Активный документ не является чертежом или фрагментом или не открыто никакого документа."
                   "\nПлагин будет отключен до перехода к поддерживаемому типу документа.");
    }
    else
    {
        ((CButton*)GetDlgItem( IDC_DRAW_OPERATION ))->EnableWindow( 1 );
        ((CButton*)GetDlgItem( IDC_UNDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditUndo) != 0 );
        ((CButton*)GetDlgItem( IDC_REDO ))->EnableWindow( ksIsKompasCommandEnable(ksCMEditRedo) != 0 );
        ((CButton*)GetDlgItem( IDC_MANUAL_MARKS ))->EnableWindow( 1 );
            //((CEdit*)GetDlgItem( IDC_DATAEDIT ))->GetWindowTextLengthW() == 0? 1 : 0 );

        short unittype = 0;
        if (GetDocOptions(LENGTHUNITS_OPTIONS, &unittype, sizeof(unittype)))
            m_MmToUnits = (unittype == ST_MIX_MM)? 1.0 : (unittype == ST_MIX_SM)? 0.1 :
                          (unittype == ST_MIX_DM)? 0.01 : (unittype == ST_MIX_M)? 0.001 : 1.0;
        MmToUnits = m_MmToUnits;
    }
}


void CSewingDlg::ParseDoubleData(int nID)
{
    CEdit* ctrl_item = (CEdit*)sewing_object->GetDlgItem(nID);
    CString text;
    ctrl_item->GetWindowTextW(text);
    int chindex = text.Find('.');
    if (chindex >= 0) {
        chindex = text.Find('.', chindex + 1);
        if (chindex >= 0) ctrl_item->SetWindowTextW(text.Left(chindex));
    }
    if (ctrl_item->GetWindowTextLengthW() == 1 && text.Find('.') >= 0) ctrl_item->SetWindowTextW(_T(""));
    if (ctrl_item->GetWindowTextLengthW() == 0) ctrl_item->SetWindowTextW(_T("0"));
}

void CSewingDlg::OnEnKillfocusStockout()
{
    ParseDoubleData(IDC_STOCKOUT);
}

void CSewingDlg::OnEnKillfocusStockin()
{
    ParseDoubleData(IDC_STOCKIN);
}

void CSewingDlg::OnEnKillfocusMarking()
{
    ParseDoubleData(IDC_MARKING);
}

void CSewingDlg::OnEnKillfocusPrecision()
{
    ParseDoubleData(IDC_PRECISION);
}

void CSewingDlg::OnEnChangeMarking()
{
    // TODO:  Если это элемент управления RICHEDIT, то элемент управления не будет
    // send this notification unless you override the CDialog::OnInitDialog()
    // function and call CRichEditCtrl().SetEventMask()
    // with the ENM_CHANGE flag ORed into the mask.

    // TODO:  Добавьте код элемента управления
}
Третий Рим должен пасть!
Re: Оцените качество кода на С++
От: alxn1 Россия  
Дата: 18.09.14 09:58
Оценка: +5
На мой взгляд CSewingDlg — это обьект-бог, он делает столько всего, что аж дух захватывает. Накожено, может быть и ничего (стиль определенно чувствуется), но быстро разобраться в этом очень трудно, не говоря уже о поддержке такого. Это моя субьективная оценка

Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.
Re: Оцените качество кода на С++
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.09.14 09:58
Оценка: +2
в общем, довольно не плохо с первого взгляда, видал и похуже %)
"порадовало" использование запятой:
if (basepoint == 0)
  Points.push_back(mpMathPoint.x),
  Points.push_back(mpMathPoint.y),
  Points.push_back(right2X),
  Points.push_back(right2Y);
else if (basepoint == basepoint_count - 1 && closed_path == false)
  Points.push_back(left2X),
  Points.push_back(left2Y),
  Points.push_back(mpMathPoint.x),
  Points.push_back(mpMathPoint.y);
else
  Points.push_back(left2X),
  Points.push_back(left2Y),
  Points.push_back(mpMathPoint.x),
  Points.push_back(mpMathPoint.y),
  Points.push_back(mpMathPoint.x),
  Points.push_back(mpMathPoint.y),   // doubling inner point!
  Points.push_back(right2X),
  Points.push_back(right2Y),
  Weights.push_back(1.0),
  Weights.push_back(1.0);   // doubling inner point!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.09.2014 10:01 niXman . Предыдущая версия .
Re[2]: Оцените качество кода на С++
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.09.14 09:59
Оценка:
и да, функции размером в двести строк, тоже доставляют %)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: Оцените качество кода на С++
От: uzhas Ниоткуда  
Дата: 18.09.14 10:14
Оценка: +1
Здравствуйте, alxn1, Вы писали:

A>Накожено, может быть и ничего (стиль определенно чувствуется)

стиля тут точно нет
члены класса:
    bool Activated;
    PointParam m_BegPoint;
    reference m_grpAuxScratches;
    unsigned short m_curves_style;


с остальным согласен, write-only код
Re: Оцените качество кода на С++
От: Kernighan СССР  
Дата: 18.09.14 10:15
Оценка: 5 (2) +5
Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.


Ну, этот код по читаемости гораздо лучше того, что пишу например я.
Чтобы разговор вышел из детсадовского уровня сформулируй свои претензии в виде слов — что тебе не нравится.
Я уверен, что твой сотрудник пойдёт тебе навстречу, если ты правильно сформулируешь.
Re: Оцените качество кода на С++
От: Кодт Россия  
Дата: 18.09.14 10:26
Оценка: -2
Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.


GC>
GC>// SewingDlg.h 

// мне казалось, что визард лепит стандартный инклуд-гард наряду с pragma once
// для MSVC его отсутствие, в общем-то, некритично, но всё же... культуру себе надо прививать

#ifndef __SEWING_DLG__H__
#define __SEWING_DLG__H__
// и в конце
#undef//__SEWING_DLG__H__

GC>#pragma once

GC>#include "MainHeaders.h" // почему не засунуто в "stdafx.h" ?
GC>#include "afxwin.h" // <afxwin.h> чтобы подчеркнуть, что этот хедер вне проекта, из системной библиотеки

GC>#include <vector>
GC>#include <map>

#define NOMINMAX // где-нибудь в самом начале stdafx.h

GC>#ifdef max
GC>#undef max
GC>#endif

GC>#ifdef min
GC>#undef min
GC>#endif


Вот эту часть я бы вынес в отдельный хедер. Явно же она нужна где-то ещё, и зачем в нагрузку к ней тащить диалог?
GC>class KompasObjectHolder // немец, что ли? CompassObjectHolder
GC>{
GC>protected:
GC>    reference m_reference; // не видя, как определён тип reference, сложно сказать, нужны ли все эти танцы с бубном...
GC>public:
GC>    KompasObjectHolder() : m_reference(0) {}
GC>    KompasObjectHolder(reference object_reference) : m_reference(object_reference) {}
GC>    KompasObjectHolder(KompasObjectHolder& prev_holder) : m_reference(prev_holder.m_reference) { prev_holder.m_reference = 0; }
GC>    KompasObjectHolder& operator =(KompasObjectHolder& prev_holder) {
GC>        if (!m_reference) m_reference = prev_holder.m_reference, prev_holder.m_reference = 0; return *this; }
GC>    ~KompasObjectHolder()
GC>    {
GC>        if (m_reference) DeleteObj(m_reference);
GC>        m_reference = 0;
GC>    }
GC>    operator reference() { return m_reference; }
GC>    operator bool() { return m_reference != 0; }
GC>};

// я бы сделал проще
typedef /*boost|std*/ shared_ptr<reference> compass_obj_ptr;
compass_obj_ptr make_compass_obj_ptr(reference r) { return compass_obj_ptr(r, DeleteObj); }


// вот это - кажется архитектурным злом. Наследовать один умный указатель от другого умного указателя...

GC>class KompasIteratorHolder : public KompasObjectHolder
GC>{
GC>public:
GC>    KompasIteratorHolder() {}
GC>    KompasIteratorHolder(reference iterator_reference) : KompasObjectHolder(iterator_reference) {}
GC>    KompasIteratorHolder& operator =(KompasIteratorHolder& prev_holder) {
GC>        if (!m_reference) m_reference = prev_holder.m_reference, prev_holder.m_reference = 0; return *this; }
GC>    ~KompasIteratorHolder()
GC>    {
GC>        if (m_reference) DeleteIterator(m_reference);
GC>        m_reference = 0;
GC>    }
GC>};

// быстрое-грязное решение (но опять же, я не знаю, что за сущность такая - reference)
compass_obj_ptr make_compass_obj_iter(reference r) { return compass_obj_ptr(r, DeleteIterator); }


В самом диалоге очень сильно настораживает обилие голых reference.
Надо уж определиться: или они подлежат какому-то контролю за временем жизни, или этот контроль не больно-то нужен.
Особенно это касается вектора и мапа. Ну хоть бы какое-то словесное примечание было: например, что время жизни диалога заведомо меньше времени жизни этих reference, переданных туда извне.
GC>class CSewingDlg : public CDialog       // диалоговое окно CSewingDlg
GC>{
GC>    DECLARE_DYNAMIC(CSewingDlg)

GC>public:
GC>    CSewingDlg(CWnd* pParent = NULL);   // стандартный конструктор
GC>    virtual ~CSewingDlg();

GC>    reference Draw2DElement(reference element, bool closed = false);
GC>    reference DrawLineSeg(reference element);
GC>    reference DrawCircle(reference element);
GC>    reference DrawArc(reference element);
GC>    reference DrawEllipse(reference element);
GC>        reference DrawEllipseArc(reference element);                    // BAD when coercing EllipseArc & Nurbs ??bag in KOMPAS
GC>    reference DrawEllipseArcWithNurbs(reference element);               // new API7+IMath2D version - !EllipseArc as case of Nurbs
GC>    reference DrawRectangle(reference element);
GC>    reference DrawRegularPolygon(reference element);
GC>        reference DrawBezier(reference element, bool closed = false);   // new API7 version - allows Bezier 2 type (Equidistants fail too)
GC>    reference DrawBezierWithNurbs(reference element, bool closed);      // new API7+IMath2D version - !Bezier as case of Nurbs
GC>    reference DrawEquidistant7(IDrawingObjectPtr& idcContour,
GC>                              EquidistantParam *equiparam, bool swapped);       // new API7 version - no adv.features
GC>    reference DrawEquidistant(EquidistantParam *equiparam, bool swapped);       // new API5 version - ?
GC>    reference DrawPolyline(reference element, bool closed = false);
GC>        reference DrawApproximation(reference element, int curve_type);
GC>    reference DrawContour(reference element, bool closed = false);
GC>    reference DrawNurbs(reference element, bool closed = false);    // new API7+IMath2D version - !works

GC>    reference SmallNurbs3(double x1, double y1, double x2, double y2, unsigned short style);

GC>    double CurvesDeviation(reference old_curve, ICurve2DPtr& new_curve, double precision, double* tpars, int points_count);

GC>    inline void KompasCorrectAngles(double& dBeginAngle, double& dEndAngle, bool clockwise);

GC>    int PseudoProcessAcceptedData(void* pInputData, EquidistantParam *equiparam, bool PseudoGroupMode);
GC>    void PrepareContoursMakeEquidistants(reference obj_iterator, EquidistantParam* equiparam);

GC>    void ProcessMarks(reference curve, reference contour, EquidistantParam* equiparam);

GC>    bool CheckSwapBegPoint(double& x1, double& y1, double& x2, double& y2);
GC>    bool CheckTipWithScratch(double& x1, double& y1);
GC>    bool CheckSwapCurve(reference curve);
GC>    reference DestroyContoursGroup(int tipSearch);
GC>    double GetEquidistantPerimeter(reference element);      // using destroyObj to get true length of Equidistant
GC>    int CheckContourSide(reference contour, bool swapped, bool issingle);
GC>    int CheckIntersections(reference contour, bool swapped, double t);

GC>    bool TestInterrupt(LPSTR msg, int count);

GC>void api7test();

GC>    bool Activated;
GC>    PointParam m_BegPoint;
GC>    reference m_grpAuxScratches;
GC>    unsigned short m_curves_style;

GC>// Данные диалогового окна
GC>    enum { IDD = IDD_SEWINGDLG };
GC>    enum { enCurves_All = 0, enCurves_Selected, enCurves_Unselected };

GC>protected:
GC>    virtual BOOL OnInitDialog();

GC>    void ParseDoubleData(int nID);

GC>    virtual void DoDataExchange(CDataExchange* pDX);    // поддержка DDX/DDV

GC>    DECLARE_MESSAGE_MAP()
GC>public:
GC>    afx_msg void OnBnClickedDrawOperation();
GC>    afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
GC>    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
GC>    afx_msg void OnBnClickedCancel();
GC>    afx_msg void OnBnClickedUndo();
GC>    afx_msg void OnBnClickedRedo();
GC>protected:
GC>    int m_StockOutCheck;
GC>    int m_StockInCheck;
GC>    int m_MarkingCheck;
GC>    double m_StockOut;
GC>    double m_StockIn;
GC>    double m_MarkingStep;
GC>    int m_SelectType;
GC>private:
GC>    int m_UndoRedo;
GC>    int m_ProcessClosedOnly;
GC>    int m_ContourHasAnyLineStyles;
GC>    int m_ProcessEnclosedContours;
GC>    int m_MaxSplitNum;
GC>    int m_MaxMarksNum;
GC>    double m_MmToUnits;

GC>    double m_precision;

GC>    std::map<reference, reference> m_CurveParts;
GC>    std::vector<reference> equi_curves;     // tmp vector needed to correct Equidistant behavior
GC>    int equi_curves_count;                  // may differ from equi_curves.size() due to m_grpAuxScratches
GC>    bool m_swapped;
GC>    bool m_issingle;
GC>    reference m_aux_scratch;
GC>    bool m_skip_scratch;        // in API5 Contour()-mode all references are 0 = i.e. temp intrinsic objects for Contour()
GC>public:
GC>    afx_msg void OnBnClickedManualMarks();
GC>    afx_msg void OnEnKillfocusPrecision();
GC>    afx_msg void OnEnKillfocusStockout();
GC>    afx_msg void OnEnKillfocusStockin();
GC>    afx_msg void OnEnKillfocusMarking();
GC>    afx_msg void OnEnChangeMarking();
GC>};

GC>


GC>
GC>// SewingDlg.cpp: файл реализации
GC>//

GC>#include "stdafx.h"
GC>#include "SewingDlg.h"
GC>#include "ProgressDlg.h"
GC>#include "SewingPlugin.h"

GC>#include "testEvents/BaseEvent.h"

GC>#include <limits>
GC>#include <cmath>
GC>#include <algorithm>

GC>const double PI2DEGREE = 180.0 / 3.14159265;
GC>const int EQUI_STYLE = ksCSConstruction;    // 6 : вспомогательная (красная)

GC>extern BOOL glb_Interrupt;

GC>//   from eventsAuto.cpp
GC>void AdviseDoc( KompasObject* kompas,
GC>                LPDISPATCH doc, long docType,
GC>                bool fSelectMng = true,
GC>                bool fObject = true,
GC>                bool fStamp = true,
GC>                bool fDocument = true,
GC>                bool fSpecification = true,
GC>                bool fSpcObject = true,
GC>                long objType = 0 /*= -1*/);


// это рукоделие или визард напихал?

GC>#if defined(ASSERT) && !defined(_DEBUG)
GC>#undef ASSERT
GC>#define FILEW2(x) L##x
GC>#define FILEW(f) FILEW2(f)
GC>#define ASSERT(f) {CString sss;if (!(f)){sss.Format(L"BAD ASSERT in line %d (file " FILEW(__FILE__) L")", __LINE__);MessageW((LPWSTR)sss.GetString());}}
GC>#endif

// ой-ой-ой, заплатки и борьба за имитацию вариадиков в макросах.

GC>#define MESSAGE_COMMA ,
GC>#define MESSAGE(mesh) {   CString sss; sss.Format(mesh); MessageW((LPWSTR)sss.GetString());   }


// inline лишний - тем более, внутри .cpp

GC>template<typename FloatType> inline // to improve need call_traits, etc
GC>bool approx_equals(FloatType x, FloatType y, FloatType relative_factor=FloatType(64))
GC>{
GC>    // default relative_factor=64 results in approximately 2 decimal digits tolerance in significand
GC>    using std::abs; using std::max; using std::numeric_limits;
GC>    return abs(x-y) <= ( relative_factor * numeric_limits<FloatType>::epsilon() * max(abs(x),abs(y)) );
GC>}

// static inline ? достаточно одного static или запихать в локальное пространство имён
// кстати, почему бы не вынести эти функции-утилитки в отдельный хедер?

GC>static inline bool equal_points(double x1, double y1, double x2, double y2, double precision = 0.0)
GC>{
GC>    // double epsilon = 1e-16, so 1e9 gives real Kompas precision about 1e-7..1e-6..1e-5
GC>    //return VTSL::Math::approx_equals<double>( x1, x2, double(1e9) ) && VTSL::Math::approx_equals<double>( y1, y2, double(1e9) );
GC>    using std::abs; using std::max; using std::numeric_limits;

GC>    double minerror = DBL_EPSILON * double(1e9);

GC>    if (precision > minerror)
GC>        return max(abs(x1 - x2), abs(y1 - y2)) <= precision;
GC>//Message("equal_points");

GC>//  double correction = double(1e9) * (precision <= minerror? 1.0 : precision / minerror);
GC>    double correction = (precision <= minerror? minerror : precision) / DBL_EPSILON;
GC>    bool bx, by;
GC>    double absmax = max(abs(x1), abs(x2));
GC>    if ( absmax > 1.0 ) bx = approx_equals<double>( x1, x2, correction );
GC>    else {
GC>        if ( absmax < minerror ) bx = true;
GC>            else bx = approx_equals<double>( x1/absmax, x2/absmax, correction );
GC>    }
GC>    absmax = max(abs(y1), abs(y2));
GC>    if ( absmax > 1.0 ) by = approx_equals<double>( y1, y2, correction );
GC>    else {
GC>        if ( absmax < minerror ) by = true;
GC>            else by = approx_equals<double>( y1/absmax, y2/absmax, correction );
GC>    }
GC>    return bx && by;
GC>}

GC>static inline bool equal_values(double val1, double val2,  double precision = 0.0)
GC>{
GC>    const double minerror = DBL_EPSILON * double(1e9);
GC>//  double correction = double(1e9) * (precision <= minerror? 1.0 : precision / minerror);
GC>    double correction = (precision <= minerror? minerror : precision) / DBL_EPSILON;
GC>    double absmax = std::max(abs(val1), abs(val2));
GC>    if ( absmax < 1.0 )
GC>    {
GC>        if (absmax < minerror) return true;    // DBL_EPSILON * 64
GC>        return approx_equals<double>( val1/absmax, val2/absmax, correction);
GC>    }
GC>    return approx_equals<double>( val1, val2, correction);
GC>}

GC>static bool IsContourInsideContour(reference contour, reference other, CSewingDlg* pThis)
GC>{
GC>    int type = GetObjParam(other, 0, 0, ALLPARAM);
GC>    int side = 0;
GC>    double t1, t2, x1, y1, x2, y2;
GC>    ksGetCurveMinMaxParametr (contour, &t1, &t2);
GC>    ksGetCurvePoint(contour, t1, &x1, &y1);
GC>    ksGetCurvePoint(contour, t2, &x2, &y2);

GC>    if (type == CONTOUR_OBJ) {
GC>        side = ksIsPointInsideContour(other, x1, y1, 1e-6);
GC>    }

GC>    if (side == 0) {    // special cases for single bezier contour etc.
GC>        reference bref = ksApproximationCurve(other, 0.1, 0, 0, 1);
GC>        if (bref)
GC>        {
GC>            int type = GetObjParam(bref, 0, 0, ALLPARAM);
GC>            if (type == CONTOUR_OBJ) {
GC>                side = ksIsPointInsideContour(bref, x1, y1, 1e-6);
GC>            }
GC>            DeleteObj(bref);
GC>        }
GC>    }


// if(...) do{ ... break ... }while(false) - оригинально , но как бы намекает, что это место следует отрефакторить


GC>    if (side == 0) do {    // special cases for single rectangle, circle etc.

GC>        KompasObjectHolder decomposed_group(DecomposeObj(other, 5, 0.5, 1));
GC>        if (!decomposed_group) break;

GC>        KompasIteratorHolder group_iterator(CreateIterator(ALL_OBJ, decomposed_group));
GC>        if (!group_iterator) break;

GC>        Contour(1);

GC>        reference cur_obj = MoveIterator(group_iterator, 'F');
GC>        while (cur_obj)
GC>        {
GC>            pThis->Draw2DElement(cur_obj);
GC>            cur_obj = MoveIterator(group_iterator, 'N');
GC>        }

GC>        reference contour_obj = EndObj();
GC>        if (contour_obj)
GC>            side = ksIsPointInsideContour(contour_obj, x1, y1, 1e-6);
GC>        if (contour_obj) DeleteObj(contour_obj);
GC>    } while (0);

GC>    if (side == 3) {
GC>Message("IsContourInsideContour");
GC>        int kp = 0;
GC>        IntersectCurvCurv (contour, other, &kp, 0, 0, 0);
GC>        if (kp == 0) return true;
GC>    }
GC>    return false;
GC>}

GC>// диалоговое окно CSewingDlg

GC>IMPLEMENT_DYNAMIC(CSewingDlg, CDialog)

GC>CSewingDlg::CSewingDlg(CWnd* pParent /*=NULL*/)
GC>    : CDialog(CSewingDlg::IDD, pParent)
GC>    , m_StockInCheck(false)
GC>    , m_StockOutCheck(false)
GC>    , m_MarkingCheck(false)
GC>    , m_StockOut(0)
GC>    , m_StockIn(0)
GC>    , m_MarkingStep(0)
GC>    , m_SelectType(0)
GC>    , m_UndoRedo(0)
GC>    , m_ProcessClosedOnly(1)
GC>    , m_ContourHasAnyLineStyles(0)
GC>    , m_ProcessEnclosedContours(0)      // enclosing may be too slow
GC>    , m_MaxSplitNum(20)
GC>    , m_MaxMarksNum(10)
GC>    , m_precision(1.0)
GC>{
GC>    Activated = true;
GC>    m_BegPoint.x = m_BegPoint.y = 0;
GC>    m_BegPoint.style = 0;
GC>    m_grpAuxScratches = 0; m_curves_style = 0;
GC>    m_MmToUnits = 1.0;
GC>    m_swapped = m_issingle = false;
GC>    m_aux_scratch = 0; m_skip_scratch = false;
GC>}

GC>CSewingDlg::~CSewingDlg()
GC>{
GC>}

GC>void CSewingDlg::DoDataExchange(CDataExchange* pDX)
GC>{
GC>    CDialog::DoDataExchange(pDX);
GC>    DDX_Radio(pDX,      IDC_RADIO1,             m_SelectType);
GC>    DDX_Check(pDX,      IDC_STOCKOUT_CHECK,     m_StockOutCheck);
GC>    DDX_Check(pDX,      IDC_STOCKIN_CHECK,      m_StockInCheck);
GC>    DDX_Check(pDX,      IDC_MARKING_CHECK,      m_MarkingCheck);
GC>    DDX_Check(pDX,      IDC_PROCESS_CLOSED_ONLY,            m_ProcessClosedOnly);
GC>    DDX_Check(pDX,      IDC_CONTOUR_HAS_ANY_LINE_STYLES,    m_ContourHasAnyLineStyles);
GC>    DDX_Check(pDX,      IDC_PROCESS_ENCLOSED_CONTUORS,      m_ProcessEnclosedContours);
GC>    DDX_Text (pDX,      IDC_STOCKOUT,           m_StockOut);
GC>    DDX_Text (pDX,      IDC_STOCKIN,            m_StockIn);
GC>    DDX_Text (pDX,      IDC_MARKING,            m_MarkingStep);
GC>    DDX_Text (pDX,      IDC_CURVE_MAX_POINTS,   m_MaxSplitNum);
GC>    DDX_Text (pDX,      IDC_MARKS_PER_CURVE,    m_MaxMarksNum);
GC>    DDX_Text (pDX,      IDC_PRECISION,          m_precision);
GC>}


GC>BEGIN_MESSAGE_MAP(CSewingDlg, CDialog)
GC>    ON_BN_CLICKED(IDC_DRAW_OPERATION, &CSewingDlg::OnBnClickedDrawOperation)
GC>//    ON_WM_ACTIVATE()
GC>    ON_WM_KEYDOWN()
GC>    ON_BN_CLICKED(IDCANCEL, &CSewingDlg::OnBnClickedCancel)
GC>    ON_BN_CLICKED(IDC_UNDO, &CSewingDlg::OnBnClickedUndo)
GC>    ON_BN_CLICKED(IDC_REDO, &CSewingDlg::OnBnClickedRedo)
GC>//    ON_WM_CHAR()
GC>ON_WM_ACTIVATE()
GC>ON_BN_CLICKED(IDC_MANUAL_MARKS, &CSewingDlg::OnBnClickedManualMarks)
GC>ON_EN_KILLFOCUS(IDC_PRECISION, &CSewingDlg::OnEnKillfocusPrecision)
GC>ON_EN_KILLFOCUS(IDC_STOCKOUT, &CSewingDlg::OnEnKillfocusStockout)
GC>ON_EN_KILLFOCUS(IDC_STOCKIN, &CSewingDlg::OnEnKillfocusStockin)
GC>ON_EN_KILLFOCUS(IDC_MARKING, &CSewingDlg::OnEnKillfocusMarking)
GC>ON_EN_CHANGE(IDC_MARKING, &CSewingDlg::OnEnChangeMarking)
GC>END_MESSAGE_MAP()

GC>//-----------------------------------------------------------------------------
GC>// Dialog initialization
GC>BOOL CSewingDlg::OnInitDialog()
GC>{
GC>    CDialog::OnInitDialog();

GC>    m_StockOutCheck = true;
GC>    m_StockInCheck = false;
GC>    m_MarkingCheck = true;
GC>    m_StockOut = 10.50;
GC>    m_StockIn  = 10.50;
GC>    m_MarkingStep = 100;
GC>    m_SelectType = 0;
GC>    m_MaxSplitNum = 20;
GC>    m_MaxMarksNum = 5;

GC>    ((CButton*)GetDlgItem( IDC_PROCESS_CLOSED_ONLY ))->SetCheck( m_ProcessClosedOnly? 1 : 0 );
GC>    ((CButton*)GetDlgItem( IDC_CONTOUR_HAS_ANY_LINE_STYLES ))->SetCheck( m_ContourHasAnyLineStyles? 1 : 0 );
GC>    ((CButton*)GetDlgItem( IDC_PROCESS_ENCLOSED_CONTUORS ))->SetCheck( m_ProcessEnclosedContours? 1 : 0 );

GC>    UpdateData(FALSE);

GC>    return TRUE;  // return TRUE unless you set the focus to a control
GC>                  // EXCEPTION: OCX Property Pages should return FALSE
GC>}


GC>/*
GC>    //reference obj = Circle(100,100,100,1);
GC>/ *
GC>    RectangleParam par; // структура параметров прямоугольника
GC>    ::memset(&par, 0, sizeof(RectangleParam));
       RectangleParam par = {}; // вместо memset'а, на котором слишком легко опечататься

GC>    par.x = -73.55; // базовая точка 1
GC>    par.y = 39.95; // 
GC>    par.ang = 0.00; // угол вектора направления от 1-ой точки ко 2-ой
GC>    par.height = -66.68; // высота
GC>    par.width = 79.90; // ширина
GC>    par.pCorner = ::CreateArray(CORNER_ARR, 0); // Создание массива параметров углов
GC>    par.style = 1; // стиль линии

GC>    reference obj = ::ksRectangle(&par, 0); // создать прямоугольник 

// этот reference владеющий или нет? логично предположить, что владеющий, тогда почему без умных указателей?

GC>* /
GC>/ *
GC>    reference rseg1 = LineSeg(10,10,100,100,1);
GC>    reference rseg2 = LineSeg(100,100,200,20,1);

GC>    reference obj = NewGroup(0);
GC>    AddObjGroup(obj, rseg1);
GC>    AddObjGroup(obj, rseg2);
GC>    EndGroup();* /

GC>    Contour(1);

GC>    //определим группу выделения
GC>//    reference obj0 = SelectGroup(0,2,0,0,0,0); //ksViewGetObjectArea();
GC>    //CopyObj(obj0, 0,0,0,0,1,1);
GC>    //CopyGroupToDocument(obj0, ksGetCurrentDocument(0), ksGetCurrentDocument(0));

GC>//    reference group_iterator = CreateIterator(LINESEG_OBJ, 0);
GC>    reference group_iterator = CreateIterator(SELECT_GROUP_OBJ, 0);

GC>    reference cur_obj = MoveIterator(group_iterator, 'F');
GC>    while (cur_obj)
GC>    {
GC>        ksLineSegParamPtr lspLineParam = kompasAPI->GetParamStruct(ko_LineSegParam);
GC>//        long ksres = sewing_object->m_pKompasDoc5->ksGetObjParam(cur_obj, lspLineParam, ALLPARAM);
GC>        long ksres = m_pKompasDoc5->ksGetObjParam(cur_obj, lspLineParam, ALLPARAM);
GC>        if(ksres)
GC>        {
GC>            double x1 = lspLineParam->x1,
GC>                   x2 = lspLineParam->x2,
GC>                   y1 = lspLineParam->y1,
GC>                   y2 = lspLineParam->y2;

GC>//            LineSeg(x1,y1,x2,y2,1);
GC>/ * задание параметров копирования * /
GC>/ *
GC>RequestInfo info;
GC>memset(&info, 0, sizeof(info));
GC>info.title = "Title";
GC>info.prompt = " Новое положение базовой точки ";
GC>info.dynamic = 0;
GC>info.commands = "!test!test1";
GC>int j=CommandWindow(&info);

GC>double x=0,y=0,scale=1,ang=0;
GC>if ((Cursor (&info, &x, &y, 0)) &&
GC>(ReadDouble("Угол поворота", 0, 0, 360, &ang)) &&
GC>(ReadDouble("Масштаб", 1, 0, 999, &scale)))
GC>;* /
GC>/ *
GC>reference posLeader = ksCreateViewObject(POSLEADER_OBJ );
GC>if (posLeader){ 
GC>LightObj(posLeader, 1); 
GC>Message("Позиционная линия выноски");
GC>LightObj(posLeader, 0);

GC>    if (ksEditViewObject(posLeader)) { 
GC>    LightObj(posLeader, 1);
GC>    Message("Отредактированная позиционная линия выноски"); 
GC>    LightObj(posLeader, 0);
GC>    } 

GC>} 

GC>

Извини, дальше смотреть код было уже лень. Во-первых, его слишком много, во-вторых, он замусорен /**/ и плохой табуляцией, — как черновик, сойдёт, а на публику такое выносить не очень прилично.
Перекуём баги на фичи!
Re: Оцените качество кода на С++
От: -n1l-  
Дата: 18.09.14 10:28
Оценка:
Здравствуйте, GhostCoders, Вы писали:
Первый вопрос, у вас есть code conventions в вашей компании? Или все пишут как им хочется?

Почему в одном месте скобки стоят в другом нет? Это создает трудности в чтении.

GC>    else {
GC>        if ( absmax < minerror ) bx = true;
GC>            else bx = approx_equals<double>( x1/absmax, x2/absmax, correction );
GC>    }


Понятное дело что так можно, но...


Вот это что за апи метода?
void AdviseDoc( KompasObject* kompas,
                LPDISPATCH doc, long docType,
                bool fSelectMng = true,
                bool fObject = true,
                bool fStamp = true,
                bool fDocument = true,
                bool fSpecification = true,
                bool fSpcObject = true,
                long objType = 0 /*= -1*/);


Как это наверное здорово читается:

...
                false, true,true,false,false,...

Каким аргументам я задал значение а каким нет, гадайте. Да?


            do {    // pseudo-cycle to destruct tempRasters BEFORE doc-switching & CloseDocument()
                KompasIteratorHolder tempApprox(CreateIterator(ALL_OBJ, 0));    // GetViewReference(0)));
                if(!tempApprox) break;
                elem = MoveIterator(tempApprox, 'F');
            } while (0);


вот это что за цикл на одно действие?

Код сложно читать -> поддерживать, есть риск получить трудноуловимые ошибки.
В коде присутствуют слишком универсальные классы.
Код, может быть и сойдет, но явно говорить, что он хорош — это глупо.
Re: Оцените качество кода на С++
От: Andrew.W Worobow https://github.com/Worobow
Дата: 18.09.14 10:43
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.


Если чесно, то код ужас. Как по стилю, так и по подпоркам и затычкам.
Но так сейчас многие пишут. Какие-то странные имена Типа GjrThowAllocWPgo, ифы типа

if ( ! (a!=0) )e=4;
break;


Нет разбивки на файлы, мало коментариев. мало пустых строк — код НЕ оформлен. Всякая экзотика в виде запятых.
Но я бы попросил его оформить как надо. И все. Ну в смысле не называл это плохим кодом.
Не все кто уехал, предал Россию.
Re: Оцените качество кода на С++
От: bnk СССР http://unmanagedvisio.com/
Дата: 18.09.14 11:11
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.


Я думаю что с форматированием проблемы из-за смешения табов и пробелов.
Т.е. у тебя просто размер табуляции стоит не такой, как у коллеги, поэтому выглядит жутковато.

Код конечно не торт, но подобный ппц вполне ожидаем в продукте с N-летней историей.

В общем зря ты на него бочку катишь, "переписать все заново" — это скорее мечта,
а ему премию выдать надо за то что он в этом разбирается, или по-крайней мере молоко за вредность
Отредактировано 18.09.2014 11:12 bnk . Предыдущая версия .
Re[2]: Оцените качество кода на С++
От: GhostCoders Россия  
Дата: 18.09.14 11:20
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Код конечно не торт, но подобный ппц вполне ожидаем в продукте с N-летней историей.

Этот код был написан в течении последних двух месяцев практически с нуля. Так сказать, свежачок....
Третий Рим должен пасть!
Re[3]: Оцените качество кода на С++
От: GhostCoders Россия  
Дата: 18.09.14 11:27
Оценка:
Здравствуйте, niXman, Вы писали:

X>и да, функции размером в двести строк, тоже доставляют %)

Тут есть функция CSewingDlg::PseudoProcessAcceptedData(), которая начинается на 2029 строке и заканчивается на строке номер 3433
Третий Рим должен пасть!
Re[3]: Оцените качество кода на С++
От: smeeld  
Дата: 18.09.14 11:30
Оценка: 3 (1)
Здравствуйте, niXman, Вы писали:

X>и да, функции размером в двести строк, тоже доставляют


Жалкие двести строк и кому-то не нравится?
Видели бы вы такие функции
Re[4]: Оцените качество кода на С++
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.09.14 11:35
Оценка: +1
Здравствуйте, smeeld, Вы писали:

S>Видели бы вы такие функции

эта функция лучше, потому что в ней комментариев с избытком.
но да, можно было и ее разделить на *надцать поменьше — все бы только выиграли
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: Оцените качество кода на С++
От: smeeld  
Дата: 18.09.14 11:35
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Здравствуйте, bnk, Вы писали:


bnk>>Код конечно не торт, но подобный ппц вполне ожидаем в продукте с N-летней историей.

GC>:) Этот код был написан в течении последних двух месяцев практически с нуля. Так сказать, свежачок....

Это всё писалось целых два месяца? А как же план для программиста в 500 строк в день?
Re[2]: Оцените качество кода на С++
От: Кодт Россия  
Дата: 18.09.14 11:36
Оценка:
Здравствуйте, -n1l-, Вы писали:

N>
N>            do {    // pseudo-cycle to destruct tempRasters BEFORE doc-switching & CloseDocument()
N>                KompasIteratorHolder tempApprox(CreateIterator(ALL_OBJ, 0));    // GetViewReference(0)));
N>                if(!tempApprox) break;
N>                elem = MoveIterator(tempApprox, 'F');
N>            } while (0);
N>

N>вот это что за цикл на одно действие?

Это прикольнейшая идиома. Это не цикл, а goto end. В роли goto используется break.

N>Код сложно читать -> поддерживать, есть риск получить трудноуловимые ошибки.


(в смысле — всё плохо!)
Перекуём баги на фичи!
Re[3]: Оцените качество кода на С++
От: Кодт Россия  
Дата: 18.09.14 11:38
Оценка: +1 :))
Здравствуйте, GhostCoders, Вы писали:

bnk>>Код конечно не торт, но подобный ппц вполне ожидаем в продукте с N-летней историей.

GC> Этот код был написан в течении последних двух месяцев практически с нуля. Так сказать, свежачок....

"Просто я её сочинил как древнюю легенду"
Перекуём баги на фичи!
Re[4]: Оцените качество кода на С++
От: GhostCoders Россия  
Дата: 18.09.14 11:47
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Жалкие двести строк и кому-то не нравится?

S>Видели бы вы такие функции
Мой сотрудник на самом деле не намного отстал.
Тут есть функция CSewingDlg::PseudoProcessAcceptedData(), которая начинается на 2029 строке и заканчивается на строке номер 3433
Третий Рим должен пасть!
Re: Оцените качество кода на С++
От: TimurSPB Интернет  
Дата: 18.09.14 11:53
Оценка:
Сурово:
for (ULONG i0 = 0, j0 = 0; j0 < sabNewArray.cElements; i0 += 6 * step, j0 += 6)      // B,L,R -> L,B,R !
            {
                if (i0 >= 6 * AllPointsCount) i0 = 6 * (AllPointsCount - 1);
                LONG i = i0, j = j0 + 2;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 2, j = j0;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i = i0 + 4, j = j0 + 4;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
                i++, j++;
                ::SafeArrayGetElement( pSrc, &i, &arrdata);
                ::SafeArrayPutElement( pSafe, &j, &arrdata);
            }

Не хотелось бы такое поддерживать в будущем. Код без автора я бы править не стал.
Ещё смущает обилие конструкций "Points.push_back(.." в вектор на стеке. Производительность кода всех устраивает?
Make flame.politics Great Again!
Re: Оцените качество кода на С++
От: vladimir_i СССР  
Дата: 18.09.14 12:20
Оценка: -6
Здравствуйте, GhostCoders, Вы писали:

GC>Данный код был написан моим сотрудником. Мне этот код не нравится, но он мне отвечает что я субъективен и его код неплох.

GC>...

Довольно странно, что вы вот так просто выставляете собственность компании на всеобщее обозрение. Если конечно это не ваша компания, но все равно странно как-то.
Может это даже ваш код и, вместо того чтобы в этом признаться и показаться не очень профессиональным в глазах коллег, вы придумали сотрудника.


По существу: текст не помешает пропустить сквозь авто-формат.
Еще можно провести рефакторинг: сделать наименование однообразным, например, окончательно определиться с "m_" в именах членов класса:
 int equi_curves_count;
 bool m_swapped;


А вообще, качество кода определяется наличием ошибок и соответствием ТЗ. Если программа делает то, что требуется, не течет и не тормозит, то нечего придираться.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.