struct sCAD
{
 int    nLineGroup = 0; // 0-3

 pen
 // A
 pA,
 pVisibleEdge,            // Sichtbare Kanten
 pVisibleContour,        // Sichtbarer Umriss
 pUsableWindingLength,    // Nutzbare Gewindelänge
 pSystemLine,            // Systemlinie (Stahlbau)
 pDiagramCurve,            // Kurve in Diagrammen
 pSurfaceStructure,        // Oberflächenstrukturen
 // B
 pB,
 pLightEdge,                // Lichtkante
 pMeasureLine,            // Maßlinie
 pMeasureHelpLine,        // Maßhilfslinie
 pMeasureLineBound,        // Maßlinienbegrenzung
 pReferenceLine,            // Hinweislinie
 pHatch,                    // Schraffur
 pWindingGround,            // Gewindegrund
 pDiagonalCross,            // Diagonalkreuz
 pBendLine,                // Biegelinie
 pProjectionLine,        // Projektionslinie
 pGrid,                    // Rasterlinien
 // C
 pC,
 pFreehand,                // Begrenzung abgebrochener oder unterbrochener
 // Schnitte, wenn die Begrenzung
 // keine Mittellinie ist
 // E
 pE,
 pSurfaceTreatmentAllowed,    // Bereich zulässiger Oberflächenbehandlung
 // F
 pF,
 pInvisibleEdge,            // unsichtbare Kante
 pInvisibleContour,        // unsichtbarer Umriss
 // G
 pG,
 pMiddleLine,            // Mittellinie
 pSymmetryLine,            // Symmetrielinie
 pPartialCircle,            // Teilkreis
 pCircularHole,            // Lochkreis
 pDivisionPlane,            // Teilungsebene
 pTransferLine,            // Trajektorien (Übertragungslinien)
 // J
 pJ,
 pCuttingPlane,                // Schnittebene
 pSurfaceTreatmentRequested,    // Bereich geforderter Behandlungen
 // K
 pK,
 pContourBeforeDeformation,    // Umrisse vor Verformung
 pAdjacentPartContour,        // Umrisse angrenzender Teile
 pEndShapeRawMaterial,        // Fertigformen in Rohteilen
 pContourEligibleType,        // Umrisse wahlweiser Ausführungen
 pPartInFrontOfCuttingPlane;    // Teile vor der Schnittebene



 static sCAD Create(int nLineGroup = 1)
 {
   sCAD    cad = new sCAD;
   if ( nLineGroup < 0 )
     nLineGroup = 0;
   if ( nLineGroup > 3 )
     nLineGroup = 3;
   cad.nLineGroup = nLineGroup;

   restricted real[]    dblFullWidth = {0.35mm, 0.5mm, 0.7mm, 1.0mm};
   restricted real[]    dblHalfWidth = {0.18mm, 0.25mm, 0.35mm, 0.5mm};

   pen    pFullWidth = linewidth(dblFullWidth[nLineGroup]);
   pen    pHalfWidth = linewidth(dblHalfWidth[nLineGroup]);

   // Linienarten:
   // A
   cad.pA =
     cad.pVisibleEdge =
     cad.pVisibleContour =
     cad.pUsableWindingLength =
     cad.pSystemLine =
     cad.pDiagramCurve =
     cad.pSurfaceStructure =
     pFullWidth + solid;
   // B
   cad.pB =
     cad.pLightEdge =
     cad.pMeasureLine =
     cad.pMeasureHelpLine =
     cad.pMeasureLineBound =
     cad.pReferenceLine =
     cad.pHatch =
     cad.pWindingGround =
     cad.pDiagonalCross =
     cad.pBendLine =
     cad.pProjectionLine =
     cad.pGrid =
     pHalfWidth + solid;
   // C
   cad.pC =
     cad.pFreehand =
     pHalfWidth + solid;
   // D
   // Missing, as I have no idea how to implement this...
   // E
   cad.pE =
     cad.pSurfaceTreatmentAllowed =
     pFullWidth + linetype(new real[] {10,2.5});
   // F
   cad.pF =
     cad.pInvisibleEdge =
     cad.pInvisibleContour =
     pHalfWidth + linetype(new real[] {20,5});
   // G
   cad.pG =
     cad.pMiddleLine =
     cad.pSymmetryLine =
     cad.pPartialCircle =
     cad.pCircularHole =
     cad.pDivisionPlane =
     cad.pTransferLine =
     pHalfWidth + linetype(new real[] {40,5,5,5});
   // H
   // see J
   // I
   // This letter is not used in DIN 15
   // J
   cad.pJ =
     cad.pCuttingPlane =
     cad.pSurfaceTreatmentRequested =
     pFullWidth + linetype(new real[] {20,2.5,2.5,2.5});
   // K
   cad.pK =
     cad.pContourBeforeDeformation =
     cad.pAdjacentPartContour =
     cad.pEndShapeRawMaterial =
     cad.pContourEligibleType =
     cad.pPartInFrontOfCuttingPlane =
     pHalfWidth + linetype(new real[] {40,5,5,5,5,5});

   return cad;
 } // end of Create



 real    GetMeasurementBoundSize(bool bSmallBound = false)
 {
   if ( bSmallBound )
     return 1.5 * linewidth(pVisibleEdge) / 2;
   else
     return 5 * linewidth(pVisibleEdge);
 }



 path    GetMeasurementBound(bool bSmallBound = false)
 {
   if ( bSmallBound )
     return scale(GetMeasurementBoundSize(bSmallBound = bSmallBound)) *
       unitcircle;
   else
     return (0,0) --
       (-cos(radians(7.5)), -sin(radians(7.5))) *
       GetMeasurementBoundSize(bSmallBound = bSmallBound) --
       (-cos(radians(7.5)), sin(radians(7.5))) *
       GetMeasurementBoundSize(bSmallBound = bSmallBound) --
       cycle;
 }



 void    MeasureLine(picture pic = currentpicture,
                     Label L,
                     pair pFrom,
                     pair pTo,
                     real dblLeft = 0,
                     real dblRight = 0,
                     real dblRelPosition = 0.5,
                     bool bSmallBound = false)
 {
   if ( dblLeft < 0 )
     dblLeft = 0;
   if ( dblRight < 0 )
     dblRight = 0;
   if ( (dblLeft > 0) && (dblRight == 0) )
     dblRight = dblLeft;
   if ( (dblLeft == 0) && (dblRight > 0) )
     dblLeft = dblRight;
   pair    pDiff = pTo - pFrom;
   real    dblLength = length(pDiff);
   pair    pBegin = pFrom - dblLeft * unit(pDiff);
   pair    pEnd = pTo + dblRight * unit(pDiff);
   if ( bSmallBound )
     {
       draw(
            pic = pic,
            g = pBegin--pEnd,
            p = pMeasureLine);
     }
   else
     {
       real dblBoundSize = GetMeasurementBoundSize(bSmallBound = bSmallBound);
       if ( dblLeft == 0 )
         draw(
              pic = pic,
              g = (pFrom + dblBoundSize/2 * unit(pDiff))
              -- (pTo - dblBoundSize/2 * unit(pDiff)),
              p = pMeasureLine);
       else
         draw(
              pic = pic,
              g = pBegin -- (pFrom - dblBoundSize/2 * unit(pDiff))
              ^^ pFrom -- pTo
              ^^ (pTo + dblBoundSize/2 * unit(pDiff)) -- pEnd,
              p = pMeasureLine);
     }
   path    gArrow = GetMeasurementBound(bSmallBound = bSmallBound);
   picture    picL;
   label(picL, L);
   pair    pLabelSize = 1.2 * (max(picL) - min(picL));
   if ( dblLeft == 0 )
     {
       fill(
            pic = pic,
            g = shift(pFrom) * rotate(degrees(-pDiff)) * gArrow,
            p = pVisibleEdge);
       fill(
            pic = pic,
            g = shift(pTo) * rotate(degrees(pDiff)) * gArrow,
            p = pVisibleEdge);
       if ( dblRelPosition < 0 )
         dblRelPosition = 0;
       if ( dblRelPosition > 1 )
         dblRelPosition = 1;
       label(
             pic = pic,
             L = rotate(degrees(pDiff)) * L,
             position =
             pFrom
             + dblRelPosition * pDiff
             + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
     }
   else
     {
       fill(
            pic = pic,
            g = shift(pFrom) * rotate(degrees(pDiff)) * gArrow,
            p = pVisibleEdge);
       fill(
            pic = pic,
            g = shift(pTo) * rotate(degrees(-pDiff)) * gArrow,
            p = pVisibleEdge);
       if ( (dblRelPosition >= 0) && (dblRelPosition <= 1) )
         label(
               pic = pic,
               L = rotate(degrees(pDiff)) * L,
               position =
               pFrom
               + dblRelPosition * pDiff
               + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
       else
         {
           // draw label outside
           if ( dblRelPosition < 0 )
             label(
                   pic = pic,
                   L = rotate(degrees(pDiff)) * L,
                   position =
                   pBegin
                   + pLabelSize.x / 2 * unit(pDiff)
                   + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
           else
             // dblRelPosition > 1
             label(
                   pic = pic,
                   L = rotate(degrees(pDiff)) * L,
                   position =
                   pEnd
                   - pLabelSize.x / 2 * unit(pDiff)
                   + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
         }
     }
 } // end of MeasureLine



 void    MeasureParallel(picture pic = currentpicture,
                         Label L,
                         pair pFrom,
                         pair pTo,
                         real dblDistance,
                         // Variables from MeasureLine
                         real dblLeft = 0,
                         real dblRight = 0,
                         real dblRelPosition = 0.5,
                         bool bSmallBound = false)
 {
   pair    pDiff = pTo - pFrom;
   pair    pPerpendicularDiff = unit(rotate(90) * pDiff);
   real    dblDistancePlus;
   if ( dblDistance >= 0 )
     dblDistancePlus = dblDistance + 1mm;
   else
     dblDistancePlus = dblDistance - 1mm;
   draw(
        pic = pic,
        g = pFrom--(pFrom + dblDistancePlus*pPerpendicularDiff),
        p = pMeasureHelpLine
        );
   draw(
        pic = pic,
        g = pTo--(pTo + dblDistancePlus*pPerpendicularDiff),
        p = pMeasureHelpLine
        );
   MeasureLine(
               pic = pic,
               L = L,
               pFrom = pFrom + dblDistance * pPerpendicularDiff,
               pTo = pTo + dblDistance * pPerpendicularDiff,
               dblLeft = dblLeft,
               dblRight = dblRight,
               dblRelPosition = dblRelPosition,
               bSmallBound = bSmallBound);
 } // end of MeasureParallel



 path MakeFreehand(pair pFrom, pair pTo,
                   real dblRelDivisionLength = 12.5,
                   real dblRelDistortion = 2.5,
                   bool bIncludeTo = true)
 {
   pair    pDiff = pTo - pFrom;
   pair    pPerpendicular = dblRelDistortion * linewidth(pFreehand) *
     unit(rotate(90) * pDiff);

   int nNumOfSubDivisions=ceil(length(pDiff) /
                               (dblRelDivisionLength * linewidth(pFreehand)));

   restricted real[]    dblDistortion = {1, -.5, .75, -.25, .25, -1, .5, -.75,
                                         .25, -.25};
   int                    nDistortion = 0;

   guide    g;
   g = pFrom;
   for ( int i = 1 ; i < nNumOfSubDivisions ; ++i )
     {
       g = g ..
         (pFrom
          + pDiff * i / (real)nNumOfSubDivisions
          + pPerpendicular * dblDistortion[nDistortion]);
       nDistortion += 1;
       if ( nDistortion > 9 )
         nDistortion = 0;
     }

   if ( bIncludeTo )
     g = g .. pTo;

   return g;
 } // end of MakeFreehand



} // end of CAD