<?xml version="1.0" encoding="utf-8"?>
<!-- ArchiFrame element settings etc -->
<archiframe>
  <!-- Settings for elements -->
  <elem>
    <settings>
      <!-- These libparts will be tracked for changes in addition to AF internal ones. Add any libpart type here used as custom element stamp, cut list or similar. Data is used for handling copy/paste between ArchiCADs -->
      <trackelemsettings>
        <libpart guid="FD6C137D-C647-42FD-A904-181281909443"></libpart>
        <libpart guid="9056D768-6A80-423F-B548-30D0A09D857F"></libpart>
        <libpart guid="9FD03D30-6A12-4B0F-AB3A-01410A529E38"></libpart>
      </trackelemsettings>

      <!-- Common settings -->
      <plank>
        <misc minlen="0.01" idstr="%s-01"></misc>
      </plank>

      <!-- Common settings for projections/element drawings -->
      <projections maxwidth="80">
      </projections>

      <!-- Settings for new element object, also run when element gets ungrouped -->
      <newelem>
        <elemparam name="pen">1</elemparam>
        <objparam name="iShowElemType">1</objparam>
        <objparam name="iShowID2D">1</objparam>
        <objparam name="iShowID3D">1</objparam>
        <objparam name="iElemTypeIdShow"></objparam>
        <objparam name="iID2Yoff">0</objparam>
        <objparam name="iPenID">0</objparam>
      </newelem>

      <!-- Settings for new plank for element -->
      <newelemplank>
        <elemparam name="pen">1</elemparam>
        <objparam name="iShowID">0</objparam>
        <objparam name="iShowID3D">0</objparam>
        <objparam name="iPenErr">1</objparam>
        <objparam name="iPenLocked">8</objparam>
        <objparam name="iUsageId">ELEM</objparam>
        <objparam name="iColLines">3</objparam>
        <objparam name="iSectX">1</objparam>
      </newelemplank>

      <!-- For side projection plank -->
      <newelemprojside>
        <elemparam name="pen">1</elemparam>
        <objparam name="iShowID">1</objparam>
        <objparam name="iShowLen">1</objparam>
        <objparam name="iIDPlace">-1</objparam>
        <objparam name="iXoffID">-0.1</objparam>
        <objparam name="iFontSizeBase">7</objparam>
        <objparam name="iPenErr">1</objparam>
        <objparam name="iPenLocked">8</objparam>
        <objparam name="iShowIDSep">-</objparam>
      </newelemprojside>

      <!-- For top projection plank -->
      <newelemprojtop>
        <elemparam name="pen">1</elemparam>
        <objparam name="iShowID">0</objparam>
        <objparam name="iFontSizeBase">7</objparam>
        <objparam name="iPenErr">1</objparam>
        <objparam name="iPenLocked">8</objparam>
        <objparam name="iShowIDSep">-</objparam>
      </newelemprojtop>

      <!-- Settings for free weight calculation marker, calcempty: 1=calculate empty openings as windows/doors -->
      <weightmarker libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" text="(weight) KG" units="kg" calcempty="0">
        <settings>
          <objparam name="iFill">*25*</objparam>
          <objparam name="A">0.250</objparam>
          <objparam name="B">0.325</objparam>
          <objparam name="ZZYZX">0.325</objparam>
          <objparam name="iShow3D">1</objparam>
        </settings>
      </weightmarker>

      <!-- MULTILAYER BEG -->

      <!-- Settings for new board object -->
      <newelemboard>
        <elemparam name="pen">1</elemparam>
        <layer>AF Board</layer>
        <objparam name="iPenLocked">8</objparam>
        <objparam name="iFillFrom3D">1</objparam>
      </newelemboard>

      <!-- For side projection board -->
      <newelemboardprojside>
        <elemparam name="pen">1</elemparam>
        <objparam name="iFill">25 %</objparam>
        <objparam name="iShowID2D">1</objparam>
        <objparam name="iShowIDSep">#</objparam>
        <objparam name="iFillFrom3D">1</objparam>
      </newelemboardprojside>

      <!-- For top projection board -->
      <newelemboardprojtop>
        <elemparam name="pen">1</elemparam>
        <objparam name="iFill">25 %</objparam>
        <objparam name="iShowIDSep">#</objparam>
        <objparam name="iFillFrom3D">0</objparam>
      </newelemboardprojtop>


      <!-- Settings for new board object modelling insulation -->
      <neweleminsu>
        <elemparam name="pen">1</elemparam>
        <layer>AF Insulation</layer>
        <objparam name="iFill">25 %</objparam>
        <objparam name="iTypeCode">200</objparam>
        <objparam name="iPenLocked">8</objparam>
        <objparam name="iFillFrom3D">1</objparam>
        <objparam name="iShowID2D">0</objparam>
        <objparam name="iShowID3D">0</objparam>
        <objparam name="iShowIDSep">#</objparam>
      </neweleminsu>

      <!-- For side projection board -->
      <neweleminsuprojside>
        <objparam name="iFill">25 %</objparam>
        <objparam name="iShowIDSep">#</objparam>
      </neweleminsuprojside>

      <!-- For top projection board -->
      <neweleminsuprojtop>
        <objparam name="iFill">25 %</objparam>
      </neweleminsuprojtop>


      <!-- When panel board is exploded into planks -->
      <boardexploded>
        <objparam name="iPanelBlock">4</objparam>
        <objparam name="iFill">0</objparam>
        <objparam name="iSawLines">15</objparam>
        <objparam name="iWire3D">1</objparam>
      </boardexploded>

      <!-- For projections: To use different pen for boards next to each other. First one is the default pen. If pen is left empty, best match is searched based on rgb. -->
      <boardpens>
        <pen r="0.55" g="0.55" b="0.55" rpen="0.45" gpen="0.45" bpen="0.45"></pen>
        <pen r="0.9" g="0.9" b="0.9" rpen="0.9" gpen="0.9" bpen="0.9"></pen>
        <pen r="0.8" g="0.8" b="0.2" rpen="0.7" gpen="0.7" bpen="0.15"></pen>
        <pen r="0.2" g="0.8" b="0.5" rpen="0.15" gpen="0.7" bpen="0.43"></pen>
      </boardpens>

      <!-- MULTILAYER END -->

      <!-- For element projection tool/section, uses object ArchiFrameDetMarker from ArchiFrame library -->
      <sectionmarker>
        <objparam name="iTypeID">8</objparam>
        <elemparam name="pen">1</elemparam>
        <elemparam name="linetype">*dash*</elemparam>
        <objparam name="iLinetype" type="attr_linetype">*dash*</objparam>
        <objparam name="iFontSize">15</objparam>
      </sectionmarker>


      <!-- Wup-cnc: Saw cut marker object defaults -->
      <sawcut routermaxlen="0.3">
        <elemparam name="pen">1</elemparam>
        <layer></layer>
      </sawcut>

      <!-- Dimension line defaults -->
      <dimlinesettings>
        <elemparam name="dimensiontype">linear</elemparam>
        <elemparam name="pen">1</elemparam>
        <elemparam name="fontname">Arial</elemparam>
        <elemparam name="fontsize">1.5</elemparam>
        <elemparam name="fontstyle"></elemparam>
        <elemparam name="markersize">2</elemparam>
        <elemparam name="markerpen">1</elemparam>
        <elemparam name="witness">1</elemparam>
      </dimlinesettings>

      <!-- Predefined dimline settings -->
      <dimsettings>
        <!-- Settings for element elevation - to be used in many element definitions -->
        <dimlines id="wall_elevation">

          <!-- Boards -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="*boarding*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="*boarding*,*core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Panel offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" minpoints="3" exclude="*" includeelem="*core*,*finish*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="CLADDING" content_fin="VERHOILU" content_nor="PANEL" textid="projid*20+7" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <dimline side="bottom" margin="0.75" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*core*" onlyelem="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for vertical posts -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addminmax="1" addminplankmindistfrom="0.050" addmaxplankmindistfrom="0.050" addy="1" anchormid="1" exclude="*" include="*core*">
            <text content="STUD MID" content_fin="TOLPPA KESKI" content_nor="STENDERE SENTER" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*,*stud*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size vert, all omitted settings are 0 -->
          <dimline side="right" margin="1" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>


          <!-- Dimension line for openings vertical -->
          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          
          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+8" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          
          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*finish*" onlyelem="1">
            <text content="CLADDING" content_fin="VERHOILU" content_nor="PANEL" textid="projid*20+9" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for gable wall top tilted planks -->
          <dimspec type="toptilted" margin="0.3" addminmax="2" anchorfirst="1" anchormid="0" anchorlast="0" ltor="0">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
          </dimspec>

          <!-- Cross dimension for the element -->
          <dimspec type="cross" anchor="lb">
            <dimlinesettings>
            </dimlinesettings>
          </dimspec>
        </dimlines>

        <!-- Settings for element elevation - to be used in many element definitions -->
        <dimlines id="wall_top" script="dim_scripts" scriptcreate="TopDimLines">
          <!-- Element thickness -->
          <dimline side="right" margin="1.0" elemvecz="1" addminmax="1">
            <dimlinesettings>
              <elemparam name="fontsize">1.5</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for vertical posts cumulative -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" exclude="*" include="*core*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE VENSTRE" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <dimlines id="wall_top_more_space" script="dim_scripts" scriptcreate="TopDimLines">
          <!-- Element thickness -->
          <dimline side="right" margin="1.0" elemvecz="1" addminmax="1">
            <dimlinesettings>
              <elemparam name="fontsize">1.5</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for vertical posts cumulative -->
          <dimline side="bottom" margin="0.75" elemvecx="1" addy="1" anchorfirst="1" exclude="*" include="*core*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE VENSTRE" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <!-- Settings for element elevation - to be used in many element definitions -->
        <dimlines id="roof_section">
          <!-- Element thickness -->
          <dimline side="right" margin="1.0" elemvecz="1" addminmax="1">
            <dimlinesettings>
              <elemparam name="fontsize">1.5</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for vertical posts cumulative -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" exclude="intstud*,extstud*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="RAFTER LEFT" content_fin="VASA VASEN" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>
		
		
        <!-- 2018_03 BEG -->
        <!-- ### 2018_03 JUST FRAMING -->
        <dimlines id="an_framing" script="dim_scripts" scriptcreate="AddCoreModules">
          <!-- Tolpat väli keskellä -->
          <dimline side="bottom" margin="1" elemvecx="1" addy="1" anchormid="1" exclude="*" include="*core*">
            <text content="STUD MID" content_fin="TOLPPA KESKI" content_nor="STENDERE SENTER" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*,*stud*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <dimline side="bottom" margin="0.25" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*core*" onlyelem="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Main dimension line showing just element size vert, all omitted settings are 0 -->
          <dimline side="right" margin="1" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for gable wall top tilted planks -->
          <dimspec type="toptilted" margin="0.3" addminmax="2" anchorfirst="0" anchormid="0" anchorlast="1" ltor="0">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
            </dimlinesettings>
          </dimspec>

          <!-- Cross dimension for the element -->
          <dimspec type="cross" anchor="lb">
            <dimlinesettings>
            </dimlinesettings>
          </dimspec>

          <!-- Openings -->
          <dimspec type="opening" include="core" vertdim="1" crossdim="0" vertanchorbot="top" vertopeningbot="1" vertopeningtop="-1">
            <dimlinesettings_vert>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings_vert>
            <dimlinesettings_cross>
            </dimlinesettings_cross>
          </dimspec>
        </dimlines>

        <!-- ### 2018_03 JUST FRAMING AND THEN INSULATION DIM LINE -->
        <dimlines id="an_frame_board_insu">
          <!-- Tolpat väli keskellä -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" exclude="*" include="*core*">
            <text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE V" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Tolpat juokseva -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" addminmax="2" exclude="*" include="*core*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE V" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*,*stud*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <dimline side="bottom" margin="0.25" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*core*" onlyelem="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Main dimension line showing just element size vert, all omitted settings are 0 -->
          <dimline side="right" margin="1" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+7" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">2</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings vertical -->
          <!--dimline side="right" margin="0.25" elemvecy="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline-->

          <!-- Dimension line for gable wall top tilted planks -->
          <dimspec type="toptilted" margin="0.3" addminmax="2" anchorfirst="1" anchormid="0" anchorlast="0" ltor="0">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
            </dimlinesettings>
          </dimspec>

          <!-- Cross dimension for the element -->
          <dimspec type="cross" anchor="lb">
            <dimlinesettings>
            </dimlinesettings>
          </dimspec>

          <!-- Openings -->
          <dimspec type="opening" include="core" vertdim="1" crossdim="0" vertanchorbot="top" vertopeningbot="1" vertopeningtop="-1">
            <dimlinesettings_vert>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings_vert>
            <dimlinesettings_cross>
            </dimlinesettings_cross>
          </dimspec>

          <dimline side="top" margin="0.25" elemvecx="1" addy="1" anchorfirst="1" anchorlast="1" exclude="*" include="*core*">
            <text content="INSULATION" content_fin="VILLA" content_nor="ISOLASJON" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="boarding*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="boarding*,core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <!-- ### 2018_03 INTERIOR STUDDING -->
        <dimlines id="an_horframing">
          <!-- Vaakakoolaus alhaalta -->
          <dimline side="right" margin="0.5" elemvecy="1" addx="1" anchorfirst="1" minpoints="3" exclude="*" include="intstud*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*intstud*" onlyelem="1">
          </dimline>
        </dimlines>


        <!-- ### 2018_03 FRAME + BOARD FROM OUTSIDE -->
        <dimlines id="an_frame_board_ext">
          <!-- Levyt -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="boarding_ext*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="boarding_ext*,core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Tolpat väli keskellä -->
          <dimline side="bottom" margin="1" elemvecx="1" addy="1" anchormid="1" exclude="*" include="*core*">
            <text content="STUD MID" content_fin="TOLPPA KESKI" content_nor="STENDERE SENTER" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Tolpat juokseva -->
          <dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" addminmax="2" exclude="*" include="*core*">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE V" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*,*stud*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <dimline side="bottom" margin="0.25" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*core*" onlyelem="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Main dimension line showing just element size vert, all omitted settings are 0 -->
          <dimline side="right" margin="1" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for gable wall top tilted planks -->
          <dimspec type="toptilted" margin="0.3" addminmax="2" anchorfirst="1" anchormid="0" anchorlast="0" ltor="0">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
            </dimlinesettings>
          </dimspec>

          <dimspec type="opening" include="core" vertdim="1" crossdim="0" vertanchorbot="top" vertopeningbot="1" vertopeningtop="-1">
            <dimlinesettings_vert>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings_vert>
            <dimlinesettings_cross>
            </dimlinesettings_cross>
          </dimspec>
          
          <!-- Cross dimension for the element -->
          <dimspec type="cross" anchor="lb">
            <dimlinesettings>
            </dimlinesettings>
          </dimspec>
        </dimlines>

        <!-- ### 2018_03 RUNKO (ilmarako) + VERHOILU ULKOAPÄIN -->
        <dimlines id="an_frame_cladding">
          <!-- Tolpat väli keskellä -->
          <dimline side="bottom" margin="1" elemvecx="1" addy="1" anchormid="1" exclude="*" include="*core*">
            <text content="STUD MID" content_fin="TOLPPA KESKI" content_nor="STENDERE SENTER" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="*core*,*stud*" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <dimline side="bottom" margin="0.25" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*core*" onlyelem="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" minpoints="3" exclude="*" includeelem="*core*,*finish*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="CLADDING" content_fin="VERHOILU" content_nor="PANEL" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size vert, all omitted settings are 0 -->
          <dimline side="right" margin="1" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*finish*" onlyelem="1">
            <text content="CLADDING" content_fin="VERHOILU" content_nor="PANEL" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Dimension line for gable wall top tilted planks -->
          <dimspec type="toptilted" margin="0.3" addminmax="2" anchorfirst="1" anchormid="0" anchorlast="0" ltor="0">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
            </dimlinesettings>
          </dimspec>

          <dimspec type="opening" include="core" vertdim="1" crossdim="0" vertanchorbot="top" vertopeningbot="1" vertopeningtop="-1">
            <dimlinesettings_vert>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings_vert>
            <dimlinesettings_cross>
            </dimlinesettings_cross>
          </dimspec>
          
          <!-- Cross dimension for the element -->
          <dimspec type="cross" anchor="lb">
            <dimlinesettings>
            </dimlinesettings>
          </dimspec>
        </dimlines>


        <!-- # BOARD + STUDDING -->

        <dimlines id="an_vertstud_board" script="dim_scripts">
          <!-- Boards -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="boarding*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="boarding*,core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+2" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+3" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Studding -->
          <dimline side="bottom" margin="0.75" elemvecx="1" addy="1" anchorfirst="1" exclude="*" include="core,intstud,intstud2" scriptfind="FindVertBattensPlusLeftFrame">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="STUD LEFT" textid="projid*20+4" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

        </dimlines>

        <!-- ### LEVY -->
        <dimlines id="kw_levy">
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="*boarding*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="*boarding*,!*core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <!--dimline side="bottom" margin="0.75" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*boarding*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline-->

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="!*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+8" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <!-- ### 2xBOARD -->
        <dimlines id="an_board2">
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="*boarding*2">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD1" content_fin="LEVY1" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="*boarding*3">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD2" content_fin="LEVY2" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="*boarding*,*core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Main dimension line showing just element size hor -->
          <!--dimline side="bottom" margin="0.75" elemvecx="1" elemvecy="0" elemvecz="0" addminmax="1" addx="0" addy="0" addz="0" exclude="*" includeelem="*boarding*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline-->

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+8" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">2</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <!-- ### INSULATION -->
        <dimlines id="an_insu">
          <dimline side="top" margin="0.25" elemvecx="1" addy="1" anchorfirst="1" anchorlast="1" exclude="*" include="*core*">
            <text content="INSULATION" content_fin="VILLA" content_nor="ISOLASJON" textid="projid*20+1" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">2</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>

        <!-- 2018_03 END -->

        <dimlines id="dim_wallsect_nowin_horint_10" script="dim_wallsect" scriptcreate="SectDimLines">
          <!-- Base dim lines could be added before script based -->
        </dimlines>

        <dimlines id="dim_wallsect_nowin_horint_10_cum" script="dim_wallsect" scriptcreate="SectDimLinesCum">
          <!-- Base dim lines could be added before script based -->
        </dimlines>

        <dimlines id="boards_and_studh" script="dim_scripts">
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" exclude="*" include="*boarding*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+5" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <!-- Boards offset -->
          <dimline side="top" margin="0.25" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchormid="0" anchorlast="1" minpoints="3" exclude="*" includeelem="*boarding*,!*core*" onlyelem="1">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+6" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="2" addx="1" anchorfirst="1" minpoints="3" anchormid="0" anchorlast="0" addminplankmindistfrom="0.020" exclude="*" include="!core,*stud*" scriptfind="FindHorBattensPlusBottomFrame">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
              <elemparam name="markertype">5</elemparam>
            </dimlinesettings>
            <text content="BOT" content_fin="ALA" content_swe="LÄKT BOT" textid="projid*20+4" anchor="6" marg="0.2">
              <layer></layer>
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>

          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" minpoints="3" exclude="*" includeelem="!*core*,*boarding*" onlyelem="1">
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" textid="projid*20+8" anchor="6" marg="0.2">
              <elemparam name="pen">1</elemparam>
              <elemparam name="fontname">arial</elemparam>
              <elemparam name="fontsize">1.5</elemparam>
              <elemparam name="fontstyle"></elemparam>
            </text>
          </dimline>
        </dimlines>
      </dimsettings>

      <!-- For element creation, markings in the element projections -->
      <elemmarkings>
        <elemmarking id="mark_opening">
          <opening text="#id#\n#width#\nx\n#height#">
            <elemparam name="pen">8</elemparam>
            <elemparam name="fontname">Arial</elemparam>
            <elemparam name="fontsize">1.5</elemparam>
            <elemparam name="fontstyle"></elemparam>
            <elemparam name="just">center</elemparam>
            <framelines create="0">
              <elemparam name="pen">1</elemparam>
              <elemparam name="linetype">1</elemparam>
            </framelines>
          </opening>
        </elemmarking>
      </elemmarkings>

      <!-- Predefined settings for various places -->
      <presettings>

        <!-- 2018_03 BEG -->
        <cutlist_table_an11 tab1="0.5" tab2="0.8" tab3="1.2" tab4="1.5" tab5="1.8" boards="0" sortby="len" plankid="-" boardid="#" libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an11">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
        </cutlist_table_an11>

        <cutlist_table_an_single tab1="0.5" tab2="0.8" tab3="1.2" tab4="1.5" tab5="1.8" boards="0" sortby="len" plankid="-" boardid="#" libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an_single">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
        </cutlist_table_an_single>

        <cutlist_table_an_single_boards tab1="0.5" tab2="0.8" tab3="1.2" tab4="1.5" tab5="1.8" boards="0" sortby="len" plankid="-" boardid="#" libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an_single_boards">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
        </cutlist_table_an_single_boards>

        <cutlist_script_an11 ref="elem/settings/presettings/cutlist_script_an">
          <![CDATA[
          gType="1.1"
]]>
        </cutlist_script_an11>

        <cutlist_script_an_single ref="elem/settings/presettings/cutlist_script_an">
          <![CDATA[
          gSingle=true
          gNoBoard=true
]]>
        </cutlist_script_an_single>

        <!-- Referenced from user specific folders - do not remove -->
        <cutlist_script_an_single_boards ref="elem/settings/presettings/cutlist_script_an">
          <![CDATA[
          gSingle=true
]]>
        </cutlist_script_an_single_boards>


        <cutlist_script_an_cabbf ref="elem/settings/presettings/cutlist_script_an">
          <![CDATA[
          gType="ffbc"
]]>
        </cutlist_script_an_cabbf>

        <!-- ### PRESETTINGS TO INCLUDE JUST SOME PARTS PER CUT LIST BEG ### -->
        <!-- Core all -->
        <cutlist_table_coreall libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="#id# CORE"
if gLang=="fin" then
  gListSettings.title="#id# RUNKO"
elseif gLang=="swe" then
  gListSettings.title="#id# Huvudstomme lodrät" 
elseif gLang=="nor" then
  gListSettings.title="#id# BINDINGSVERK" 
elseif gLang=="por" then
  gListSettings.title="#id# NÚCLEO"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "core") then
    return false
  end
  return true
end

gListSettings.addmc=1
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_coreall>

        <!-- Core/studs -->
        <cutlist_table_corestuds libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="#id# STUDS"
if gLang=="fin" then
  gListSettings.title="#id# TOLPAT"
elseif gLang=="swe" then
  gListSettings.title="#id# Huvudstomme lodrät" 
elseif gLang=="nor" then
  gListSettings.title="#id# STENDERE" 
elseif gLang=="por" then
  gListSettings.title="#id# STUDS" 
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "core") then
    return false
  end
  if plank.elemtypesort=="002" then   -- Non-vertical piece
    return false
  end
  return true
end

gListSettings.addmc=1
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_corestuds>

        <cutlist_table_coreothers libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="OTHERS"
if gLang=="fin" then
  gListSettings.title="MUUT"
elseif gLang=="swe" then
  gListSettings.title="Huvudstomme vågrät"
elseif gLang=="nor" then
  gListSettings.title="#id# ANDRE" 
elseif gLang=="por" then
  gListSettings.title="#id# OUTROS" 
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "core") then
    return false
  end
  if plank.elemtypesort~="002" then   -- Non-vertical piece
    return false
  end
  return true
end

gListSettings.addmc=1
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_coreothers>


        <cutlist_table_coremodules libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="MODULES"
if gLang=="fin" then
  gListSettings.title="MODUULIT"
elseif gLang=="por" then
  gListSettings.title="MÓDULOS"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "core") then
    return false
  end
  
  local s

  ac_objectopen(plank.plankinfo.ptr)
  s=ac_objectget("iElemModule")
  ac_objectclose()
  if not s or s=="" then
    return false
  end
  return true
end

gListSettings.addmc=1
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_coremodules>

        <cutlist_table_insulation libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="#id# INSULATION"
if gLang=="fin" then
  gListSettings.title="#id# ERISTE"
elseif gLang=="swe" then
  --gListSettings.title="#id# Huvudstomme lodrät" 
elseif gLang=="nor" then
  --gListSettings.title="#id# BINDINGSVERK" 
elseif gLang=="por" then
  gListSettings.title="#id# ISOLAMENTO" 
end

gListSettings.funccollect=function(plank)
  if plank.plankinfo.type~=4 then
    return false
  end
  local n
  
  ac_objectopen(plank.plankinfo.ptr)
  n=ac_objectget("iTypeCode")
  ac_objectclose()
--ac_environment("tolog", string.format("iTypeCode=%s", n))
  if n and n==201 then
    return true
  end
  return false
end
gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
gListSettings.addinsu=true
gListSettings.resetlist=true
]]>
          </luasettings>
        </cutlist_table_insulation>


        <!-- Exterior boards -->
        <cutlist_table_extboards libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD EXT"
if gLang=="fin" then
  gListSettings.title="LEVY ULKO"
elseif gLang=="swe" then
  gListSettings.title="SKIVA UTSIDA"
elseif gLang=="nor" then
  gListSettings.title="PLATE UTVENDING"
elseif gLang=="por" then
  gListSettings.title="PLACA EXTERIOR"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "^boarding_ext.*") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extboards>

        
        <!-- Exterior boards 2 -->
        <cutlist_table_extboards2 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD EXT"
if gLang=="fin" then
  gListSettings.title="LEVY ULKO"
elseif gLang=="swe" then
  gListSettings.title="SKIVA UTSIDA"
elseif gLang=="nor" then
  gListSettings.title="PLATE UTVENDING"
elseif gLang=="por" then
  gListSettings.title="PLACA EXTERIOR"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or (not string.match(plank.elemtype, "boarding_ext") and not string.match(plank.elemtype, "boarding_ext2")) then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extboards2>


        <!-- Exterior boards 3 -->
        <cutlist_table_extboards3 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD EXT"
if gLang=="fin" then
  gListSettings.title="LEVY ULKO"
elseif gLang=="swe" then
  gListSettings.title="SKIVA UTSIDA"
elseif gLang=="nor" then
  gListSettings.title="PLATE UTVENDING"
elseif gLang=="por" then
  gListSettings.title="PLACA EXTERIOR"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "boarding_ext3") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extboards3>


        <!-- Exterior cladding & studding -->
        <cutlist_table_extcladstuds libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="CLADDING AND EXT STUDDING"
if gLang=="fin" then
  gListSettings.title="VERHOILU JA UP KOOLAUS"
elseif gLang=="nor" then
  gListSettings.title="KLEDNING OG LEKT"
elseif gLang=="por" then
  gListSettings.title="REVESTIMENTO E ESTRUTURA EXT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or (not string.match(plank.elemtype, "^finish_ext.*") and not string.match(plank.elemtype, "^extstud.*"))  then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extcladstuds>

        <cutlist_table_extall libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="EXTERIOR"
if gLang=="fin" then
  gListSettings.title="ULKOPUOLELLA"
elseif gLang=="nor" then
  gListSettings.title="UTVENDING"
elseif gLang=="por" then
  gListSettings.title="EXTERIOR"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, ".*ext.*") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=true      -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extall>
        
        <!-- Interior cladding & studding -->
        <cutlist_table_intcladstuds libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="INT STUDDING AND INT CLADDING"
if gLang=="fin" then
  gListSettings.title="SP KOOLAUS JA SP VERHOILU"
elseif gLang=="nor" then
  gListSettings.title="INNVENDIG PÅFORING OG INNVENDIG KLEDNING"
elseif gLang=="por" then
  gListSettings.title="ESTRUTURA INT E REVESTIMENTO INT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or (not string.match(plank.elemtype, "^finish_int.*") and not string.match(plank.elemtype, "^intstud.*"))  then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intcladstuds>

        <!-- Just first ext studding -->
        <cutlist_table_extstuds1 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="EXT STUDDING"
if gLang=="fin" then
  gListSettings.title="UP KOOLAUS"
elseif gLang=="swe" then
  gListSettings.title="SEKUNDÄRSTOMME"
elseif gLang=="nor" then
  gListSettings.title="UTVENDIG LEKT"
elseif gLang=="por" then
  gListSettings.title="ESTRUTURA EXT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or (plank.elemtype~="extstud" and plank.elemtype~="extstud2") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extstuds1>

        <!-- Just second ext studding -->
        <cutlist_table_extstuds2 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="EXT STUDDING"
if gLang=="fin" then
  gListSettings.title="UP KOOLAUS"
elseif gLang=="swe" then
  gListSettings.title="LUFTLÄKT"
elseif gLang=="nor" then
  gListSettings.title="UTVENDIG LEKT"
elseif gLang=="por" then
  gListSettings.title="ESTRUTURA EXT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or plank.elemtype~="extstud3" then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extstuds2>



        <!-- Just second ext studding -->
        <cutlist_table_extstuds3 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="EXT STUDDING"
if gLang=="fin" then
  gListSettings.title="UP KOOLAUS"
elseif gLang=="swe" then
  gListSettings.title="SPIKLÄKT"
elseif gLang=="nor" then
  gListSettings.title="UTVENDIG LEKT"
elseif gLang=="por" then
  gListSettings.title="ESTRUTURA EXT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or plank.elemtype~="extstud4" then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extstuds3>



        <!-- Just cladding -->
        <cutlist_table_extclad libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="CLADDING"
if gLang=="fin" then
  gListSettings.title="VERHOILU"
elseif gLang=="swe" then
  gListSettings.title="FASADBEKLÄDNAD"
elseif gLang=="nor" then
  gListSettings.title="KLEDNING"
elseif gLang=="por" then
  gListSettings.title="REVESTIMENTO"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "^finish_ext.*") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_extclad>
        
        <!-- Interior boards -->
        <cutlist_table_intboards libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD INT"
if gLang=="fin" then
  gListSettings.title="LEVY SISÄ"
elseif gLang=="swe" then
  gListSettings.title="Skiva insida"
elseif gLang=="nor" then
  gListSettings.title="PLATE INNVENDING"
elseif gLang=="por" then
  gListSettings.title="PLACA INT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "^boarding_int.*") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intboards>

        <cutlist_table_intboards2 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD INT 1"
if gLang=="fin" then
  gListSettings.title="LEVY SISÄ 1"
elseif gLang=="swe" then
  gListSettings.title="Skiva insida 1"
elseif gLang=="nor" then
  gListSettings.title="PLATE INNVENDING 1"
elseif gLang=="por" then
  gListSettings.title="PLACA INT 1"
end

gListSettings.funccollect=function(plank)
  -- Take first boarding which is either layer boarding_int or boarding_int2
  if plank.elemtype and (plank.elemtype=="boarding_int" or plank.elemtype=="boarding_int2") then
    return true
  end
  return false
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intboards2>


        <cutlist_table_intboards3 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD INT 2"
if gLang=="fin" then
  gListSettings.title="LEVY SISÄ 2"
elseif gLang=="swe" then
  gListSettings.title="SKIVA INSIDA 2"
elseif gLang=="nor" then
  gListSettings.title="PLATE INNVENDING 2"
elseif gLang=="por" then
  gListSettings.title="PLACA INT 2"
end

gListSettings.funccollect=function(plank)
  if plank.elemtype and plank.elemtype=="boarding_int3" then
    return true
  end
  return false
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intboards3>

        <cutlist_table_intboards4 libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="BOARD INT 3"
if gLang=="fin" then
  gListSettings.title="LEVY SISÄ 3"
elseif gLang=="swe" then
  gListSettings.title="SKIVA INSIDA 3"
elseif gLang=="nor" then
  gListSettings.title="PLATE INNVENDING 3"
elseif gLang=="por" then
  gListSettings.title="PLACA INT 3"
end

gListSettings.funccollect=function(plank)
  if plank.elemtype and plank.elemtype=="boarding_int4" then
    return true
  end
  return false
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intboards4>

        <!-- Interior studding -->
        <cutlist_table_intstuds libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="STUDDING INT"
if gLang=="fin" then
  gListSettings.title="SP KOOLAUS"
elseif gLang=="swe" then
  gListSettings.title="Sekundärstomme"
elseif gLang=="nor" then
  gListSettings.title="INNVENDIG PÅFORING"
elseif gLang=="por" then
  gListSettings.title="ESTRUTURA INT"
end

gListSettings.funccollect=function(plank)
  if not plank.elemtype or not string.match(plank.elemtype, "^intstud.*") then
    return false
  end
  return true
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_intstuds>
        
        <cutlist_table_allplanks libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="#id# CORE"
if gLang=="fin" then
  gListSettings.title="#id# RUNKO"
elseif gLang=="nor" then
  gListSettings.title="#id# BINDINGSVERK"
elseif gLang=="por" then
  gListSettings.title="#id# NÚCLEO"
end

gListSettings.funccollect=function(plank)
  if plank.plankinfo.type~=1 then
    return false
  end
  return true
end

gListSettings.addmc=1
gListSettings.addlen=1
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=nil
]]>
          </luasettings>
        </cutlist_table_allplanks>


        <cutlist_table_acc libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_script_an">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
          <luasettings>
            <![CDATA[
gListSettings={}
gListSettings.title="#id# ACCESSORIES"
gPcs="pcs"
if gLang=="fin" then
  gListSettings.title="#id# TARVIKKEET"
  gPcs="kpl"
elseif gLang=="swe" then
  gListSettings.title="#id# TILBEHÖR"
  gPcs="stk"
elseif gLang=="nor" then
  gListSettings.title="#id# TILBEHØR"
  gPcs="stk"
elseif gLang=="por" then
  gListSettings.title="#id# ACCESSORIES"
end

gAccTbl={}    -- funccollect collect all accessories here

gListSettings.funccollect=function(plank)
  -- Process every plank
  --if not plank.elemtype or not string.match(plank.elemtype, "core") then
  --  return false
  --end
  
--ac_environment("tolog", string.format("plank.plankinfo.ptr=%s", plank.plankinfo.ptr))
  ac_objectopen(plank.plankinfo.ptr)
  CalcMcQuant(gAccTbl)    -- For each piece calculate the accessories
  ac_objectclose()
  return true
end

gListSettings.funcgetrows=function()
  local k, v, i, res, t
  
  i=0
  res={}
  for k,v in pairs(gAccTbl) do
    t={}
    t.cols={}
    t.cols[1]="<left>" .. k     -- Acc ID
    if v.unit==2 then
      -- Meters
      t.cols[2]=Len2Str(v.num)
      t.cols[3]=ac_environment("units", "length", "dim")
    else
      t.cols[2]=string.format("%d", v.num)
      t.cols[3]=gPcs
    end

    i=i+1
    res[i]=t
  end
  
  table.sort( res,  function(p1, p2)
                            return p1.cols[1]<p2.cols[1]
                          end )

  return res
end

gListSettings.addmc=0
gListSettings.addlen=0
gListSettings.cladaddmat=false     -- Must be in every item since this setting is used when the list is first time created
gListSettings.rowheight=nil        -- Use defaults
gListSettings.tablewidth=4.5

gListSettings.collectall=true
gListSettings.resetlist=true

gListSettings.cols={}
t={}
t.title="<b><left>ID"
t.content=""		-- Not used
t.width=0.80
gListSettings.cols[1]=t
t={}
t.title="<b>NUM"
t.content=""		-- Not used
t.width=0.10
gListSettings.cols[2]=t
t={}
t.title="<b>UNIT"
t.content=""		-- Not used
t.width=0.10
gListSettings.cols[3]=t
]]>
          </luasettings>
        </cutlist_table_acc>

        <!-- ### PRESETTINGS TO INCLUDE JUST SOME PARTS PER CUT LIST END ### -->
        <cutlist_script_an>
          <![CDATA[
EPS=0.0001
gType=nil     -- Other possible values for separate cut lists: ffbc=main framing, main framing, all boards, cladding, 1.1=version 1.1 - include ext studding with cladding
g_sepByLayer=nil     -- If true, parts with same ID on different layers will be separated (for example boarding_ext2 and boarding_ext3)
g_clearElemRole=nil  -- If true, will reset element role when grouping the planks
g_collectAll=nil     -- Used to count accessories, causes all planks&boards to go to the filtering function


function GetLang()
  local lang
  
  lang=af_request("aflang")
  if lang==nil then
    lang="eng"
  end
  return lang
end


function BoardIsInsu()
	local code

	code=ac_objectget("iTypeCode")
	if code and code>=200 and code<300 then
		return true
	end
	return false
end


function Len2Str(len)
  return ac_environment("ntos", len, "length", "dim")
end

----------------------------------------
-- ACCESSORIES HELP

-- # Frame machinings types
EMcFrAngledBegOld	= 100
EMcFrAngledBeg		= 101
EMcFrAngledBegTenon = 110		-- Also dovetail (OLD)
EMcFrBegHiddenShoe	= 111
EMcFrAngledBegTenonMort = 112
EMcJointBeg			= 113
EMcVCutBeg			= 114
EMcFrAngledEndOld	= 200
EMcFrAngledEnd		= 201
EMcFrAngledEndTenon	= 210
EMcFrEndHiddenShoe	= 211
EMcFrAngledEndTenonMort = 212
EMcJointEnd			= 213
EMcVCutEnd			= 214

EMcFrOpening		= 300		-- Opening - unused now
EMcFrGroove			= 301		-- Logsin tapainen vapaa ura
EMcFrDrill			= 302		-- Drilling
EMcFrMarking		= 303		-- Marking
EMcFrReinforce		= 304
EMcFrSaw			= 305
EMcFrNailGroup		= 306
EMcFrNailLine		= 307

EMcFrTenonSide		= 400		-- Also dovetail
EMcFrBalkJoint		= 401		-- Narrowed balk

EMcLogTakasBalk		= 900
EMcLogTakasLog		= 901
EMcLogRounding		= 902
EMcLogCutShape		= 903
EMcFrTirol  		= 904

EMcFrBalkShoe		= 1000
EMcFrHobaFix		= 1001


-- Calcs balk shoes etc: tblAcc's key is the acc id and it has fields: num=quantity, unit: 1=pcs, 2=meters
function CalcMcQuant(tblAcc)
  local i, count, mc, tbl, s, key, c
  
  count=ac_objectget("iMc",-1)
  for i=1,count do
    mc=ac_objectget("iMc", i, 1)
    if mc==EMcFrBalkShoe  then
		  s=ac_objectget("iMcStr", i)
		  if s and s~="" then
			  tbl=tblAcc[s]
			  if tbl==nil then
				  tbl={}
				  tbl.num=0
          tbl.unit=1
				  tblAcc[s]=tbl
			  end

			  local nBeg, nEnd, n

			  nBeg=1
			  nEnd=0
			  n=ac_objectget("iMc",i,2)		-- flags
			  if ac_environment("bittest", n, 0)==1 then
				  nBeg=0
				  nEnd=1
			  end
			  if ac_environment("bittest", n, 3)==1 then
				  nBeg=1
				  nEnd=1
			  end
			  tbl.num=tbl.num+nBeg+nEnd
		  end
    elseif mc==EMcFrHobaFix  then
		  -- Hobafix
		  s=ac_objectget("iMcStr", i)
		  if s and s~="" then
			  tbl=tblAcc[s]
			  if tbl==nil then
				  tbl={}
				  tbl.num=0
          tbl.unit=1
				  tblAcc[s]=tbl
			  end
			  tbl.num=tbl.num+1
		  end
    elseif mc==EMcFrReinforce then
		  -- Reinforcement found
		  local height, len, width

		  s=ac_objectget("iMcStr", i)
		  height=ac_objectget("iMc",i,5)
		  len=ac_objectget("iMc",i,4)
		  width=ac_objectget("iMc",i,6)
		  if len==0 then
			  len=GetPlankLen()
		  end

		  c=1
		  if ac_objectget("iMc",i,8)==1 then
			  -- Both sides
			  c=2
		  end

		  key=string.format("%s %s x %s x %s", s, ac_environment("ntos", width, "length", "dim"), ac_environment("ntos", height, "length", "dim"), ac_environment("ntos", len, "length", "dim") )
		  tbl=tblAcc[key]
		  if tbl==nil then
			  tbl={}
			  tbl.num=0
        tbl.unit=1
			  tbl.width=width
			  tbl.height=height
			  tbl.len=len
			  tblAcc[key]=tbl
		  end

		  tbl.num=tbl.num+c
    end
  end
end

-- ACCESSORIES HELP
----------------------------------------


-- Constructs string for col1 (may be overridden by gListSettings.col1str_plank later on)
function GetCol1Str(item)
  if item.type==4 then
    -- Board, find max size from the polygon
    local   i, count, x1, x2, y1, y2, x, y, s
    
    x1=1e10
    y1=1e10
    x2=-x1
    y2=-y1
    count=ac_objectget("iPolygon", -1)
    for i=1,count do
      x=ac_objectget("iPolygon", i, 1)
      y=ac_objectget("iPolygon", i, 2)
      if x<x1 then
        x1=x
      end
      if x>x2 then
        x2=x
      end
      if y<y1 then
        y1=y
      end
      if y>y2 then
        y2=y
      end
    end

    -- 2018_03 boards named TS 9*width*height, take just first part
    -- Allow also x:
    local i2, sep
    
    s=item.typename
    sep="*"
    i=string.find(s, "*")
    i2=string.find(s, "x")
    if not i or (i and i2 and i2<i) then
      sep="x"
      i=i2
    end
    if i then
      s=string.sub(s, 1, i-1)
    end
    return string.format("%s %s %s %s %s (%s)", s, sep, Len2Str(x2-x1), sep, Len2Str(y2-y1), item.id)
  end

  return item.idgroupshow
end


-- COMMON FUNCTION IN A FEW PLACES IN DATA-FOLDER, UPDATE ALL IF UPDATING ONE
-- isHor  Is it horizontal structure (false/nil=default) (rotated inside the element, in walls true if horizontal framing)
-- lang   eng/swe/fin
-- elemgroup  Parameter iElemGroup
-- nFloorRoof, nil=not known or a wall, 1=it is a floor, 2=it is a roof
function GetElemGroupName(isHor, elemgroup, nFloorRoof)
  local lang
  
--ac_environment("tolog", string.format("%s", tostring(isFloor)))
  -- 4/2022: Added possibility to set this easily for own element type layouts
  if gnFloorRoof then
    nFloorRoof=gnFloorRoof
  end
  
  lang=af_request("aflang")
  if nFloorRoof and nFloorRoof==1 then
    -- It is a floor
    if elemgroup==nil then
      elemgroup=""
    elseif string.match(elemgroup, "^nogging.*") then
      elemgroup="Nogging"
      if lang=="nor" then
        elemgroup="Kubbing"
      elseif lang=="fin" then
        elemgroup="Nurjahdustuki"
      elseif lang=="swe" then
        elemgroup="Kortling"
      elseif lang=="por" then
        elemgroup="Tabique"
      end
    elseif elemgroup=="sideleft_spacing" or elemgroup=="sideright_spacing" then
      elemgroup="Side beams"
      if lang=="fin" then
        elemgroup="Sivupalkki"
      elseif lang=="nor" then
        elemgroup="Stikkbjelke"
      elseif lang=="swe" then
        elemgroup="Ändkortling"
      elseif lang=="por" then
        elemgroup="Vigas laterais"
      end
    elseif string.match(elemgroup, "^vertical_x.*") or string.match(elemgroup, "^contourtilted_opening.*") then
      elemgroup="Joist"   -- Could be better
      if lang=="fin" then
        elemgroup="Vekselipalkki"
      elseif lang=="nor" then
        elemgroup="Vekselbjelke"
      elseif lang=="swe" then
        elemgroup="Joist" -- Could be better
      elseif lang=="por" then
        elemgroup="Viga"  -- Could be better
      end
    elseif string.match(elemgroup, "^vertical_spacing.*") then
      elemgroup="Joist"   -- Could be better
      if lang=="fin" then
        elemgroup="Vasa"
      elseif lang=="nor" then
        elemgroup="Modulbjelke"
      elseif lang=="swe" then
        elemgroup="Joist" -- Could be better
      elseif lang=="por" then
        elemgroup="Viga"  -- Could be better
      end
    elseif string.match(elemgroup, "^vertical_y.*") then
      elemgroup="Joist"   -- Could be better
      if lang=="fin" then
        elemgroup="Vasa"
      elseif lang=="nor" then
        elemgroup="Sidebjelke"
      elseif lang=="swe" then
        elemgroup="Joist" -- Could be better
      elseif lang=="por" then
        elemgroup="Viga"  -- Could be better
      end
    elseif string.match(elemgroup, "^top.*") or string.match(elemgroup, "^2ndtop.*") or string.match(elemgroup, "^contour.*") or string.match(elemgroup, "^bottom.*") or string.match(elemgroup, "^2ndbottom.*") then
      if lang=="eng" then
        elemgroup="Contour piece"
      elseif lang=="fin" then
        elemgroup="Reunakappale"
      elseif lang=="swe" then
        elemgroup="Contour piece"
      elseif lang=="nor" then
        elemgroup="Kantbjelke"
      elseif lang=="por" then
        elemgroup="Peça de contorno"
      end
    else
      if lang=="eng" then
        elemgroup="Joist"
      elseif lang=="fin" then
        elemgroup="Vasa"
      elseif lang=="swe" then
        elemgroup="Joist"
      elseif lang=="nor" then
        elemgroup="Bjelke"
      elseif lang=="por" then
        elemgroup="Viga"
      end
    end
  elseif nFloorRoof and nFloorRoof==2 then
    -- It is a roof
    if elemgroup==nil then
      elemgroup=""
    elseif string.match(elemgroup, "^top.*") or string.match(elemgroup, "^2ndtop.*") or string.match(elemgroup, "^contour.*") or string.match(elemgroup, "^bottom.*") or string.match(elemgroup, "^2ndbottom.*") then
      if lang=="eng" then
        elemgroup="Top/bottom"
      elseif lang=="fin" then
        elemgroup="Ylä/alajuoksu"
      elseif lang=="swe" then
        elemgroup="Top/bottom"
      elseif lang=="nor" then
        elemgroup="Drager"
      elseif lang=="por" then
        elemgroup="Topo/base"
      end
    else
      if lang=="eng" then
        elemgroup="Rafter"
      elseif lang=="fin" then
        elemgroup="Vasa"
      elseif lang=="swe" then
        elemgroup="Rafter"
      elseif lang=="nor" then
        elemgroup="Sperr"
      elseif lang=="por" then
        elemgroup="Trave"
      end
    end
  elseif isHor then
    -- Horizontal structure
    if elemgroup==nil then
      elemgroup=""
    elseif string.match(elemgroup, "^top%a*") or string.match(elemgroup, "^2ndtop%a*") or string.match(elemgroup, "^contour_x.*") then
      elemgroup="Stud"
      if lang=="fin" then
        elemgroup="Tolppa"
      elseif lang=="swe" then
        elemgroup="Regel"
      elseif lang=="nor" then
        elemgroup="Stendere"
      elseif lang=="por" then
        elemgroup="Stud"
      end
    elseif string.match(elemgroup, "^bottom%a*") or string.match(elemgroup, "^2ndbottom%a*") then
      elemgroup="Stud"
      if lang=="fin" then
        elemgroup="Tolppa"
      elseif lang=="swe" then
        elemgroup="Regel"
      elseif lang=="nor" then
        elemgroup="Stendere"
      elseif lang=="por" then
        elemgroup="Stud"
      end
    elseif string.match(elemgroup, "^vertical_x%a*") or string.match(elemgroup, "^vertical_y%a*") or string.match(elemgroup, "^contourtilted_opening%a*") then
      elemgroup="Door/win"
      if lang=="fin" then
        elemgroup="Ikk/ovi"
      elseif lang=="swe" then
        elemgroup="Avväxling"
      elseif lang=="nor" then
        elemgroup="Losholt" -- "Dør/vindu"
      elseif lang=="por" then
        elemgroup="Porta/Janela"
      end
    elseif string.match(elemgroup, "^vertical%a*") then
      elemgroup="Hor"
      if lang=="fin" then
        elemgroup="Vaaka"
      elseif lang=="nor" then
        elemgroup="Vannrett"
      elseif lang=="por" then
        elemgroup="Hor"
      end
    elseif string.match(elemgroup, "^contourtilted%a*") then
      elemgroup="Angled"
      if lang=="fin" then
        elemgroup="Vinojuoksu"
      elseif lang=="swe" then
        elemgroup="Regel"
      elseif lang=="nor" then
        elemgroup="Vinklet"
      elseif lang=="por" then
        elemgroup="Angulado"
      end
    elseif string.match(elemgroup, "^balk.*") then
      elemgroup="Beam"
      if lang=="fin" then
        elemgroup="Palkki"
      elseif lang=="swe" then
        elemgroup="Bärlina"
      elseif lang=="nor" then
        elemgroup="Bjelke"
      elseif lang=="por" then
        elemgroup="Viga"
      end
    elseif string.match(elemgroup, "^lintel.*") then
      elemgroup="W/D beam"
      if lang=="fin" then
        elemgroup="Aukkopalkki"
      elseif lang=="swe" then
        elemgroup="Bärplanka"
      elseif lang=="nor" then
        elemgroup="Dragere"   -- "Dør-/vindu-bjelke"
      elseif lang=="por" then
        elemgroup="Viga P/J"
      end
    elseif string.match(elemgroup, "^reinforce.*") then
      elemgroup="Reinforcement"
      if lang=="fin" then
        elemgroup="Vahvike"
      elseif lang=="swe" then
        elemgroup="Förstärkning"
      elseif lang=="nor" then
        elemgroup="Forsterkning"
      elseif lang=="por" then
        elemgroup="Reforço"
      end
    elseif string.match(elemgroup, "^nogging.*") then
      elemgroup="Nogging"
      if lang=="nor" then
        elemgroup="Kubbing"
      elseif lang=="fin" then
        elemgroup="Nurjahdustuki"
      elseif lang=="swe" then
        elemgroup="Kortling"
      elseif lang=="por" then
        elemgroup="Tabique"
      end
    elseif elemgroup=="sideleft_spacing" or elemgroup=="sideright_spacing" then
      elemgroup="Side beams"
      if lang=="fin" then
        elemgroup="Sivupalkki"
      elseif lang=="nor" then
        elemgroup="Stikkbjelke"
      elseif lang=="swe" then
        elemgroup="Ändkortling"
      elseif lang=="por" then
        elemgroup="Vigas laterais"
      end
    else
      elemgroup=""    -- Just leave it empty, earlier was "? (elemgroup)"
    end
  else
    -- Vertical structure
    if elemgroup==nil then
      elemgroup=""
    elseif string.match(elemgroup, "^top%a*") or string.match(elemgroup, "^2ndtop%a*") then
      elemgroup="Top plate"
      if lang=="fin" then
        elemgroup="Yläjuoksu"
      elseif lang=="swe" then
        elemgroup="HB"
      elseif lang=="nor" then
        elemgroup="Toppsvill"
      elseif lang=="por" then
        elemgroup="Placa de topo"
      end
    elseif string.match(elemgroup, "^bottom%a*") or string.match(elemgroup, "^2ndbottom%a*") then
      elemgroup="Bottom plate"
      if lang=="fin" then
        elemgroup="Alajuoksu"
      elseif lang=="swe" then
        elemgroup="Syll"
      elseif lang=="nor" then
        elemgroup="Bunnsvill"
      elseif lang=="por" then
        elemgroup="Placa base"
      end
    elseif string.match(elemgroup, "^contour_x.*") then
      elemgroup="Top/bottom plate"
      if lang=="fin" then
        elemgroup="Ylä/alajuoksu"
      elseif lang=="swe" then
        elemgroup="HB/Syll"
      elseif lang=="nor" then
        elemgroup="Topp-/Bunnsvill"
      elseif lang=="por" then
        elemgroup="Placa Topo/base"
      end
    elseif string.match(elemgroup, "^vertical_x%a*") or string.match(elemgroup, "^contourtilted_opening%a*") then
      elemgroup="Win/door"
      if lang=="fin" then
        elemgroup="Ikk/ovi"
      elseif lang=="swe" then
        elemgroup="Avväxling"
      elseif lang=="nor" then
        elemgroup="Losholt" -- "Dør/vindu"
      elseif lang=="por" then
        elemgroup="Janela/Porta"
      end
    elseif string.match(elemgroup, "^vertical%a*") or string.match(elemgroup, "^contour_y.*") then
      elemgroup="Stud"
      if lang=="fin" then
        elemgroup="Tolppa"
      elseif lang=="swe" then
        elemgroup="Regel"
      elseif lang=="nor" then
        elemgroup="Stendere"
      elseif lang=="por" then
        elemgroup="Stud"
      end
    elseif string.match(elemgroup, "^contourtilted%a*") then
      elemgroup="Angled"
      if lang=="fin" then
        elemgroup="Vinojuoksu"
      elseif lang=="swe" then
        elemgroup="Regel"
      elseif lang=="nor" then
        elemgroup="Vinklet"
      elseif lang=="por" then
        elemgroup="Angulado"
      end
    elseif string.match(elemgroup, "^balktop.*") then
      elemgroup="Beam top"
      if lang=="fin" then
        elemgroup="Palkki ylä"
      elseif lang=="swe" then
        elemgroup="Bärlina topp"
      elseif lang=="nor" then
        elemgroup="Bjelke"
      elseif lang=="por" then
        elemgroup="Viga topo"
      end
    elseif string.match(elemgroup, "^balkbot.*") then
      elemgroup="Beam bottom"
      if lang=="fin" then
        elemgroup="Palkki ala"
      elseif lang=="swe" then
        elemgroup="Bärlina botten"
      elseif lang=="nor" then
        elemgroup="Bjelke"
      elseif lang=="por" then
        elemgroup="Viga base"
      end
    elseif string.match(elemgroup, "^lintel.*") then
      elemgroup="W/D beam"
      if lang=="fin" then
        elemgroup="Aukkopalkki"
      elseif lang=="swe" then
        elemgroup="Bärplanka"
      elseif lang=="nor" then
        elemgroup="Dragere" -- "Dør-/vindu-bjelke"
      elseif lang=="por" then
        elemgroup="Viga P/J"
      end
    elseif string.match(elemgroup, "^nogging.*") then
      elemgroup="Nogging"
      if lang=="nor" then
        elemgroup="Kubbing"
      elseif lang=="fin" then
        elemgroup="Nurjahdustuki"
      elseif lang=="swe" then
        elemgroup="Kortling"
      elseif lang=="por" then
        elemgroup="Tabique"
      end
    elseif elemgroup=="sideleft_spacing" or elemgroup=="sideright_spacing" then
      elemgroup="Side beams"
      if lang=="fin" then
        elemgroup="Sivupalkki"
      elseif lang=="nor" then
        elemgroup="Stikkbjelke"
      elseif lang=="swe" then
        elemgroup="Ändkortling"
      elseif lang=="por" then
        elemgroup="Vigas laterais"
      end
    else
      elemgroup=""    -- Just leave it empty, earlier was "? (elemgroup)"
    end
  end
  
  return elemgroup
end


-- tblguids   in, the planks/boards to process
-- tblPlanks  out, result is saved here
function CollectPlanksBoards( vElem, tblguids, tblPlanks, elemTypeSort, isHor, bPanel )
  local i, v, plankInfo, id, s, pos, item, fillpen, idgroup, idgroupshow, elemgroup, elemTypeSortNow
  local lang
  
  lang=GetLang()
  i=1
	while true do
		v=tblguids[i]
    i=i+1
		if v==nil then
			break
		end

    if v.ispanel~=nil and v.ispanel==1 then
      -- Cladding layer made with ArchiFrameBoardPanel-object
      local tblPtrs, tbl2, i2
      
      tblPtrs=af_request("mc_explodepanel", v.ptr, nil)
      if tblPtrs then
        tbl2={}
        i2=1
        while tblPtrs[i2] do
          tbl2[i2]={}
          tbl2[i2].ptr=tblPtrs[i2]
          i2=i2+1
        end
        CollectPlanksBoards( vElem, tbl2, tblPlanks, elemTypeSort, isHor, true )
      end
    else
      -- Plank/board, get first the type of the piece
		  ac_objectopen(v.ptr)
		  plankInfo=af_request("plankinfo")
      s="-"     -- This is the master plank not showing the short ID probably: ac_objectget("iShowIDSep")
      if plankInfo.type==4 then
        s="#"   -- board
      end

      -- Then force the ID separator to be able to use ID generation string
      local infoSettings
      
      infoSettings={}
      infoSettings.idsep=s
      
		  plankInfo=af_request("plankinfo", nil, nil, infoSettings)
      fillpen=ac_objectget("iFillPen")
      elemgroup=ac_objectget("iElemGroup")

      id=plankInfo.idgenerated
      if not id then
		    id=ac_objectget("#id")
        if id then
          -- Skip element ID
          --pos=string.find(id, s, 1, true)   -- No reverse find in Lua
          pos=string.len(id)
          while pos>=1 do
            if string.sub(id,pos,pos)==s then
              break
            end
            pos=pos-1
          end
          if pos then
            id=string.sub(id, pos+1)
          end
        end
      end

      -- Check if floor only if made as customer specific customization (not on by default)
      local nFloorRoof
      
      if false then
        -- Not used in default data
        if vElem.geo then
          if math.abs(1 - math.abs(vElem.geo.vecz.z))<0.01 then
            nFloorRoof=1
          elseif math.abs(math.abs(vElem.geo.vecz.z))>0.01 then
            nFloorRoof=2
          end
        end
      end
      elemgroup=GetElemGroupName(isHor, elemgroup, nFloorRoof)

      elemTypeSortNow=elemTypeSort
      if elemTypeSortNow=="001" then
        if math.abs(plankInfo.vecx.z-1)>EPS then
          -- Ei pysty
          elemTypeSortNow="002"
        end
      end

      if bPanel then
        -- Exploded panels without ID, forget elemgroup
        idgroup=string.format("%s %s %s %s", plankInfo.typename, Len2Str(plankInfo.width), Len2Str(plankInfo.height), Len2Str(plankInfo.len))
        idgroupshow=plankInfo.typename
      else
        s=elemgroup
        if g_clearElemRole then
          s=""
        end
        idgroup=s .. " " .. plankInfo.typename .. " (" .. id .. ")"     -- Actually id is last
        idgroupshow=idgroup
        idgroup=idgroup .. Len2Str(plankInfo.len)   -- Add length in case we have manual plank numbering
      end
      
      if plankInfo.tblWeather and plankInfo.tblWeather.wbguid then
        -- Separate weatherboards by wbguid to have different opening pieces not combined
        idgroup=idgroup .. " " .. plankInfo.tblWeather.wbguid
      end

      if (bPanel or string.match(vElem.elemtype, "^finish.*")) and gListSettings and gListSettings.cladaddmat then
          -- Add AC 3D material name to the cladding piece
        local smat
        
        smat=" " .. ac_objectget("#matname")
        idgroup=idgroup .. smat
        idgroupshow=idgroupshow .. smat
      end
      
      if g_collectAll then
        idgroup=idgroup .. plankInfo.ptr
      end

      s=ac_objectget("iIncludeCutlist")     -- Added 8/2019, 1=include (default)
      if BoardIsInsu() and (not gListSettings or not gListSettings.addinsu) then                 -- 2/2020: Don't collect insulation unless it is exploded. Change 4/2021: collect if in settings
        s=0
      end
      if not s or s==1 then
        s=string.format("%s %s", elemTypeSortNow, idgroup)

        if g_sepByLayer and vElem and vElem.elemtype then
          s=s .. vElem.elemtype
        end

    --ac_environment("tolog", s)
        item=tblPlanks[s]
        if item==nil then
          item={}
          item.elemtypesort=elemTypeSortNow
          item.idgroup=idgroup
          item.idgroupshow=idgroupshow
          item.elemgroup=elemgroup
          item.elemtype=vElem.elemtype
          item.id=id
          item.plankinfo=plankInfo
          item.type=plankInfo.type
          item.matid=ac_objectget("iMatId")
          item.typename=plankInfo.typename
          item.typewidth=plankInfo.width
          item.typeheight=plankInfo.height
          item.len=plankInfo.len
          item.fillpen=fillpen
          item.tblids={}
          item.tblinfos={}
          item.count=0
          item.col1str=GetCol1Str(item)
          item.external=v.external
          tblPlanks[s]=item
        end

        item.count=item.count+1
        item.tblinfos[item.count]=plankInfo
      end
      
      ac_objectclose()
    end
  end
end


function CmpPlanks( p1, p2 )
  if p1.type~=p2.type then
    return p1.type<p2.type      -- Plank=1, 4=board, planks first
  end
  
  if p1.type==4 then
    -- For boards the sort order is: typename, thickness, height, len
    if p1.typename~=p2.typename then
      return p1.typename<p2.typename
    end

    if math.abs(p1.typewidth-p2.typewidth)>0.001 then
      -- Actually for similar type boards the thickness should be the same
      return p1.typewidth>p2.typewidth
    end
    
    if math.abs(p1.typeheight-p2.typeheight)>0.001 then
      return p1.typeheight>p2.typeheight
    end

    if math.abs(p1.len-p2.len)>0.001 then
      return p1.len>p2.len
    end
    
    return false
  end
  
  -- Owning element type
  if p1.elemtypesort~=p2.elemtypesort then
    return p1.elemtypesort<p2.elemtypesort
  end
  
  -- Bigger first
  if math.abs(p1.typewidth-p2.typewidth)>0.001 then
    return p1.typewidth>p2.typewidth
  end

  if math.abs(p1.typeheight-p2.typeheight)>0.001 then
    return p1.typeheight>p2.typeheight
  end
  
  if p1.typename~=p2.typename then
    return p1.typename<p2.typename
  end

  if math.abs(p1.len-p2.len)>0.001 then
    return p1.len>p2.len
  end
  
  return p1.idgroup<p2.idgroup
end


-- Generates info text for current piece (similar functions in ArchiFrameBlocks.xml and ArchiFrameElements.xml)
function GetInfoText(plankinfo, bCladding)
  local i, count, res, mc, nUnknown
  local lang
  
  lang=GetLang()
  res=""
  count=ac_objectget("iMc",-1)
  nUnknown=0
  for i=1,count do
    mc=ac_objectget("iMc", i, 1)
    if mc==301 and not bCladding then
      -- Groove
      local side, x1, x2, y1, y2, width, angleDeg, tiltDeg, groType

      x1=ac_objectget("iMc", i, 2)
      y1=ac_objectget("iMc", i, 3)
      x2=ac_objectget("iMc", i, 4)
      y2=ac_objectget("iMc", i, 5)
      depth=ac_objectget("iMc", i, 6)
      width=ac_objectget("iMc", i, 7)
      angleDeg=ac_objectget("iMc", i, 8)
      side=ac_objectget("iMc", i, 9)
      tiltDeg=ac_objectget("iMc", i, 10)
      groType=ac_objectget("iMc", i, 11)

	    if (side==5 or side==6) and groType==0 and angleDeg==0 and tiltDeg==0 and x1<EPS and x2>plankinfo.width-EPS and math.abs(y2-y1)<EPS then
		    -- Move gro to top/bottom if possible
		    if y1<EPS or y1+width+EPS>plankinfo.height then
			    local orgSide, depthOrg

			    orgSide=side
          depthOrg=depth
			    if y1<EPS then
				    side=3
			    else
				    side=1
			    end
			    if orgSide==5 then
				    x1=depth
			    else
				    x1=plankinfo.len
			    end
			    x2=x1
			    y1=0
			    y2=plankinfo.width
			    depth=width
			    width=depthOrg
		    end
	    end

      if (side==3 or side==1) and groType==0 and angleDeg==0 and tiltDeg==0 and y1<EPS and y2>plankinfo.width-EPS and math.abs(x2-x1)<EPS then
        local distBot, distTop, s
        
        distBot=x1-width
        distTop=plankinfo.len-x1

        if res~="" then
          res=res .. ", "
        end
        
        if math.abs(distBot)<0.0004 then
          distBot=0
        end
        if math.abs(distTop)<0.0004 then
          distTop=0
        end

        if plankinfo.vecx.z>0.999 then
          s="front"
          if side==1 then
            s="back"
          end
          if lang=="fin" then
            s="etu"
            if side==1 then
              s="taka"
            end
          end
        else
          s="bottom"
          if side==1 then
            s="top"
          end
          if lang=="fin" then
            s="ala"
            if side==1 then
              s="ylä"
            end
          end
        end

        if math.abs(distBot)<math.abs(distTop) then
          if plankinfo.vecx.z>0.99 then
            if lang=="fin" then
              s=string.format("Lovi %s %sx%s ar:sta %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            else
              s=string.format("Slot %s %sx%s from bot %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            end
          else
            if lang=="fin" then
              s=string.format("Lovi %s %sx%s alusta %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            else
              s=string.format("Slot %s %sx%s from begin %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            end
          end
        else
          if plankinfo.vecx.z>0.99 then
            if lang=="fin" then
              s=string.format("Lovi %s %sx%s yr:sta %s", s, Len2Str(depth), Len2Str(width), Len2Str(distTop))
            else
              s=string.format("Slot %s %sx%s from top %s", s, Len2Str(depth), Len2Str(width), Len2Str(distTop))
            end
          else
            if lang=="fin" then
              s=string.format("Lovi %s %sx%s lopusta %s", s, Len2Str(depth), Len2Str(width), Len2Str(distTop))
            else
              s=string.format("Slot %s %sx%s from end %s", s, Len2Str(depth), Len2Str(width), Len2Str(distTop))
            end
          end
        end
        res=res .. s
      else
        nUnknown=nUnknown+1
      end
    elseif mc==101 or mc==201 then
      -- Cut beg/end
      local a1, a2, fmt
      
      a1=ac_objectget("iMc", i, 2)
      a2=ac_objectget("iMc", i, 3)
      fmt="Angled beg"
      if mc==201 then
        fmt="Angled end"
      end
      if lang=="fin" then
        fmt="Viiste alku"
        if mc==201 then
          fmt="Viiste loppu"
        end
      end
      

      if res~="" then
        res=res .. ", "
      end
      if math.abs(a1-90)>0.4 and math.abs(a2-90)<0.4 then
        s=string.format("%s %.0f°", fmt, math.abs(a1-90))
      elseif math.abs(a1-90)<0.4 and math.abs(a2-90)>0.4 then
        if lang=="fin" then
          s=string.format("%s korksuunnassa %.1f°", fmt, math.abs(a2-90))
        else
          s=string.format("%s in height dir %.1f°", fmt, math.abs(a2-90))
        end
      else
        if lang=="fin" then
          s=string.format("%s kahteen suuntaan, katso ohje", fmt)
        else
          s=string.format("%s double angled, see detail", fmt)
        end
      end
      res=res .. s
      
    elseif mc==305 then
      -- Lengthwise cut
      local side, x1, width, depth, yoff, angle_c, angle_d, handled, w2, depth, height, plankInfo
      
      side=ac_objectget("iMc", i, 2)
      x1=ac_objectget("iMc", i, 3)
      width=ac_objectget("iMc", i, 4)
      depth=ac_objectget("iMc", i, 5)
      yoff=ac_objectget("iMc", i, 6)
      angle_c=ac_objectget("iMc", i, 7)
      angle_d=ac_objectget("iMc", i, 8)

--ac_environment("tolog", string.format("x1=%f width=%f depth=%f yoff=%f angle_c=%f angle_d=%f", x1, width, depth, yoff, angle_c, angle_d))
      w2=plankinfo.height*0.5
      if x1<0.001 and width<0.001 and math.abs(depth)<0.001 and (side==2 or side==4) then
        if angle_c>0 and math.abs(angle_d)<0.1 then
          -- Top of the surface cut
          -- 0.017453292=PI/180
          depth=w2-yoff
		      height=depth*math.tan(angle_c*0.017453292)
        elseif angle_d>0 and math.abs(angle_c)<0.1 then
          -- Bottom of the surface cut
          depth=w2+yoff
		      height=depth*math.tan(angle_d*0.017453292)
        end
        
		    plankInfo=af_request("plankinfo")
        if depth>0 and height>0 and depth<plankInfo.height and height<plankInfo.width then
		      if res~="" then
			      res=res .. ", "
		      end
          if lang=="fin" then
            s=string.format("viiste %sx%s", Len2Str(depth), Len2Str(height))
          else
            s=string.format("lengthwise cut %sx%s", Len2Str(depth), Len2Str(height))
          end
		      res=res .. s
		      handled=true
        end
	    end
      
      if not handled then
        nUnknown=nUnknown+1
      end
    elseif mc>0 then
        -- Do not calculate as unknown: EMcMarking = 303, EMcNailGroup = 306, EMcNailLine = 307, EMetalShoeEnd = 1000, EMetalHobaFix = 1001
        if mc~=303 and mc~=306 and mc~=307 and mc~=1000 and mc~=1001 then
          nUnknown=nUnknown+1
        end
    end
  end
  
  if nUnknown>0 and not bCladding then
    if res~="" then
      res=res .. ", "
    end
    if lang=="fin" then
      s=string.format("muita työstöjä %d kpl - katso ohje", nUnknown)
    else
      s=string.format("other cuts %d pcs - see detail", nUnknown)
    end
    res=res .. s
  end
  return res
end


function GetDist3D(c1, c2)
  local dx, dy, dz
  
  dx=c2.x-c1.x
  dy=c2.y-c1.y
  dz=c2.z-c1.z
  dx=math.sqrt(dx*dx + dy*dy + dz*dz)
  return dx
end


function IsNeighbour(item1, item2)
  if GetDist3D(item1.begc, item2.begc)>item1.width+0.001 then
    return false
  end

  if GetDist3D(item1.endc, item2.endc)>item1.width+0.001 then
    return false
  end

  if math.abs(item1.vecx.x-item2.vecx.x)>0.001 or math.abs(item1.vecx.y-item2.vecx.y)>0.001 or math.abs(item1.vecx.z-item2.vecx.z)>0.001 then
    return false
  end

  if math.abs(item1.vecz.x-item2.vecz.x)>0.001 or math.abs(item1.vecz.y-item2.vecz.y)>0.001 or math.abs(item1.vecz.z-item2.vecz.z)>0.001 then
    return false
  end
  
  return true
end


-- Creates string for studs next to each other
-- tblinfos 1-based table of plankinfos
function GetGroupedStudsStr(inStr, tblinfos)
  local i, v, res, tblGroup, tblUsed, i2, added, tblNow, i3, collected, s
  local lang=GetLang()
  
  res=inStr
  tblGroup={}   -- Index=number grouped planks, value=count of groups (not planks)
  tblUsed={}    -- Index=ptr for used planks
  i=1
  while tblinfos[i] do
    v=tblinfos[i]
    if not tblUsed[v.ptr] and v.vecx.z>0.999 and v.type==1 then
      -- Find any connecting
      local x1, x2
      tblUsed[v.ptr]=true
      
      -- Collect the group
      tblNow={}
      tblNow[1]=v
      collected=1

      repeat
        added=false
        i2=i+1
        while tblinfos[i2] do
          for i3=1,collected do
            if IsNeighbour(tblNow[i3], tblinfos[i2]) and tblUsed[tblinfos[i2].ptr]==nil then
              tblUsed[tblinfos[i2].ptr]=true
              collected=collected+1
              tblNow[collected]=tblinfos[i2]
              added=true
              break
            end
          end
          
          i2=i2+1
        end
      until not added
      
      if collected>1 then
        if tblGroup[collected]==nil then
          tblGroup[collected]=0
        end
        tblGroup[collected]=tblGroup[collected]+1
      end
    end
    i=i+1
  end
  
  for i=2,10 do
    if tblGroup[i] then
      if i==2 then
        if lang=="fin" then
          s="tuplatolppa"
        else
          s="double stud"
        end
      else
        if lang=="fin" then
          s=string.format("%d x tolppa", i)
        else
          s=string.format("%d x stud", i)
        end
      end
      
      if res~="" then
        res = res .. ", "
      end
      if lang=="fin" then
        res=res .. string.format("%d kpl %s", tblGroup[i], s)
      else
        res=res .. string.format("%d pcs %s", tblGroup[i], s)
      end
    end
  end

  return res
end


-- Collects all planks&boards related to all element layers
-- Returns it sorted
function DoTable(pickExternal)
	local	s, k, v, i, nElem, vElem, tblQuant, plankInfo, id, item, elemId
  local tblPlanks   -- Also boards, key="type typename length", fields: type (1=plank, 2=log object, 4=board), matid, typename, typewidth, typeheight, len (numeric), tblids=table of plank ids with id=key, count=number of this type
  local tblElemSortToName
  local lang

  lang=GetLang()
  v={}
  v.external=pickExternal
  tblQuant=af_request("elem_quantities", nil, 1, v)

  elemId="(ID MISSING)"
  tblPlanks={}
  tblElemSortToName={}      -- Maps element type sort str -> its name (001->RUNKO, 002->SP KOOLAUS, 003->MUUT)
	for nElem,vElem in ipairs(tblQuant.tblelems) do
    if not vElem.geo then
      vElem.geo=tblQuant.geo      -- To have it later on, not exactly for this element, use given if added in future
    end
    
    if vElem.elemtype=="core" then
      elemId=vElem.id
    end

    local elemTypeSort, elemTypeName
    
    elemTypeSort="999"
    if lang=="fin" then
      elemTypeName="MUUT"
    elseif lang=="nor" then
      elemTypeName="ANDRE" 
    else
      elemTypeName="OTHERS"
    end        
    
    if vElem.elemtype=="core" then
      elemTypeSort="001"
      if lang=="fin" then
        elemTypeName="TOLPAT"
      else
        elemTypeName="STUDS"
      end        
      if lang=="fin" then
        tblElemSortToName["002"]="MUUT"
      elseif lang=="swe" then
        tblElemSortToName["002"]="Vågrät"
      elseif lang=="nor" then
        tblElemSortToName["002"]="ANDRE" 
      else
        tblElemSortToName["002"]="OTHERS"
      end
    elseif string.match(vElem.elemtype, "^intstud*") then
      elemTypeSort="010"
      if lang=="fin" then
        elemTypeName="SISÄKOOLAUS"
      else
        elemTypeName="INT STUDDING"
      end        
    elseif string.match(vElem.elemtype, "^extstud*") then
      elemTypeSort="020"
      if lang=="fin" then
        elemTypeName="ULKOKOOLAUS"
      else
        elemTypeName="EXT STUDDING"
      end
    elseif string.match(vElem.elemtype, "^finish_ext*") then
      elemTypeSort="030"    -- This number used not to include mc-info
      if lang=="fin" then
        elemTypeName="VERHOILU"
      else
        elemTypeName="CLADDING"
      end
    elseif string.match(vElem.elemtype, "^boarding_ext*") then
      elemTypeSort="040"
      if lang=="fin" then
        elemTypeName="LEVY ULKO"
      else
        elemTypeName="BOARD EXT"
      end
    elseif string.match(vElem.elemtype, "^boarding_int*") then
      elemTypeSort="050"
      if lang=="fin" then
        elemTypeName="LEVY SISÄ"
      else
        elemTypeName="BOARD INT"
      end
    end

    if elemTypeSort then
      local isHor
      
      isHor=false
      if vElem.templateid and (vElem.templateid=="framing_horlong" or vElem.templateid=="framinghor1") then
        isHor=true
      end
    
      tblElemSortToName[elemTypeSort]=elemTypeName
      -- New logic 1/2020: Collect all boards if it is not cladding layer, if cladding layer collect all boards if no planks or if board is not cladding part
		  --if vElem.tblboards and (not vElem.tblplanks or vElem.layertypenum~=2) then
      if vElem.tblboards and (not gNoBoard or (elemTypeSort~="040" and elemTypeSort~="050")) then
        local tbl2
        
        if not vElem.tblplanks or vElem.layertypenum~=2 then
          tbl2=vElem.tblboards
        else
          -- Cladding layer and it has planks, skip all boards having cladding definition
          tbl2={}
          for k,v in pairs(vElem.tblboards) do
            ac_objectopen(v.guid)
            if ac_objectget("iPanelProfDX")==0 then
              tbl2[#tbl2+1]=v
            end
            ac_objectclose()
          end
        end
        CollectPlanksBoards( vElem, tbl2, tblPlanks, elemTypeSort )
      end

		  if vElem.tblplanks then
        CollectPlanksBoards( vElem, vElem.tblplanks, tblPlanks, elemTypeSort, isHor )
      end
    end
  end

  -- Sort by type, len
  local tblPlanksSort, bCladding
  
  tblPlanksSort={}
  i=0
  for k,v in pairs(tblPlanks) do
    i=i+1
    tblPlanksSort[i]=v
    
    bCladding=false
    if v.elemtypesort=="030" then
      bCladding=true
    end
    
    ac_objectopen(v.plankinfo.ptr)
    v.infotext=GetInfoText(v.plankinfo, bCladding)
    ac_objectclose()
  end

  table.sort( tblPlanksSort, CmpPlanks )
  return tblPlanksSort, tblElemSortToName, elemId
end


function ParseContentTags(str, v)
  str=ac_environment("strreplace", str, "#id#", v.id)
  str=ac_environment("strreplace", str, "#matwidth#", ac_environment("ntos", v.typewidth, "length", "dim"))
  str=ac_environment("strreplace", str, "#matheight#", ac_environment("ntos", v.typeheight, "length", "dim"))
  str=ac_environment("strreplace", str, "#len#", ac_environment("ntos", v.len, "length", "dim"))
  str=ac_environment("strreplace", str, "#pcs#", tostring(v.count))

  str=ac_environment("strreplace", str, "#typename#", v.typename)
  str=ac_environment("strreplace", str, "#matid#", v.matid)
  str=ac_environment("strreplace", str, "#elemgroup#", v.elemgroup)
  if string.find(str, "#matname#", 1, true) then
    local matinfo

    matinfo=af_request("singlemat", v.matid)
    if matinfo then
      str=ac_environment("strreplace", str, "#matname#", matinfo.name)
    else
      str=ac_environment("strreplace", str, "#matname#", v.typename)
    end
  end

  str=ac_environment("strreplace", str, "#cutinfo#", v.infotext)

  -- Parse #par:xxx#: First make find & replace table
  local pos, parname, parnameorg, parval, partype, tblReplace, pos2
        
  tblReplace={}
  pos=1
  while true do
    parname=string.match(str, "#par:(.-)#", pos)
    if not parname then
      break
    end
    parnameorg=parname
    pos=string.find(str, "#par:", pos, true)
    pos=pos+1
    
    -- Parameter type
    partype=""
    pos2=string.find(parname, ":", 1, true)
    if pos2 then
      partype=string.sub(parname,1,pos2-1)
      parname=string.sub(parname,pos2+1)
--ac_environment("tolog", string.format("partype=%s parname=%s", partype, parname))
    end
    
    parval=ac_getobjparam(v.plankinfo.ptr, parname)
    if not parval then
      parval=""
    else
      if partype=="lendim" then
        parval=ac_environment ("ntos", parval, "length", "dim")
      elseif partype=="lencalc" then
        parval=ac_environment ("ntos", parval, "length", "calc")
      else
        parval=tostring(parval)
      end
    end
    tblReplace[string.format("#par:%s#",parnameorg)]=parval
  end

  for pos,parval in pairs(tblReplace) do
    str=ac_environment("strreplace", str, pos, parval)
  end
  return str
end


-- Table copy values
function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end


-- nSeqNum: 0=tolpat, 1=juoksut, 2=TS-levyt, 3=verhoilu, (lopulta 4=eristeet), 4=sisäkoolaus
function DoCutList(nSeqNum, sSettingsLua)
	local	s, k, v, i, nElem, vElem, tblQuant, plankInfo, id, item
  local tblPlanks   -- Also boards, key="type typename length", fields: type (1=plank, 2=log object, 4=board), matid, typename, elemgroup, typewidth, typeheight, len (numeric), tblids=table of plank ids with id=key, count=number of this type
  local tblCollElemTypes, typeName
  local addMc, addLen
  local lang=GetLang()
  local filterFunc
  local collectExternal   -- nil=just direct owned planks
  local addExternal       -- nil=just direct owned planks (when calling filterFunc)
  
  addMc=0
  addLen=1
  gListSettings=nil
  if sSettingsLua and sSettingsLua~="" then
    -- String contains lua script that fills global gListSettings
    local f
    
--ac_environment("tolog", string.format("SETTINGS: %s", sSettingsLua))
    f=loadstring(sSettingsLua)
    if not f then
      ac_environment("tolog", string.format("Cut list: Bad settings Lua-script: %s", sSettingsLua))
    end
    f()   -- Creates gListSettings
    if gListSettings then
      if gListSettings.addmc and gListSettings.addmc==1 then
        addMc=1
      end
      if gListSettings.addlen and gListSettings.addlen==0 then
        addLen=0
      end
      filterFunc=gListSettings.funccollect
      collectExternal=gListSettings.collectexternal
      addExternal=gListSettings.addexternal
      if tostring(g_sepByLayer)~=tostring(gListSettings.sepbylayer) or tostring(g_clearElemRole)~=tostring(gListSettings.clearelemrole) then
        g_tblPlanksSort=nil     -- cause rebuilding of the list
      end
      g_sepByLayer=gListSettings.sepbylayer
      g_clearElemRole=gListSettings.clearelemrole
      g_collectAll=gListSettings.collectall
    end
  end

  if not g_tblPlanksSort or (gListSettings and gListSettings.resetlist) then
    g_tblPlanksSort, g_tblElemSortToName, g_elemId=DoTable(collectExternal)
  end
  
  if not nSeqNum then
    ac_environment("tolog", "DoCutList(nSeqNum): nSeqNum missing - old program version, update ArchiFrame")
    nSeqNum=0
  end
  
  -- what to collect
  
  tblCollElemTypes={}

  typeName=g_tblElemSortToName["001"]

  if gListSettings then
    -- NOP on purpose
  elseif gType and gType=="ffbc" then
    if nSeqNum==0 then
      typeName=g_tblElemSortToName["001"]
      tblCollElemTypes["001"]=true
      tblCollElemTypes["999"]=true
      addMc=1
    elseif nSeqNum==1 then
      typeName=g_tblElemSortToName["002"]
      tblCollElemTypes["002"]=true
      addMc=1   -- Juoksuihin myös työstöt 1/2018
    elseif nSeqNum==2 then
      -- Windshield boards
      typeName=g_tblElemSortToName["040"]
      tblCollElemTypes["040"]=true
      addLen=0
    elseif nSeqNum==3 then
      if lang=="fin" then
        typeName="ULKOKOOLAUS JA VERHOILU"
      else
        typeName="EXT STUD AND CLADDING"
      end
      tblCollElemTypes["030"]=true
      tblCollElemTypes["020"]=true
    else
      ac_environment("tolog", string.format("DoCutList(nSeqNum=%d): Bad nSeqNum - nothing collected", nSeqNum))
      typeName="NONE"
    end
  elseif not gSingle then
    if nSeqNum==0 then
      typeName=g_tblElemSortToName["001"]
      tblCollElemTypes["001"]=true
      tblCollElemTypes["999"]=true
      addMc=1
    elseif nSeqNum==1 then
      typeName=g_tblElemSortToName["002"]
      tblCollElemTypes["002"]=true
      addMc=1   -- Juoksuihin myös työstöt 1/2018
    elseif nSeqNum==2 then
      -- Windshield boards
      typeName=g_tblElemSortToName["040"]
      tblCollElemTypes["040"]=true
      addLen=0
    elseif nSeqNum==3 then
      typeName=g_tblElemSortToName["030"]
      tblCollElemTypes["030"]=true
      if gType and gType=="1.1" then
        -- ext studding will be collected first
        tblCollElemTypes["020"]=true
        if lang=="fin" then
          typeName="ULKOKOOLAUS"
        else
          typeName="EXT STUDDING"
        end
      end
    elseif nSeqNum==4 then
      typeName=g_tblElemSortToName["010"]
      tblCollElemTypes["010"]=true
    elseif nSeqNum==5 then
      typeName=g_tblElemSortToName["050"]
      tblCollElemTypes["050"]=true
      addLen=0
    else
      ac_environment("tolog", string.format("DoCutList(nSeqNum=%d): Bad nSeqNum - nothing collected", nSeqNum))
      typeName="NONE"
    end
  end

  if gSingle and addMc==0 then
    -- Add mc row if it is used
    for k,v in ipairs(g_tblPlanksSort) do
      if v.infotext and v.infotext~="" then
        addMc=1
        break
      end
    end
  end
  
  -- Filter planks now to be able to open them - soon table object will be opened  
  local   tblPlanksNow
  
  tblPlanksNow=g_tblPlanksSort
  if filterFunc then
    -- 1/2019 made mechanism: collect only needed ones now and prehaps resort
    local i2

    tblPlanksNow={}
    i2=0
    for k,v in ipairs(g_tblPlanksSort) do
      if (addExternal or not v.external) and filterFunc(v) then
        i2=i2+1
        tblPlanksNow[i2]=v
      end
    end
    
    table.sort( tblPlanksNow, CmpPlanks )      -- Resort since filter func may have changed elemtypesort
    
    if gListSettings.funcisless then
      -- New sorting
      local i3
      
      for i3=1,i2 do
         tblPlanksNow[i3]=deepcopy(tblPlanksNow[i3])          -- Since we wil set the count again
      end
      
      table.sort( tblPlanksNow, gListSettings.funcisless)     -- Resort with new filter func
      
      -- Then calculate per type since filter may have changed sorting tags of the plank
      local tblPlanksScan, i3
    
      tblPlanksScan=tblPlanksNow
      tblPlanksNow={}
    
      i3=1
      while tblPlanksScan[i3] do
         -- Scan if similar using the CmpPlanks-function
         tblPlanksNow[#tblPlanksNow+1]=tblPlanksScan[i3]
         while tblPlanksScan[i3+1] and gListSettings.funcisless(tblPlanksScan[i3], tblPlanksScan[i3+1])==false and gListSettings.funcisless(tblPlanksScan[i3+1], tblPlanksScan[i3])==false do
           -- Combine
           i3=i3+1
           tblPlanksNow[#tblPlanksNow].count=tblPlanksNow[#tblPlanksNow].count+tblPlanksScan[i3].count
         end
         i3=i3+1
      end
    end
  end

  local nRow, nHeightRows, rowHeight

  ac_objectopen(nil)      -- ### Table object opened
  
  -- Settings
  local bImperial
  
  rowHeight=0.170
  if gListSettings and gListSettings.rowheight then
    rowHeight=gListSettings.rowheight
  end
  
  ac_objectset("#pen", 1)
  bImperial=false
  nRow,s=ac_environment("units", "length", "dim")
  if nRow and nRow>2 and s~="mm" then
    bImperial=true
  end
  
  ac_objectset("iFontName", "Arial")
  ac_objectset("iRowHeight", rowHeight)
  ac_objectset("iMargin", rowHeight*0.1)
  ac_objectset("iColCount", 2+addMc+addLen)
  if addMc~=0 then
    if bImperial then
      ac_objectset("iColWidth", 0.31, 1)
      ac_objectset("iColWidth", 0.18, 2)
      ac_objectset("iColWidth", 0.06, 3)
      ac_objectset("iColWidth", 0.45, 4)
      ac_objectset("A", 5.0)
    else
      ac_objectset("iColWidth", 0.42, 1)
      ac_objectset("iColWidth", 0.10, 2)
      ac_objectset("iColWidth", 0.08, 3)
      ac_objectset("iColWidth", 0.40, 4)
      ac_objectset("A", 4.5)
    end
  else
    if addLen~=0 then
      ac_objectset("iColWidth", 0.70, 1)
      ac_objectset("iColWidth", 0.20, 2)
      ac_objectset("iColWidth", 0.10, 3)
    else
      -- Just two cols
      ac_objectset("iColWidth", 0.875, 1)
      ac_objectset("iColWidth", 0.125, 2)
    end
    ac_objectset("A", 3.5)
  end
  if gListSettings and gListSettings.tablewidth then
    ac_objectset("A", gListSettings.tablewidth)
  end
  
  if not typeName then
    typeName="(EMPTY)"
  end

  -- Title
  nRow=1
  nHeightRows=1
  if gListSettings and gListSettings.title then
    s=gListSettings.title
    if #tblPlanksNow>0 and tblPlanksNow[1].title then
      s=tblPlanksNow[1].title
    end
    s=ac_environment("strreplace", s, "#id#", g_elemId)
    ac_objectset("iRows", "<b><vtop><left><nolines><merge 4>" .. s, 1, 1)
  else
    if nSeqNum==0 then
      ac_objectset("iRows", "<mulheight 1><b><vtop><left><nolines><merge 4>" .. g_elemId .. " " .. typeName, 1, 1)
    else
      ac_objectset("iRows", "<b><vtop><left><nolines><merge 4>" .. typeName, 1, 1)
    end
   end
  
  nRow=nRow+1
  nHeightRows=nHeightRows+1
  if gListSettings and gListSettings.cols then
    -- All content defined by the caller
    local colk,colv,i
    
    i=0
    for colk,colv in ipairs(gListSettings.cols) do
      i=i+1
      ac_objectset("iColWidth", colv.width, colk)
      if not gListSettings.cols_skiptitle then
        ac_objectset("iRows", colv.title, nRow, colk)
      end
    end
    ac_objectset("iColCount", i)
    if gListSettings.cols_skiptitle then
      nRow=nRow-1   -- Will be preincremented for the first item to add
    end
  else
    -- Column headers (fixed legacy)
    if lang=="fin" then
      ac_objectset("iRows", "<b><left>Tyyppi", nRow, 1)
      ac_objectset("iRows", "<b>Pit", nRow, 2)
      ac_objectset("iRows", "<b>Kpl", nRow, 2+addLen)
      if addMc~=0 then
        ac_objectset("iRows", "<b><left>Työstöt", nRow, 4)
      end
    elseif lang=="swe" then
      ac_objectset("iRows", "<b><left>Material (ID)", nRow, 1)
      ac_objectset("iRows", "<b>L", nRow, 2)
      ac_objectset("iRows", "<b>St", nRow, 2+addLen)
      if addMc~=0 then
        ac_objectset("iRows", "<b><left>Bearbetning", nRow, 4)
      end
    elseif lang=="nor" then
      ac_objectset("iRows", "<b><left>Type", nRow, 1)
      ac_objectset("iRows", "<b>Len", nRow, 2)
      ac_objectset("iRows", "<b>Stk", nRow, 2+addLen)
      if addMc~=0 then
        ac_objectset("iRows", "<b><left>Kutt", nRow, 4)
      end
    else
      ac_objectset("iRows", "<b><left>Type", nRow, 1)
      ac_objectset("iRows", "<b>Len", nRow, 2)
      ac_objectset("iRows", "<b>Pcs", nRow, 2+addLen)
      if addMc~=0 then
        ac_objectset("iRows", "<b><left>Cut info", nRow, 4)
      end
    end
  end
  
  local   isFirst , prevelemtypesort
  local   tblTexts, tblCurrText, nTexts, addType
  local   str
  
  prevelemtypesort="__not_existing__"
  addEmpty=false
  addType=false
  
  local nResCode=0
  
  if gListSettings and gListSettings.funcgetrows then
    -- All content defined by the caller perhaps not related to planks & boards (accessories)
    local rows = gListSettings.funcgetrows()
    local colk,colv

    for k,v in ipairs(rows) do
        nHeightRows=nHeightRows+1
        nRow=nRow+1

        nResCode=1
        for colk,colv in ipairs(v.cols) do
          ac_objectset("iRows", colv, nRow, colk)
        end
    end

    nResCode=1    -- List created

  else
    for k,v in ipairs(tblPlanksNow) do
  --ac_environment("tolog", string.format("v.typename=%s\n", v.typename))
      if gSingle or tblCollElemTypes[v.elemtypesort] or filterFunc then
        nRow=nRow+1
        nHeightRows=nHeightRows+1

        if v.elemtypesort~=prevelemtypesort and (not gListSettings or not gListSettings.singlelist) then
          -- Element type changes
          prevelemtypesort=v.elemtypesort
          if addEmpty then
            ac_objectset("iRows", "<nolines><merge 4>", nRow, 1)
            nRow=nRow+1
            nHeightRows=nHeightRows+1
          end

          if addType then
            -- Add material type to col1
            local name=g_tblElemSortToName[prevelemtypesort]
          
            if not name then
              name=""
            end
            if v.title then
              name=v.title
            end
            ac_objectset("iRows", string.format("<left><nolines><merge 4><b>%s", name), nRow, 1)
            nRow=nRow+1
            nHeightRows=nHeightRows+1
          end
          addType=true
        end
    
        if gListSettings and gListSettings.cols then
          -- All content defined by the caller
          local colk,colv
    
          nResCode=1
          for colk,colv in ipairs(gListSettings.cols) do
            ac_objectset("iRows", ParseContentTags(colv.content, v), nRow, colk)
          end
        else
          -- Fixed legacy content
          -- Add material type to col1
          nResCode=1
          s=""
          if false and v.fillpen and v.fillpen>0 then
            -- Material fill pen to table background color
            s=string.format("<fillrgb %d>", v.fillpen)
          end
          str=v.col1str
          if v.type==1 and gListSettings and gListSettings.col1func_plank then
            str=gListSettings.col1func_plank(v)
          elseif v.type==1 and gListSettings and gListSettings.col1str_plank then
            -- Plank, parse it here
            str=ParseContentTags(gListSettings.col1str_plank, v)
          end
          ac_objectset("iRows", string.format("<left>%s%s", s, str), nRow, 1)
      
          -- Rest
          if addLen~=0 then
            ac_objectset("iRows", "<right>" .. Len2Str(v.len), nRow, 2)
          end
          ac_objectset("iRows", string.format("%d", v.count), nRow, 2+addLen)
    
          if addMc~=0 then
            str=v.infotext
            if v.elemtypesort=="001" then
              str=GetGroupedStudsStr(str, v.tblinfos)
            end
            ac_objectset("iRows", "<left>" .. str, nRow, 4)
          end
        end

        addEmpty=true
      end
    end
  end

  ac_objectset("B", nHeightRows*rowHeight)

  ac_objectclose()        -- ### Table object
  
  return nResCode
end

gLang=GetLang()           -- Make it global for 
]]>
        </cutlist_script_an>
        <!-- 2018_03 END -->


        <!-- Used for cutlists -->
        <cutlist tab1="0.5" tab2="0.8" tab3="1.2" tab4="1.5" tab5="1.8" boards="1" sortby="len" plankid="-" boardid="#">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
        </cutlist>

        <!-- Using table and script -->
        <cutlist_table tab1="0.5" tab2="0.8" tab3="1.2" tab4="1.5" tab5="1.8" boards="1" sortby="len" plankid="-" boardid="#" libpart="{9056D768-6A80-423F-B548-30D0A09D857F}-{DF0D0022-EA4D-4E1B-AFC8-69E66245A8DF}" libscript="cutlist_table_script">
          <elemparam name="pen">1</elemparam>
          <elemparam name="fontname">Arial</elemparam>
          <elemparam name="fontsize">2.5</elemparam>
          <elemparam name="fontstyle"></elemparam>
        </cutlist_table>


        <cutlist_table_script>
          <![CDATA[
-- tblguids   in, the planks/boards to process
-- tblPlanks  out, result is saved here
function CollectPlanksBoards( tblguids, tblPlanks )
  local i, v, plankInfo, id, s, pos, item, fillpen

  i=1
	while true do
		v=tblguids[i]
    i=i+1
		if v==nil then
			break
		end
        
		ac_objectopen(v.ptr)
		plankInfo=af_request("plankinfo")
		id=ac_objectget("#id")
    s="-"     -- This is the master plank not showing the short ID probably: ac_objectget("iShowIDSep")
    if plankInfo.type==4 then
      s="#"   -- board
    end
    fillpen=ac_objectget("iFillPen")
    ac_objectclose()
        
    if s and id then
      -- Skip element ID
      --pos=string.find(id, s, 1, true)   -- No reverse find in Lua
      pos=string.len(id)
      while pos>=1 do
        if string.sub(id,pos,pos)==s then
          break
        end
        pos=pos-1
      end
      if pos then
        id=string.sub(id, pos+1)
      end
    end

    s=string.format("%d %s %s", plankInfo.type, plankInfo.typename, ac_environment("ntos", plankInfo.len, "length", "work"))
    item=tblPlanks[s]
    if item==nil then
      item={}
      item.type=plankInfo.type
      item.typename=plankInfo.typename
      item.typewidth=plankInfo.width
      item.typeheight=plankInfo.height
      item.len=plankInfo.len
      item.fillpen=fillpen
      item.tblids={}
      item.count=0
      tblPlanks[s]=item
    end

    if item.tblids[id]==nil then
      item.tblids[id]=1
    else
      item.tblids[id]=item.tblids[id]+1
    end
    item.count=item.count+1
  end
end


function CmpPlanks( p1, p2 )
  if p1.type~=p2.type then
    return p1.type<p2.type      -- Plank=1, 4=board, planks first
  end
  
  if p1.type==4 then
    -- For boards the sort order is: typename, height, len
    if p1.typename~=p2.typename then
      return p1.typename<p2.typename
    end

    if math.abs(p1.typewidth-p2.typewidth)>0.001 then
      -- Actually for similar type boards the thickness should be the same
      return p1.typewidth>p2.typewidth
    end
    
    if math.abs(p1.typeheight-p2.typeheight)>0.001 then
      return p1.typeheight>p2.typeheight
    end

    if math.abs(p1.len-p2.len)>0.001 then
      return p1.len>p2.len
    end
    
    return false
  end
  
  -- Bigger first
  if math.abs(p1.typewidth-p2.typewidth)>0.001 then
    return p1.typewidth>p2.typewidth
  end

  if math.abs(p1.typeheight-p2.typeheight)>0.001 then
    return p1.typeheight>p2.typeheight
  end
  
  if p1.typename~=p2.typename then
    return p1.typename<p2.typename
  end

  if math.abs(p1.len-p2.len)>0.001 then
    return p1.len>p2.len
  end

  return false
end


function DoCutList()
	local	s, k, v, i, nElem, vElem, tblQuant, plankInfo, id, item, elemId
  local tblPlanks   -- Also boards, key="type typename length", fields: type (1=plank, 2=log object, 4=board), typename, typewidth, typeheight, len (numeric), tblids=table of plank ids with id=key, count=number of this type

  tblQuant=af_request("elem_quantities")

  elemId="(ID MISSING)"
  tblPlanks={}
	for nElem,vElem in ipairs(tblQuant.tblelems) do
    if vElem.elemtype=="core" then
      elemId=vElem.id
    end

		if vElem.tblboards then
      -- No boards: CollectPlanksBoards( vElem.tblboards, tblPlanks )
    end

		if vElem.tblplanks then
      CollectPlanksBoards( vElem.tblplanks, tblPlanks )
    end
  end

  -- Sort by type, len
  local tblPlanksSort
  
  tblPlanksSort={}
  i=0
  for k,v in pairs(tblPlanks) do
    i=i+1
    tblPlanksSort[i]=v
  end

  table.sort( tblPlanksSort, CmpPlanks )
  
  local nRow, nHeightRows, rowHeight

  ac_objectopen(nil)      -- ### Table object opened
  
  -- Settings
  rowHeight=0.100
  ac_objectset("#pen", 1)
  
  ac_objectset("iFontName", "Arial")
  ac_objectset("iRowHeight", rowHeight)
  ac_objectset("iMargin", rowHeight*0.1)
  ac_objectset("iColCount", 4)
  ac_objectset("iColWidth", 0.25, 1)
  ac_objectset("iColWidth", 0.25, 2)
  ac_objectset("iColWidth", 0.25, 3)
  ac_objectset("iColWidth", 0.25, 4)
  --ac_objectset("iColWidth", 0.25, 5)
  
  ac_objectset("A", 2)   -- (2.4385 m=8 feet)

  -- Title
  nRow=2
  nHeightRows=3   -- In row height
  ac_objectset("iRows", "<mulheight 2><u><b><vtop><left><nolines><merge 4>" .. elemId, 1, 1)
  ac_objectset("iRows", "<left><nolines><merge 4>", 2, 1)     -- Empty line

  -- Column headers
  nRow=nRow+1
  nHeightRows=nHeightRows+1
  ac_objectset("iRows", "MATERIAL", nRow, 1)
  ac_objectset("iRows", "PIECE", nRow, 2)
  ac_objectset("iRows", "QTY", nRow, 3)
  ac_objectset("iRows", "LENGTH", nRow, 4)
  --ac_objectset("iRows", "REMARKS", nRow, 5)
  
  -- All plank types
  local   prevtype, kid, vid, isFirst 
  
  prevtype="__not_existing__"
  addEmpty=false
  for k,v in ipairs(tblPlanksSort) do
--ac_environment("tolog", string.format("v.typename=%s\n", v.typename))
  
    nRow=nRow+1
    nHeightRows=nHeightRows+1
    if v.typename~=prevtype then
      if addEmpty then
        ac_objectset("iRows", "<nolines><merge 4>", nRow, 1)
        nRow=nRow+1
        nHeightRows=nHeightRows+1
      end

      addEmpty=true
      -- Add material type to col1
      s=""
      if v.fillpen and v.fillpen>0 then
        -- Material fill pen to table background color
        s=string.format("<fillrgb %d>", v.fillpen)
      end
      ac_objectset("iRows", string.format("%s%s", s, v.typename), nRow, 1)
      
      prevtype=v.typename
    end

    
    -- IDs
    id=""
    for kid,vid in pairs(v.tblids) do
      if id~="" then
        id=id .. " "
      end
      id=id .. kid
    end
    ac_objectset("iRows", id, nRow, 2)

    -- Rest
    ac_objectset("iRows", string.format("%d", v.count), nRow, 3)
    ac_objectset("iRows", "<right>" .. ac_environment("ntos", v.len, "length", "dim"), nRow, 4)
    ac_objectset("iRows", "~", nRow, 5)
  end
  ac_objectset("B", nHeightRows*rowHeight)

  ac_objectclose()        -- ### Table object
end
]]>
        </cutlist_table_script>

        
        <!-- Bottom wood markings -->
        <markings id="mark_default">
          <bottomwood>
            <stud line="3" id="2" idline="1" markxpos="2" markypos="1" marksize="0" marktextdir="1"></stud>
            <opening line="1" windowtext="Window [width]x[height]" doortext="Door [width]x[height]" windowtext_fin="Ikk [width]x[height]" doortext_fin="Ovi [width]x[height]" windowtext_nor="Vindu [width]x[height]" doortext_nor="Dør [width]x[height]" windowtext_swe="Fönster [width]x[height]" doortext_swe="Dörr [width]x[height]"></opening>
            <neighbour begtext="&lt;[id]" endtext="[id]&gt;" marksize="0" marktextdir="1"></neighbour>
          </bottomwood>
        </markings>

        <!-- Used for element stamp -->
        <elemstamp>
          <elemparam name="pen">1</elemparam>
          <objparam name="iFont">Arial</objparam>
          <objparam name="A">10</objparam>
          <objparam name="B">1</objparam>

          <objparam name="iName1">ID</objparam>
          <objparam name="iName2">Type</objparam>
          <objparam name="iName3">Date</objparam>
          <objparam name="iName4">Project</objparam>
          <objparam name="iName5">Designer</objparam>
          <objparam name="iName6">Project num</objparam>
          <objparam name="iName7"></objparam>
        </elemstamp>

        <!-- For projection tool / custom section types -->
        <freeprojections>
          <projection id="freeproj_default" name="Zero depth no dim lines" name_fin="Nollasyvyinen ilman mittoja" exclude="" boardpanels="*" depth="0" zoom="1">
          </projection>

          <projection id="freeproj_100_rot90" name="Zero depth no dim lines rotate +90" name_fin="Nollasyvyinen ilman mittoja kierto +90" exclude="" boardpanels="*" depth="0" zoom="1" rotate="90">
          </projection>

          <projection id="freeproj_100_rotm90" name="Zero depth no dim lines rotate -90" name_fin="Nollasyvyinen ilman mittoja kierto -90" exclude="" boardpanels="*" depth="0" zoom="1" rotate="-90">
          </projection>

          <projection id="wallsect_100_10" name="Zero depth with dim lines 100% v 1.0" name_fin="Nollasyvyinen mitoilla 100% v 1.0" exclude="" boardpanels="*" depth="0" zoom="1">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>

          <projection id="freeproj_100_rot90d" name="Zero depth dim lines rotate +90" name_fin="Nollasyvyinen mitoilla kierto +90" exclude="" boardpanels="*" depth="0" zoom="1" rotate="90">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>

          <projection id="freeproj_100_rotm90d" name="Zero depth dim lines rotate -90" name_fin="Nollasyvyinen mitoilla kierto -90" exclude="" boardpanels="*" depth="0" zoom="1" rotate="-90">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>

          <projection id="wallsect_core_100_10" name="Zero depth core only with dim lines 100% v 1.0" name_fin="Nollasyvyinen pelkkä runko mitoilla 100% v 1.0" exclude="*" include="core" depth="0" zoom="1">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>

          <projection id="wallsect_200_10" name="Zero depth with dim lines 200% v 1.0" name_fin="Nollasyvyinen mitoilla 200% v 1.0" exclude="" boardpanels="*" depth="0" zoom="2">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>

          <projection id="wallsect_core_200_10" name="Zero depth core only with dim lines 200% v 1.0" name_fin="Nollasyvyinen pelkkä runko mitoilla 200% v 1.0" exclude="*" include="core" depth="0" zoom="2">
            <dimlines>
              <dimline ref="dim_wallsect_nowin_horint_10"></dimline>
            </dimlines>
          </projection>
        </freeprojections>
        
        <!-- Special attach types to set settings for projection planks -->
        <spec_attachtypes>
          <spec_attachtype name="Special projection to show weatherboards with short ID">
            <newelemprojside>
              <objparam name="iShowID">1</objparam>
              <objparam name="iShowLen">0</objparam>
              <objparam name="iIDPlace">0</objparam>
              <objparam name="iShowIDSep">-</objparam>
            </newelemprojside>
          </spec_attachtype>
        </spec_attachtypes>
        
        <!-- To add special door/window weight calculation rules -->
        <doorwinweight>
          <![CDATA[
-- Dumps given variable into string
function DumpTblInt(o, nIndent)
  local s,k,v
  
  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end
    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end
    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    if type(o) == 'string' then
    	s = '"' .. tostring(o) .. '"'
    elseif type(o) == 'number' then						-- Less digits to be able to compare results
    	s = '"' .. string.format("%0.4f", o) .. '"'
    else
    	s = tostring(o)
    end
  end
  return s
end


-- Dumps a table to the log window with indentation.
function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end          
   

-- Script loaded once and called for each opening
-- Return 0.0 to have default weight calculation, otherwise returned value will be used
function OnCalcDoorWinWeight(guid)
  if false then
    local res
    
    res=ac_elemget(guid, "props=1,ifc=1")
    
    DumpTbl(res.props)
    DumpTbl(res.ifc)
    --return 999
  end
  
  return 0.0
end
]]>
        </doorwinweight>
      </presettings>

      <!-- Scripts used many times -->
      <scripts>
        <script id="dim_scripts">
          <![CDATA[
-- Returns cos angle of the vectors if normalized
function CalcDot3D( x1, y1, z1, x2, y2, z2 )
	return x1 * x2 + y1 * y2 + z1 * z2;
end


-- tblSource is plankinfo for soure coordinate world
-- tblCam is plankinfo for camera/target world (from dim_camera)
-- Returns matrix[12] to be used in following functions
function MatInitTran(tblSource, tblCam)
  local tranMat, dx, dy, dz
  
  tranMat=ac_geo("calctranworld3", tblSource.origc, tblSource.vecx, tblSource.vecy, tblSource.vecz, tblCam.begc, tblCam.vecx, tblCam.vecy, tblCam.vecz)
  
  -- Previous calculated move values only for global coordinate system, change relative to tblCam
  dx=tranMat[4]
  dy=tranMat[8]
  dz=tranMat[12]

  tranMat[4]=CalcDot3D(dx, dy, dz, tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z)
  tranMat[8]=CalcDot3D(dx, dy, dz, tblCam.vecy.x, tblCam.vecy.y, tblCam.vecy.z)
  tranMat[12]=CalcDot3D(dx, dy, dz, tblCam.vecz.x, tblCam.vecz.y, tblCam.vecz.z)

  return tranMat
end


-- Returns VECTOR x,y,z transformed
function MatTransformVec( x, y, z, tblTran )
	local xnew, ynew, znew

	xnew=x*tblTran[1]+ y*tblTran[2]+ z*tblTran[3]
	ynew=x*tblTran[5]+ y*tblTran[6]+ z*tblTran[7]
	znew=x*tblTran[9]+ y*tblTran[10]+ z*tblTran[11]
	return xnew, ynew, znew
end


-- Returns point x,y,z transformed
function MatTransformPt( x, y, z, tblTran )
  x,y,z=MatTransformVec( x, y, z, tblTran )
	return x+tblTran[4], y+tblTran[8], z+tblTran[12]
end


-- Segment handling beg ***
-- Data is 1-based table of structs having fields x1,x2
function SegInitSingle(x1, x2)
  local tblCoords,t

  t={}
  t.x1=x1
  t.x2=x2
  tblCoords={}
  tblCoords[1]=t
  return tblCoords
end

-- Returns new segment array taking x1,x2 away from seg
function SegDifference(seg, x1, x2)
  local u1, curr1, currx1, currx2
  local tblDest, destn, t
  local eps=0.0005

  tblDest={}
  destn=0
  for u1,curr1 in ipairs(seg) do
    currx1=curr1.x1
    currx2=curr1.x2
    if currx1+eps>x2 or currx2-eps<x1 then
      -- No removing, add as whole
      t={}
      t.x1=currx1
      t.x2=currx2
      destn=destn+1
      tblDest[destn]=t
    else
      -- Perhaps overlaps, add perhaps split parts
      if currx1<x1-eps then
        t={}
        t.x1=currx1
        t.x2=x1
        destn=destn+1
        tblDest[destn]=t
      end
      
      if currx2>x2+eps then
        t={}
        t.x1=x2
        t.x2=currx2
        destn=destn+1
        tblDest[destn]=t
      end
    end
  end
  
  return tblDest
end

function SegDump(prompt, seg)
  local u1, curr1, s
  
  s=prompt
  for u1,curr1 in ipairs(seg) do
    s=s..string.format(" x1=%f x2=%f", curr1.x1, curr1.x2)
  end
  ac_environment("tolog", s)
end

-- Segment handling end ***


-- Dim line creator uses to find just first stud in stud groups
function FindCoreStudGroupsForDim()
  local i, n, s
  local tblRes, tbl, info, elemdata, incDim
  local tblProjInfo, projinfo						-- Projection infos for owning elements, key=element guid
  local typetag
  local tblCam
  local mirrorx                         -- Back projection? nil=not known, false=not, true=yes
  
  tblCam=af_request("dim_camera")
  tblRes={}
  tblProjInfo={}
  n=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo")
    tbl=ac_objectget("#af_elemdata")   -- To get typetag also
    typetag=nil
    if tbl then
      typetag=tbl.typetag
    end
    incDim=ac_objectget("iIncludeDim")
    if not incDim then
      incDim=1
    end
    ac_objectclose()
	  if info.ownerelemguid==nil and info.masterelemguid then
		  -- Take the 3D piece
		  info=af_request("plankinfo", info.masterelemguid)
	  end
    if incDim>0 and info.type==1 and info.ownerelemguid then   -- type 1 is plank
      --Not available since may be owned by any element object in the group: elemdata=ac_objectget("#af_elemdata")   
  	  projinfo=tblProjInfo[info.ownerelemguid]
	    if not projinfo then
		    projinfo=af_request("plankinfo", info.ownerelemguid)
		    projinfo.vecz,projinfo.vecy=projinfo.vecy, projinfo.vecz			-- Swap these for projection world
		    tblProjInfo[info.ownerelemguid]=projinfo
	    end

	    -- Get it again to get elemdata
	    info=af_request("plankinfo", info.guid, projinfo)
      elemdata=info.elemdata
      if math.abs(elemdata.x1-elemdata.x2)<0.001 and (typetag==nil or typetag=="core") then   -- and math.abs(elemdata.z1-elemdata.z2)<0.001 and elemdata.y2-elemdata.y1>0.01 and elemdata.y1<0.2 then
        -- Check if back projection
        if mirrorx==nil then
          local geo
          
          mirrorx=false
          geo=af_request("elem_quantities", info.ownerelemguid, 0).geo
          if CalcDot3D(geo.vecx.x, geo.vecx.y, geo.vecx.z, tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z)<-0.9 then
            mirrorx=true
          end
        end
      
        tbl={}
        tbl.index=i
        tbl.anchorfirst=1     -- No need to mirror this one since projection knows which is left in projected pieces
        tbl.anchormid=0
        tbl.anchorlast=0
        tbl.elemdata=elemdata
        n=n+1
        tblRes[n]=tbl
      end
    end
  end

--ac_environment("tolog", string.format("mirrorx=%s", tostring(mirrorx)))
  
  local tblRes2, i1, i2, bx2
  
  table.sort( tblRes,  function(p1, p2)
                            return p1.elemdata.bx1<p2.elemdata.bx1
                          end )

  -- Remove touching pieces
  tblRes2={}
  i2=0
  i1=1
  while i1<=n do
    i2=i2+1
    tblRes2[i2]=tblRes[i1]
    bx2=tblRes2[i2].elemdata.bx2+0.005      -- 0.005 is min space between planks set in own elem rules
    i1=i1+1
    while i1<=n do
      if tblRes[i1].elemdata.bx1>bx2+0.001 then
        break
      end
      if tblRes[i1].elemdata.bx2>bx2 then
        bx2=tblRes[i1].elemdata.bx2+0.005   -- 0.005 is min space between planks set in own elem rules
      end
      
      if mirrorx then
        -- Take last one
        tblRes2[i2]=tblRes[i1]
      end

      i1=i1+1
    end
  end

  return tblRes2
end


-- MODULES

function MakeTextXml(content, textid)
  local s
  s=   "<text content=\"" .. content .. "\" textid=\"" .. textid .. "\" anchor=\"6\" marg=\"0.2\">\n"
  s=s.."  <elemparam name=\"pen\">1</elemparam>\n"
  s=s.."  <elemparam name=\"fontname\">ARIAL</elemparam>\n"
  s=s.."  <elemparam name=\"fontsize\">2.5</elemparam>\n"
  s=s.."  <elemparam name=\"fontstyle\"></elemparam>\n"
  s=s.."  <layer></layer>\n"
  s=s.."</text>\n"
  return s
end


function AddModuleStuds(tblDims, ndims, tblMod, sDim, bOnlyFirstLast)
  local t, s, i, v, tblPoints, npoints

  s=sDim .. "\n"
  s=s..MakeTextXml(tblMod.name, 19-ndims)
  s=s.."</dimline>"
  
  
  tblPoints={}
  npoints=0
  
  if bOnlyFirstLast then
    t={}
    t.index=tblMod.x1plank
    t.anchorfirst=true
    npoints=npoints+1
    tblPoints[npoints]=t

    t={}
    t.index=tblMod.x2plank
    t.anchorlast=true
    npoints=npoints+1
    tblPoints[npoints]=t
    
  else
    for i,v in ipairs(tblMod.planks) do
      t={}
      t.index=v
      t.anchorfirst=true
      npoints=npoints+1
      tblPoints[npoints]=t
    end
  end
  
  t={}
  t.xmldim=s
  t.dimpoints=tblPoints
  ndims=ndims+1
  tblDims[ndims]=t
  return ndims
end


function AddModules(sInclude, tblExclude, bOnlyFirstLast)
  local i, s, info, t
  local tblModules, elemdata

  -- First find all module names, table has module's bounding box
  tblModules={}
  for i=1,gnPlanks do
    tbl=nil
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo")
    if info.type==1 then   -- is it a plank?
      elemdata=ac_objectget("#af_elemdata")
      s=ac_objectget("iElemModule")
      if elemdata and math.abs(elemdata.x2-elemdata.x1)<0.0005 and s and s~="" then
		    -- It is vertical in element
        if (not sInclude or string.match(elemdata.typetag, sInclude)) and (not tblExclude or not tblExclude[elemdata.typetag]) then
			    t=tblModules[s]
			    if not t then
				    t={}
            t.nplanks=1
            t.planks={}
            t.planks[t.nplanks]=i
            t.name=s
				    t.x1=elemdata.bx1
				    t.y1=elemdata.by1
				    t.x2=elemdata.bx1
				    t.y2=elemdata.by2
            t.x1plank=i
            t.x2plank=i
				    tblModules[s]=t
			    else
            t.nplanks=t.nplanks+1
            t.planks[t.nplanks]=i
				    if elemdata.bx1<t.x1 then
              t.x1plank=i
					    t.x1=elemdata.bx1
				    end
				    if elemdata.by1<t.y1 then
					    t.y1=elemdata.by1
				    end
				    if elemdata.bx2>t.x2 then
					    t.x2=elemdata.bx2
              t.x2plank=i
				    end
				    if elemdata.by2>t.y2 then
					    t.y2=elemdata.by2
				    end
			    end
        end
      end
		end
	  ac_objectclose()
	end
  
  -- Add dim lines for each module, sort by x1
  local tblModulesSort, k, v
  
  i=0
  tblModulesSort={}
  for k,v in pairs(tblModules) do
    i=i+1
    tblModulesSort[i]=v
  end
  
	table.sort(tblModulesSort, function (n1, n2)
    return n1.x1 < n2.x1
	end)
  
  -- Then add each module
  local prevMod
  local tblDims, ndims, s2
 
  ndims=0
  tblDims={}
  for i,v in ipairs(tblModulesSort) do
    s="0"
    if not prevMod or prevMod.x2>v.x1 then
      s="0.25"
    end
    s2=string.format("<dimline side=\"bottom\" margin=\"%s\" elemvecx=\"1\">\n", s)
    s2=s2.."<dimlinesettings><elemparam name=\"dimensiontype\">cumulative</elemparam><elemparam name=\"markertype\">5</elemparam></dimlinesettings>"

    ndims=AddModuleStuds(tblDims, ndims, v, s2, bOnlyFirstLast)
    prevMod=v
  end
  
  return tblDims
end


-- bOnlyFirstLast true=add just first and last items - not every stud, false/nil=the default - add all
function AddCoreModules(bOnlyFirstLast)
	local tblExclude
	
	tblExclude={}
	tblExclude["extstud"]=true
	tblExclude["extstud2"]=true
	tblExclude["extstud3"]=true
	tblExclude["extstud4"]=true
	tblExclude["intstud"]=true
	tblExclude["intstud2"]=true
	tblExclude["intstud3"]=true
	tblExclude["intstud4"]=true
	return AddModules("core", tblExclude, bOnlyFirstLast)
end


function AddNoCoreModules()
	local tblExclude
	
	tblExclude={}
	tblExclude["core"]=true
	return AddModules(nil, tblExclude)
end


-- Dim line creator uses to all horizontal battens plus lowest horizontal core piece
function FindHorBattensPlusBottomFrame()
  local i, group, n, layertype, minz
  local tblRes, tbl, tblElems, info, add, tblCoreMin

  tblRes={}
  tblElems={}        -- key=guid, data=layer type
  tblCoreMin=nil
  n=0
  minz=1E100
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo")
    if info.masterelemguid then
      -- Need to open the 3d piece to get element information
      ac_objectclose()
      ac_objectopen(info.masterelemguid)
      info=af_request("plankinfo")
    end

    group=ac_objectget("iElemGroup")
    ac_objectclose()
    if info and info.type==1 and info.ownerelemguid and math.abs(info.vecx.z)<0.001 and group then   -- Horizontal piece
      layertype=tblElems[info.ownerelemguid]
      if not layertype then
        local q
        
        q=af_request("elem_quantities", info.ownerelemguid, 0)
        layertype=q.tblelems[1].elemtype
        tblElems[info.ownerelemguid]=layertype
      end

      add=false
      if layertype=="core" then
        if string.match(group, "^bottom_force%.*") and info.begc.z<minz then
          minz=info.begc.z
          tblCoreMin={}
          tblCoreMin.index=i
          tblCoreMin.anchorfirst=1
          tblCoreMin.anchormid=0
          tblCoreMin.anchorlast=0
        end
      else
        -- Should be hor studding, add piece
        add=true
      end
      if add then
        tbl={}
        tbl.index=i
        tbl.anchorfirst=1
        tbl.anchormid=0
        tbl.anchorlast=0
        n=n+1
        tblRes[n]=tbl
      end
    end
  end

  if tblCoreMin then
    n=n+1
    tblRes[n]=tblCoreMin
  end
  return tblRes
end


-- Dim line creator uses to all vertical battens plus leftmost horizontal core piece
function FindVertBattensPlusLeftFrame()
  local i, group, n, layertype, minx
  local tblRes, tbl, tblElems, info, add, tblCoreMin, tblCam

  tblRes={}
  tblCoreMin=nil
  n=0
  minx=1E100
  tblCam=af_request("dim_camera")
  
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo", nil, tblCam)
    if info.masterelemguid then
      -- Need to open the 3d piece to get element information
      ac_objectclose()
      ac_objectopen(info.masterelemguid)
      info=af_request("plankinfo", nil, tblCam)
    end

    group=ac_objectget("iElemGroup")
    elemdata=ac_objectget("#af_elemdata")
    ac_objectclose()

    if info and info.type==1 and info.ownerelemguid and elemdata and math.abs(info.vecx.z)>0.999 and group then   -- Vertical piece
      layertype=elemdata.typetag
      add=false
      if layertype=="core" then
        if info.elemdata.x1<minx then
          minx=info.elemdata.x1
          tblCoreMin={}
          tblCoreMin.index=i
          tblCoreMin.anchorfirst=1
          tblCoreMin.anchormid=0
          tblCoreMin.anchorlast=0
        end
      else
        -- Should be vert studding, add piece
        add=true
      end
      if add then
        tbl={}
        tbl.index=i
        tbl.anchorfirst=1
        tbl.anchormid=0
        tbl.anchorlast=0
        n=n+1
        tblRes[n]=tbl
      end
    end
  end

  if tblCoreMin then
    n=n+1
    tblRes[n]=tblCoreMin
  end
  return tblRes
end


function FindStudsInsu()
  local i, n, s
  local tblRes, tbl, info, elemdata
  local typetag
  local elemGuid
  local tblCam
  
  tblCam=af_request("dim_camera")
  tblRes={}
  n=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo", nil, tblCam)
    tbl=ac_objectget("#af_elemdata")   -- To get typetag also
    typetag=nil
    if tbl then
      typetag=tbl.typetag
    end
    ac_objectclose()
	  if info.ownerelemguid==nil and info.masterelemguid then
		  -- Take the 3D piece
		  info=af_request("plankinfo", info.masterelemguid, tblCam)
	  end
    if info.type==1 and info.ownerelemguid then   -- type 1 is plank
      elemdata=info.elemdata
      if math.abs(elemdata.x1-elemdata.x2)<0.001 and (math.abs(elemdata.rotangle)<1 or math.abs(elemdata.rotangle-180)<1 or math.abs(elemdata.rotangle+180)<1) and (typetag==nil or typetag=="core") then   -- and math.abs(elemdata.z1-elemdata.z2)<0.001 and elemdata.y2-elemdata.y1>0.01 and elemdata.y1<0.2 then
        tbl={}
        tbl.index=i
        tbl.anchorfirst=1
        tbl.anchorfirstnextempty=1
        tbl.anchormid=0
        tbl.anchorlast=1
        tbl.elemdata=elemdata
        n=n+1
        tblRes[n]=tbl
        elemGuid=info.ownerelemguid
      end
    end
  end
  
  if elemGuid then
    -- Check if insulation weight in the layer
    local q
    
    q=af_request("elem_quantities", elemGuid, 0)
    if q and q.tblelems[1] then
      q=q.tblelems[1]
	    if q.xmlutf8 then
		    s=string.match(q.xmlutf8, " insulationkg=\"(.-)\"")
        --ac_environment("tolog", string.format("insulationkg=%s", tostring(s)))
        if s and tonumber(s)~=nil and tonumber(s)==0.0 then
          -- No insulation
          tbl={}
          return tbl
        end
	    end
    end
  end
  
  -- Addition 9/2021: Skip dimensions with value less than 10 mm (for duplicated studs with or without gap)
  local t1, t2
  
	table.sort(tblRes, function (n1, n2)
    return n1.elemdata.bx1 < n2.elemdata.bx1
	end)
  
  i=1
  while true do
    t1=tblRes[i]
    t2=tblRes[i+1]
    if not t2 then
      break
    end

    if t1.elemdata.bx2+0.01549 > t2.elemdata.bx1 and t1.elemdata.bx2+0.0001 < t2.elemdata.bx1 then
--ac_environment("tolog", string.format("t1.elemdata.bx2=%f t2.elemdata.bx1=%f", t1.elemdata.bx2, t2.elemdata.bx1))
    
      t1.anchorlastnextempty=1
    end
    i=i+1
  end

  return tblRes
end

function IsCoreBottom(elemgroup)
  return string.match(elemgroup, "^bottom_force.*") or string.match(elemgroup, "^2ndbottom_force.*")
end

function IsCoreTop(elemgroup)
  return string.match(elemgroup, "^top_force.*") or string.match(elemgroup, "^2ndtop_force.*")
end


function LineInPoly(poly,x1,y1,x2,y2)
  local res

  res=ac_geo("linepolyx", x1, y1, x2, y2, poly.poly)
  return res
end


-- Finds place for dim line that is not covered by studs
-- width  How much space to reserve for the dim line
-- tblStuds Collected studs to avoid
function FindInsuDimPos(x1, x2, y1, y2, width, tblStuds)
  local k,v,e,orgx

  -- Dim line starts from x1 and ends to x1+width
  orgx=x1
  for k,v in ipairs(tblStuds) do
    e=v.elemdata
    if e.bx2>x1 and e.bx1<x1+width and e.by2>y1 and e.by1<y2 then
      -- Collision, move after the stud. Studs are ordered by xc so no need to reset the loop
      x1=e.bx2
      if x1>x2 then
        return orgx+width   -- Revert to x1 if no place
      end
    end
  end

  return x1+width
end


-- Checks if given polygon edge intersects dim line x1,y1 -> x2,y2 and at intersection if yes
function CheckPolyEdge(pt1, pt2, tblPts, x1, y1, x2, y2)
  local xx, yy, sideoff, dist, len
  local eps=0.0005

  xx,yy=ac_geo("linex", pt1.x, pt1.y, pt2.x, pt2.y, x1, y1, x2, y2)
  if not xx then
    return
  end
  
  sideoff,dist,len=ac_geo("linedist", x1, y1, x2, y2, xx, yy)
  if dist<-eps or dist>len+eps then
    return false
  end
  
  sideoff,dist,len=ac_geo("linedist", pt1.x, pt1.y, pt2.x, pt2.y, xx, yy)
  if dist<-eps or dist>len+eps then
    return false
  end
  
  -- Add xx,yy since inside both lines
  local t
  
  t={}
  t.x=xx
  t.y=yy

--ac_environment("tolog", string.format("xx=%f, yy=%f, pt1.x=%f, pt1.y=%f, pt2.x=%f, pt2.y=%f, x1=%f, y1=%f, x2=%f, y2=%f", xx, yy, pt1.x, pt1.y, pt2.x, pt2.y, x1, y1, x2, y2))
  tblPts[#tblPts+1]=t
end


-- Scans all insulation polygons if any of their edges intersect with given dim line and puts intersections into tblPts
function AddInsuPoints(tblInsu, tblPts, x1, y1, x2, y2) 
  local kinsu, vinsu, klist,vlist, kpoint, vpoint, kscan, vscan, found, begpt, prevpt

  -- All insulation (polygons)
  for kinsu,vinsu in ipairs(tblInsu) do
--ac_environment("tolog", string.format("x1=%f, y1=%f, x2=%f, y2=%f, vinsu.x1=%f, vinsu.y1=%f, vinsu.x2=%f, vinsu.y2=%f vinsu.poly=%s", x1,y1,x2,y2, vinsu.x1, vinsu.y1, vinsu.x2, vinsu.y2, tostring(vinsu.poly)))
    -- LineInPoly takes polylist
    if LineInPoly(vinsu,x1,y1,x2,y2) then
      for klist,vlist in ipairs(vinsu.poly) do
        begpt=vlist[1]
        prevpt=nil
        for kpoint,vpoint in ipairs(vlist) do
          if prevpt then
            CheckPolyEdge(prevpt, vpoint, tblPts, x1, y1, x2, y2)
          end
          prevpt=vpoint
          
          if vpoint.isendcontour then
            -- Line from current to saved beg pt
            CheckPolyEdge(vpoint, begpt, tblPts, x1, y1, x2, y2)
            prevpt=nil
          end
      
          if vpoint.isbeghole then
            begpt=vpoint
          end
        end
      end
    end
  end
end


-- Makes vertical insulation dimension lines
function InsuDimLinesVert()
  local i, info, a1, a2
  local tbl, elemdata, tblVertx, nvertx, tblStuds, nstuds, tblPoly
  local tblInsu, ninsu    -- Collect all insulation boards, table contains polygon
  local tblCam=af_request("dim_camera")     -- Use camera to judge if piece is horizontal or not
  local eps=0.0005


  -- Collect all vertical planks and studs, also boards used to model insulation
  tblVertx={}
  nvertx=0
  tblStuds={}
  nstuds=0
  tblInsu={}
  ninsu=0

  for i=1,gnPlanks do
    ac_objectopen(string.format("#!%d",i))
    info=af_request("plankinfo")
    elemdata=ac_objectget("#af_elemdata")
    
    if info.type==1 and info.ownerelemguid and elemdata then
      -- Plank in element
      tbl={}
      tbl.index=i
      tbl.info=info
      tbl.elemdata=elemdata
      
      a1=CalcDot3D(tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z, info.vecx.x, info.vecx.y, info.vecx.z)
      a2=CalcDot3D(tblCam.vecz.x, tblCam.vecz.y, tblCam.vecz.z, info.vecz.x, info.vecz.y, info.vecz.z)
      if math.abs(a1)>0.999 and math.abs(a2)>0.999 then
        -- Horizontal piece (not a beam)
        nvertx=nvertx+1
        tblVertx[nvertx]=tbl
      elseif math.abs(a1)<0.001 then
        -- Stud
        nstuds=nstuds+1
        tblStuds[nstuds]=tbl
      end
      
      if not tblPoly then
        -- Get owner element's polygon to find openings
        tbl={}
        tbl.side=2
        tbl.givelist=1
        tblPoly=af_request("getpoly", tbl, info.ownerelemguid)
--ac_environment("tolog", string.format("poly=%s", tostring(tblPoly)))
      end
    elseif info.type==4 and info.ownerelemguid and elemdata then
       -- Board, check if insulation
       tbl=ac_objectget("iTypeCode")
       if tbl and tbl==200 then
        tbl={}
        tbl.side=2
        tbl.givelist=1
        tbl.camera=tblCam
        ninsu=ninsu+1
        tblInsu[ninsu]=af_request("getpoly", tbl)
       end
    end

    ac_objectclose()
  end

  -- Sort vertical pieces by y, x
	table.sort(tblVertx, function (n1, n2)
    local d
    
    d=n1.elemdata.by1 - n2.elemdata.by1
    if math.abs(d)>eps then
      return d<0
    end
    return n1.elemdata.bx1 < n2.elemdata.bx1
	end)

  -- Studs by x
	table.sort(tblStuds, function (n1, n2)
    return n1.elemdata.bx1 < n2.elemdata.bx1
	end)


  -- Process all collected vertical studs
  local v1,i2,v2                    -- Handled planks are marked here, key is plank index and value is true for handled ones
  local tblDims, ndims
  
  tblDims={}
  ndims=0

  for i,v1 in ipairs(tblVertx) do
    -- Find pieces above current one
    local tblSeg, tblHandled

    tblHandled={}
    tblSeg=SegInitSingle(v1.elemdata.bx1, v1.elemdata.bx2)
    i2=i+1
    while i2<=nvertx do
      v2=tblVertx[i2]
      if v2.elemdata.by1-eps<v1.elemdata.by2 then
--SegDump("PRE", tblSeg)
        tblSeg=SegDifference(tblSeg, v2.elemdata.bx1, v2.elemdata.bx2)
--SegDump(string.format("POST (diff %f %f)", v2.elemdata.bx1, v2.elemdata.bx2), tblSeg)
      else
        break     -- Sorted by y
      end
        
      i2=i2+1
    end
      
    -- Find closest upper piece from current segments (i2 is valid now)
    local kseg,vseg, i2org, x1, x2, iseg
      
    i2org=i2
    iseg=1
    while iseg<=#tblSeg do
      x1=tblSeg[iseg].x1
      x2=tblSeg[iseg].x2
      i2=i2org
      while i2<=nvertx do
        v2=tblVertx[i2]
        if x1<v2.elemdata.bx2-eps and x2>v2.elemdata.bx1+eps then
          -- There is a pair, add dim line if not at empty space
          if v2.elemdata.bx1>x1 then
            x1=v2.elemdata.bx1
          end
          if v2.elemdata.bx2<x2 then
            x2=v2.elemdata.bx2
          end
            
          local x=(x1+x2)*0.5
            
          if LineInPoly(tblPoly, x, v1.elemdata.by2, x, v2.elemdata.by1) and not tblHandled[v2.index] then
            local t, tblPts
            
            tblPts={}
            
            t={}
            t.index=v1.index
            t.anchorlast=true
            tblPts[1]=t
            
            t={}
            t.index=v2.index
            t.anchorfirst=true
            tblPts[2]=t

            AddInsuPoints(tblInsu, tblPts, x, v1.elemdata.by2, x, v2.elemdata.by1)
--ac_environment("tolog", string.format("DIM x1=%f x2=%f", x1, x2))

            t={}
            t.xmldim=string.format("<dimline side=\"left\" marginproj=\"%1.3f\" elemvecy=\"1\"/>", -FindInsuDimPos(x1, x2, v1.elemdata.by2, v2.elemdata.by1, 0.2, tblStuds) )
            t.dimpoints=tblPts

            ndims=ndims+1
            tblDims[ndims]=t
          end

          tblHandled[v2.index]=true
--SegDump("PRE2", tblSeg)
          tblSeg=SegDifference(tblSeg, x1, x2)
--SegDump(string.format("POST (diff %f %f)", x1, v2.elemdata.bx2), tblSeg)
          break
        end
        
        i2=i2+1
      end
      if i2>nvertx then
        iseg=iseg+1   -- No matching pair found, scan next segment
      end
    end
      
--ac_environment("tolog", string.format("iseg=%d #tblSeg=%d", iseg, #tblSeg))
  end
  
  return tblDims
end


-- margin Distance between dim lines
-- tblPrevDim, table of previous anchor x-coords (fields left and right). Skip dim if same value as previously. Also fields marginleft, marginright telling where to place next dim line
function AddTopDims(tblCore, tblNow, tblDims, ndims, lineSide, margin, tblPrevDim, flipx)
--ac_environment("tolog", string.format("%s flipx=%s tblNow.first.elemdata.bx1=%f tblNow.first.elemdata.bx2=%f tblCore.first.elemdata.bx1=%f tblCore.first.elemdata.bx2=%f", tblNow.typetag, tostring(flipx), tblNow.first.elemdata.bx1, tblNow.first.elemdata.bx2, tblCore.first.elemdata.bx1, tblCore.first.elemdata.bx2))

  if tblCore.first==nil or tblNow.first==nil then
    return ndims
  end

--ac_environment("tolog", "1")

  local s, t, tblPts, pt, npt, xnow, xcore
  
  -- Offset left
  xnow=tblNow.first.elemdata.bx1
  xcore=tblCore.first.elemdata.bx1
  if flipx then
    -- Need to swap x1,x2 also
    xnow=tblNow.first.elemdata.bx2
    xcore=tblCore.first.elemdata.bx2
  end
  if math.abs(xnow - xcore)>0.001 then
    tblPts={}
    npt=0

    -- Curr min
    pt={}
    pt.index=tblNow.first.index
    pt.anchorfirst=1
    npt=npt+1
    tblPts[npt]=pt

    -- Core min
    pt={}
    pt.index=tblCore.first.index
    pt.anchorfirst=1
    npt=npt+1
    tblPts[npt]=pt
    
    if tblPrevDim.left==nil or math.abs(tblPrevDim.left-xnow)>0.0005 then
      tblPrevDim.left=xnow
      s=string.format("<dimline side=\"%s\" marginproj=\"%.2f\" elemvecx=\"1\"/>", lineSide, tblPrevDim.marginleft)
      tblPrevDim.marginleft=tblPrevDim.marginleft+margin
      t={}
      t.xmldim=s
      t.dimpoints=tblPts

      ndims=ndims+1
      tblDims[ndims]=t
    end
  end
  
  -- Offset right
  xnow=tblNow.last.elemdata.bx2
  xcore=tblCore.last.elemdata.bx2
  if flipx then
    -- Need to swap x1,x2 also
    xnow=tblNow.last.elemdata.bx1
    xcore=tblCore.last.elemdata.bx1
  end
  if math.abs(xnow - xcore)>0.001 then
    tblPts={}
    npt=0

    -- Curr max
    pt={}
    pt.index=tblNow.last.index
    pt.anchorlast=1
    npt=npt+1
    tblPts[npt]=pt

--ac_environment("tolog", string.format("tblNow.typetag=%s tblNow.last.index=%d, tblNow.last.elemdata.bx1=%f, tblNow.last.elemdata.bx2=%f\ntblNow.last.elemdata.by1=%f, tblNow.last.elemdata.by2=%f", tblNow.typetag, tblNow.last.index, tblNow.last.elemdata.bx1, tblNow.last.elemdata.bx2, tblNow.last.elemdata.by1, tblNow.last.elemdata.by2))

    -- Core min
    pt={}
    pt.index=tblCore.last.index
    pt.anchorlast=1
    npt=npt+1
    tblPts[npt]=pt
    
--ac_environment("tolog", string.format("tblCore.last.index=%d tblCore.last.elemdata.bx1=%f, tblCore.last.elemdata.bx2=%f\ntblCore.last.elemdata.by1=%f, tblCore.last.elemdata.by2=%f", tblCore.last.index, tblCore.last.elemdata.bx1, tblCore.last.elemdata.bx2, tblCore.last.elemdata.by1, tblCore.last.elemdata.by2))
    if tblPrevDim.right==nil or math.abs(tblPrevDim.right-xnow)>0.0005 then
      tblPrevDim.right=xnow
      s=string.format("<dimline side=\"%s\" marginproj=\"%1.2f\" elemvecx=\"1\"/>", lineSide, tblPrevDim.marginright)
      tblPrevDim.marginright=tblPrevDim.marginright+margin
      t={}
      t.xmldim=s
      t.dimpoints=tblPts

      ndims=ndims+1
      tblDims[ndims]=t
    end
  end  
  
  return ndims
end

-- Creates offset dim lines for top projection
function TopDimLines()
  local i, a
  local tbl, info, elemdata
  local tblProjInfo, projinfo						-- Projection infos for owning elements, key=element guid
  local typetag, tblPlank
  local tblLayers                       -- key=element layer typetag, data: elem is the owner element ; parts beg and end each having fields: index, elemdata
  local tblCam=af_request("dim_camera")


  tblRes={}
  tblProjInfo={}
  tblLayers={}
  for i=1,gnPlanks do
    ac_objectopen(string.format("#!%d",i))    -- Open related master plank
    info=af_request("plankinfo")
    
    -- Include only planks which are 0/90 deg from camera's x-direction (studs or horizontal pieces)
    a=0
    if tblCam and info.type==1 then
      a=CalcDot3D(info.vecx.x, info.vecx.y, info.vecx.z, tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z)
    end
    --ac_environment("tolog", string.format("%s: a=%f", ac_objectget("#id"), a))

    tbl=ac_objectget("#af_elemdata")   -- To get typetag also
    typetag=nil
    if tbl then
      typetag=tbl.typetag
    end
    ac_objectclose()
    
    if math.abs(a)<0.02 or math.abs(a)>0.999 then
      tblPlank={}
      tblPlank.index=i
      tblPlank.elemdata=tbl
    
      if not typetag then
        ac_environment("tolog", "TopDimLines: Unexpected missing typetag")
      else
        tbl=tblLayers[typetag]
        if tbl==nil then
          -- Construct info for this layer
          tbl={}
          tbl.elem={}
        
          tbl.elem.geo=af_request("elem_quantities", info.ownerelemguid, 0).geo
          tbl.first=tblPlank
          tbl.last=tblPlank
          tblLayers[typetag]=tbl
        else
          -- Find min&max for the layer
          if tblPlank.elemdata.bx1<tbl.first.elemdata.bx1 then
            tbl.first=tblPlank
          end
        
          if tblPlank.elemdata.bx2>tbl.last.elemdata.bx2 then
            tbl.last=tblPlank
          end
        end
      end
    end
  end
  
  tblCore=tblLayers["core"]
  if tblCore==nil then
    return nil
  end

  -- Collect all layers and sort by distance from core layer to put dim lines in order
  local tblLayersSort, k, v, x, y, z
  
  tblLayersSort={}
  i=0
  for k,v in pairs(tblLayers) do
    i=i+1
    tblLayersSort[i]=v
    tblLayersSort[i].typetag=k
        
    x=v.elem.geo.orig.x - tblCore.elem.geo.orig.x
    y=v.elem.geo.orig.y - tblCore.elem.geo.orig.y
    z=v.elem.geo.orig.z - tblCore.elem.geo.orig.z
    tblLayersSort[i].dist=CalcDot3D(tblCore.elem.geo.vecz.x, tblCore.elem.geo.vecz.y, tblCore.elem.geo.vecz.z, x, y, z)
--ac_environment("tolog", string.format("%s: tblLayersSort[i].dist=%f, tblCore.elem.geo.vecz.x=%f, tblCore.elem.geo.vecz.y=%f, tblCore.elem.geo.vecz.z=%f\nx=%f y=%f z=%f", k, tblLayersSort[i].dist, tblCore.elem.geo.vecz.x, tblCore.elem.geo.vecz.y, tblCore.elem.geo.vecz.z, x, y, z))
  end

	table.sort(tblLayersSort, function (n1, n2)
    return n1.dist<n2.dist    
	end)

  -- Find core (always found)
  local coreInd
  
  for i,v in ipairs(tblLayersSort) do
    if v.typetag=="core" then
      coreInd=i
      break
    end
  end

  -- Add dims
  local ndims, tblDims
  local tblPrevDim
  local stop, sbot, mtop, mbot, flipx
  
  ndims=0
  tblDims={}
  
  -- If camera's y-axis is opposite to element's watching dir, swap top&bottom
  stop="top"
  sbot="bottom"
  mtop=0.05
  mbot=0.13
  
  v=tblCore.elem.geo.vecz
  if tblCam and CalcDot3D(v.x, v.y, v.z, tblCam.vecy.x, tblCam.vecy.y, tblCam.vecy.z)<0 then
    stop="bottom"
    sbot="top"
    mtop=0.13
    mbot=0.05
  end

  flipx=false
  v=tblCore.elem.geo.vecx
  if tblCam and CalcDot3D(v.x, v.y, v.z, tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z)<0 then
    flipx=true
    tblCore.first,tblCore.last=tblCore.last,tblCore.first
  end

  -- Anything before core to bottom
  tblPrevDim={}
  tblPrevDim.marginleft=mbot
  tblPrevDim.marginright=mbot
  i=coreInd
  while i>1 do
    i=i-1
    v=tblLayersSort[i]
    if flipx then
      v.first,v.last=v.last,v.first
    end
    ndims=AddTopDims(tblCore, v, tblDims, ndims, sbot, 0.13, tblPrevDim, flipx)
  end
  
  -- Anything after core to top
  tblPrevDim={}
  tblPrevDim.marginleft=mtop
  tblPrevDim.marginright=mtop
  i=coreInd
  while true do
    i=i+1
    v=tblLayersSort[i]
    if not v then
      break
    end

    if flipx then
      v.first,v.last=v.last,v.first
    end
    ndims=AddTopDims(tblCore, v, tblDims, ndims, stop, 0.13, tblPrevDim, flipx)
  end

  return tblDims
end


-- Creates cladding dim line adding all polygon points to the dim line HORIZONTAL
-- dimSettings  Settings for dim line containing <dimline>...</dimline>
function CladdingDimLines(dimSettings)
  local i
  local tblPoints, npoints, poly, polySettings, typetag
  local t, info, elemdata, tblCam, x1, x2, y1, y2, incDim, tblguids
  
  tblCam=af_request("dim_camera")
  tblPoints={}
  npoints=0
  polySettings={}
  polySettings.side=2                         -- Front side
  polySettings.givelist=1                     -- Future proof for split polygons
  polySettings.camera=tblCam
  tblguids={}
  for i=1,gnPlanks do
    typetag=nil
    poly=nil
    ac_objectopen(string.format("#!%d",i))    -- Open related master plank
    t=ac_objectget("#af_elemdata")   -- To get typetag also
    if t then
      typetag=t.typetag
      if typetag and string.match(typetag,"^finish.*") then
        info=af_request("plankinfo")
        incDim=ac_objectget("iIncludeDim")
        if not incDim then
          incDim=1
        end
        if incDim==1 then
          tblguids[#tblguids+1]=info.guid
        end
      end
    end
    ac_objectclose()
  end
  
  if #tblguids==0 then
    return {}
  end
  polySettings.tblguids=tblguids
  poly=af_request("getpoly", polySettings)
  if not poly then
    return {}
  end
  
  local klist,vlist, kpoint, vpoint, kscan, vscan, found
      
  for klist,vlist in ipairs(poly.poly) do
    for kpoint,vpoint in ipairs(vlist) do
      -- Do not add if x already added
      found=false
      for kscan,vscan in ipairs(tblPoints) do
        if math.abs(vscan.x-vpoint.x)<0.0005 then
          found=true
          break
        end
      end
          
      if not found then
        t={}
        t.x=vpoint.x
        t.y=vpoint.y
        npoints=npoints+1
        tblPoints[npoints]=t
            
        if not x1 or vpoint.x<x1 then
          x1=vpoint.x
          y1=vpoint.y
        end
        if not x2 or vpoint.x>x2 then
          x2=vpoint.x
          y2=vpoint.y
        end
      end
    end
  end

  local ndims, tblDims
  
  ndims=0
  tblDims={}
  
  if not npoints then
    return tblDims
  end
  
  local s

  if not dimSettings then
  s="<dimline side=\"top\" margin=\"0.2\" elemvecx=\"1\">"
  s=s .. "<dimlinesettings>\n"
  s=s .. "  <elemparam name=\"dimensiontype\">cumulative</elemparam>\n"
  s=s .. "<elemparam name=\"markertype\">5</elemparam>\n"
  s=s .. "</dimlinesettings>\n"
  s=s.."</dimline>"
  else
    s=dimSettings
  end
  
  t={}
  t.xmldim=s
  t.dimpoints=tblPoints
  ndims=ndims+1
  tblDims[ndims]=t

  if x1 then
    -- Min & max
    s="<dimline side=\"top\" margin=\"0.2\" elemvecx=\"1\">"
    s=s.."</dimline>"
  
    tblPoints={}
  
    t={}
    t.x=x1
    t.y=y1
    tblPoints[1]=t

    t={}
    t.x=x2
    t.y=y2
    tblPoints[2]=t
  
    t={}
    t.xmldim=s
    t.dimpoints=tblPoints
    ndims=ndims+1
    tblDims[ndims]=t
  end

  return tblDims
end


-- Creates cladding dim line adding all polygon points to the dim line VERTICAL
-- dimSettings  Settings for dim line containing <dimline>...</dimline>
function CladdingDimLinesVert(dimSettings)
  local i
  local tblPoints, npoints, poly, polySettings, typetag
  local t, info, elemdata, tblCam, x1, x2, y1, y2, incDim, tblguids
  
  tblCam=af_request("dim_camera")
  tblPoints={}
  npoints=0
  polySettings={}
  polySettings.side=2                         -- Front side
  polySettings.givelist=1                     -- Future proof for split polygons
  polySettings.camera=tblCam
  tblguids={}
  for i=1,gnPlanks do
    typetag=nil
    poly=nil
    ac_objectopen(string.format("#!%d",i))    -- Open related master plank
    t=ac_objectget("#af_elemdata")   -- To get typetag also
    if t then
      typetag=t.typetag
      if typetag and string.match(typetag,"^finish.*") then
        info=af_request("plankinfo")
        incDim=ac_objectget("iIncludeDim")
        if not incDim then
          incDim=1
        end
        if incDim==1 then
          tblguids[#tblguids+1]=info.guid
        end
      end
    end
    ac_objectclose()
  end
  
  if #tblguids==0 then
    return {}
  end
  polySettings.tblguids=tblguids
  poly=af_request("getpoly", polySettings)
  if not poly then
    return {}
  end  
  
  local klist,vlist, kpoint, vpoint, kscan, vscan, found
      
  for klist,vlist in ipairs(poly.poly) do
    for kpoint,vpoint in ipairs(vlist) do
      -- Do not add if y already added
      found=false
      for kscan,vscan in ipairs(tblPoints) do
        if math.abs(vscan.y-vpoint.y)<0.0005 then
          found=true
          break
        end
      end
          
      if not found then
        t={}
        t.x=vpoint.x
        t.y=vpoint.y
        npoints=npoints+1
        tblPoints[npoints]=t
            
--[[         if not x1 or vpoint.x<x1 then
          x1=vpoint.x
          y1=vpoint.y
        end
        if not x2 or vpoint.x>x2 then
          x2=vpoint.x
          y2=vpoint.y
        end --]]
			
      end
    end
  end

  local ndims, tblDims
  
  ndims=0
  tblDims={}
  
  if npoints == 0 then
    return tblDims
  end
  
  local s

  if not dimSettings then
    s="<dimline side=\"right\" margin=\"0.35\" elemvecy=\"1\">"
    s=s .. "<dimlinesettings>\n"
    s=s .. "  <elemparam name=\"dimensiontype\">cumulative</elemparam>\n"
    s=s .. "  <elemparam name=\"markertype\">5</elemparam>\n"
    s=s .. "</dimlinesettings>\n"
    s=s.."</dimline>"
  else
    s=dimSettings
  end
  
  t={}
  t.xmldim=s
  t.dimpoints=tblPoints
  ndims=ndims+1
  tblDims[ndims]=t

  return tblDims
end

-- Makes the cladding dim lines from real exploded planks
-- Makes both hor and vertical at once, two for both: layer offset and all polygon points
function CladdingDimLinesPlanks()
  local i
  local poly, polySettings
  local t, info, elemdata, tblCam, x1, x2, y1, y2, tblguids, tblguidsoff
  local offLayer      -- Could be moved to param
  
  offLayer="core"
  tblguidsoff={}
  
  tblCam=af_request("dim_camera")
  tblguids={}

  polySettings={}
  polySettings.camera=tblCam
  polySettings.givelist=1                     -- Future proof for split polygons
  polySettings.camera=tblCam
  
  -- First collect all guids
  for i=1,gnPlanks do
    poly=nil
    ac_objectopen(string.format("#!%d",i))    -- Open related master plank
    info=af_request("plankinfo")
    t=ac_objectget("#af_elemdata")   -- To get typetag also
    if t and t.typetag then
      if string.match(t.typetag, "^finish.*") then
        tblguids[#tblguids+1]=info.guid
      elseif string.match(t.typetag, offLayer) then
        tblguidsoff[#tblguidsoff+1]=info.guid
      end
    end
    ac_objectclose()
  end
  
  local tblPointsHor, npointsHor, tblPointsVert, npointsVert

  tblPointsHor={}
  npointsHor=0
  tblPointsVert={}
  npointsVert=0

  if #tblguids>0 then
    polySettings.tblguids=tblguids
    poly=af_request("getpoly", polySettings)
    if poly then
      local klist,vlist, kpoint, vpoint, kscan, vscan, found
      
      for klist,vlist in ipairs(poly.poly) do
        for kpoint,vpoint in ipairs(vlist) do
          -- Calc bounding box from all points
          if not x1 or vpoint.x<x1 then
            x1=vpoint.x
          end
          if not x2 or vpoint.x>x2 then
            x2=vpoint.x
          end
          if not y1 or vpoint.y<y1 then
            y1=vpoint.y
          end
          if not y2 or vpoint.y>y2 then
            y2=vpoint.y
          end

          -- HOR: Do not add if x already added
          found=false
          for kscan,vscan in ipairs(tblPointsHor) do
            if math.abs(vscan.x-vpoint.x)<0.0005 then
              found=true
              break
            end
          end
          
          if not found then
            t={}
            t.x=vpoint.x
            t.y=vpoint.y
            npointsHor=npointsHor+1
            tblPointsHor[npointsHor]=t
          end
          
          -- VERT: Do not add if y already added
          found=false
          for kscan,vscan in ipairs(tblPointsVert) do
            if math.abs(vscan.y-vpoint.y)<0.0005 then
              found=true
              break
            end
          end
          
          if not found then
            t={}
            t.x=vpoint.x
            t.y=vpoint.y
            npointsVert=npointsVert+1
            tblPointsVert[npointsVert]=t
          end
          
        end
      end
    end
  end
  
  local ndims, tblDims, s, t2, tdim
  
  ndims=0
  tblDims={}
  
  -- Add offset dim lines here
  local offx1, offy1, offx2, offy2
  
--ac_environment("tolog", string.format("#tblguidsoff=%d", #tblguidsoff))
  if #tblguidsoff>0 then
    polySettings.tblguids=tblguidsoff
    poly=af_request("getpoly", polySettings)
    offx1=poly.x1
    offx2=poly.x2
    offy1=poly.y1
    offy2=poly.y2
    
    -- Hor left
    if math.abs(x1-offx1)>0.001 then
      s="<dimline side=\"top\" marginproj=\"0.25\" elemvecx=\"1\">"
      s=s .. "<dimlinesettings>\n"
      s=s .. "</dimlinesettings>\n"
      s=s.."</dimline>"

      t2={}
      
      t={}
      t.x=offx1
      t.y=offy1
      t2[1]=t

      t={}
      t.x=x1
      t.y=y1
      t2[2]=t

      t={}
      t.xmldim=s
      t.dimpoints=t2
      ndims=ndims+1
      tblDims[ndims]=t
    end

    -- Hor right
    if math.abs(x2-offx2)>0.001 then
      s="<dimline side=\"top\" marginproj=\"0.25\" elemvecx=\"1\">"
      s=s .. "<dimlinesettings>\n"
      s=s .. "</dimlinesettings>\n"
      s=s.."</dimline>"

      t2={}
      
      t={}
      t.x=offx2
      t.y=offy2
      t2[1]=t

      t={}
      t.x=x2
      t.y=y2
      t2[2]=t

      t={}
      t.xmldim=s
      t.dimpoints=t2
      ndims=ndims+1
      tblDims[ndims]=t
    end
    
    -- Vert bottom
--ac_environment("tolog", string.format("y1=%f offy1=%f", y1, offy1))
    if math.abs(y1-offy1)>0.001 then
      s="<dimline side=\"right\" marginproj=\"0.25\" elemvecy=\"1\">"
      s=s .. "<dimlinesettings>\n"
      s=s .. "</dimlinesettings>\n"
      s=s.."</dimline>"

      t2={}
      
      t={}
      t.x=offx2
      t.y=offy1
      t2[1]=t

      t={}
      t.x=x2
      t.y=y1
      t2[2]=t

      t={}
      t.xmldim=s
      t.dimpoints=t2
      ndims=ndims+1
      tblDims[ndims]=t
    end

    -- Vert top
    if math.abs(y2-offy2)>0.001 then
      s="<dimline side=\"right\" marginproj=\"0.25\" elemvecy=\"1\">"
      s=s .. "<dimlinesettings>\n"
      s=s .. "</dimlinesettings>\n"
      s=s.."</dimline>"

      t2={}
      
      t={}
      t.x=offx2
      t.y=offy2
      t2[1]=t

      t={}
      t.x=x2
      t.y=y2
      t2[2]=t

      t={}
      t.xmldim=s
      t.dimpoints=t2
      ndims=ndims+1
      tblDims[ndims]=t
    end
  end  

  if npointsHor>0 then
    -- Polygon
    s="<dimline side=\"top\" margin=\"0.25\" elemvecx=\"1\">"
    s=s .. "<dimlinesettings>\n"
    s=s .. "  <elemparam name=\"dimensiontype\">cumulative</elemparam>\n"
    s=s .. "  <elemparam name=\"markertype\">5</elemparam>\n"
    s=s .. "</dimlinesettings>\n"
    s=s .. "<text content=\"CLAD\" content_fin=\"VERH\" textid=\"projid*20+18\" anchor=\"6\" marg=\"0.2\">\n"
    s=s .. "<layer></layer>\n"
    s=s .. "<elemparam name=\"pen\">1</elemparam>\n"
    s=s .. "<elemparam name=\"fontname\">arial</elemparam>\n"
    s=s .. "<elemparam name=\"fontsize\">1.5</elemparam>\n"
    s=s .. "<elemparam name=\"fontstyle\"></elemparam>\n"
    s=s .. "</text>\n"
    s=s.."</dimline>"
  
    t={}
    t.xmldim=s
    t.dimpoints=tblPointsHor
    ndims=ndims+1
    tblDims[ndims]=t
  end

  if npointsVert>0 then
    -- Polygon
    s="<dimline side=\"right\" margin=\"0.25\" elemvecy=\"1\">"
    s=s .. "<dimlinesettings>\n"
    s=s .. "  <elemparam name=\"dimensiontype\">cumulative</elemparam>\n"
    s=s .. "  <elemparam name=\"markertype\">5</elemparam>\n"
    s=s .. "</dimlinesettings>\n"
    s=s .. "<text content=\"CLAD\" content_fin=\"VERH\" textid=\"projid*20+19\" anchor=\"6\" marg=\"0.2\">\n"
    s=s .. "<layer></layer>\n"
    s=s .. "<elemparam name=\"pen\">1</elemparam>\n"
    s=s .. "<elemparam name=\"fontname\">arial</elemparam>\n"
    s=s .. "<elemparam name=\"fontsize\">1.5</elemparam>\n"
    s=s .. "<elemparam name=\"fontstyle\"></elemparam>\n"
    s=s .. "</text>\n"
    s=s.."</dimline>"

    t={}
    t.xmldim=s
    t.dimpoints=tblPointsVert
    ndims=ndims+1
    tblDims[ndims]=t
  end
  
  return tblDims
end

]]>
        </script>

        <!-- Sets values of element stamp  -->
        <script id="elemstamp">
          <![CDATA[
-- Get values from element
ac_objectopen(gGuidElem)
sId=ac_objectget("#id")
ac_objectclose()

-- Set to the stamp (only set some if not set already)
ac_objectopen(gGuidElemStamp)
ac_objectset("iStr1", sId)
ac_objectset("iStr2", gElemIdStamp)

if ac_objectget("iStr3")=="" then
  -- Check http://www.lua.org/pil/22.1.html
  d=os.date("%Y-%m-%d")
  ac_objectset("iStr3", d)
end

ac_objectset("iStr4", "<PROJECTNAME>")

if ac_objectget("iStr5")=="" then
  ac_objectset("iStr5", "<CADTECHNICIAN>")
end

ac_objectset("iStr6", "<PROJECTNUMBER>")

-- Unused: ac_objectset("iStr7", "<CUSTOM2>")

ac_objectclose()
]]>
        </script>

        <!-- Sets different pen for studs -->
        <script id="setcolours">
          <![CDATA[
gnPlankCount=0
gtblCreate = {}

-- "-" means do not create
if not gFillPen or gFillPen~="-" then
 local pen
 
 if gFillPen and gFillPen~="" then
   pen=tonumber(gFillPen)
 end
 if pen==nil then
   pen=110
 end
 
 for i=1,gnPlanks do
  ac_objectopen(string.format("#%d",i))
  
  -- Vertical (studs) with different fill
  x2=ac_objectget("iEndX")
  y2=ac_objectget("iEndY")
  if math.abs(x2)<0.001 and math.abs(y2)<0.001 then
    ac_objectset("iFillPen", pen)
    ac_objectset("iFill", "SolidNOTFOUND|50 %")
  end
  ac_objectclose()
 end
end
]]>
        </script>

       
        <script id="renum_by_role">
          <![CDATA[
-- Loaded once per element, called for each plank current plank opened already
-- Returns table having optional fields:
-- idpre  To be added before ID
-- idpost To be added after ID
-- For both, the special characters:
-- !, will not be visible
-- #num, useful for idpre - will define the starting number for the planks (not visible either)
-- =, as the first character will set the idpre as it is to the target
function GetPlankRenumData()
  local s, t, res
  
  t={}
  s=ac_objectget("iElemGroup")
  
  res="#1"
  if string.match(s, "^vertical_x.*") then
    res="#200"
  elseif string.match(s, "^lintel.*") then
    res="#250"
  elseif string.match(s, "^bottom_force.*") or string.match(s, "^2ndbottom_force.*") then
    res="#300"
  elseif string.match(s, "^top_force.*") or string.match(s, "^2ndtop_force.*") then
    res="#400"
  elseif string.match(s, "^nogging.*") then
    res="#500"
  end

  t.idpre=res
  return t
end
]]>
        </script>

        <!-- Norwegian ID prefixes inside the element -->
        <script id="renum_nor1">
          <![CDATA[
-- Loaded once per element, called for each plank current plank opened already
-- Returns table having optional fields:
-- idpre  To be added before ID
-- idpost To be added after ID
-- For both, the special characters:
-- !, will not be visible
-- #num, useful for idpre - will define the starting number for the planks (not visible either)
-- =, as the first character will set the idpre as it is to the target
function GetPlankRenumData()
  local s, t, res
  
  t={}
  s=ac_objectget("iElemGroup")
  
  res=nil
  if string.match(s, "^vertical_x.*") then
    res="L"
  elseif string.match(s, "^lintel.*") or string.match(s, "^balk.*") or string.match(s, "^reinforce.*") then
    res="D"
  elseif string.match(s, "^bottom_force.*") or string.match(s, "^2ndbottom_force.*") then
    res="B"
  elseif string.match(s, "^top_force.*") or string.match(s, "^2ndtop_force.*") then
    res="T"
  elseif string.match(s, "^vertical.*") then
    res="S"
  end

  t.idpre=res
  return t
end
]]>
        </script>


        <script id="renum_board_example">
          <![CDATA[
-- Loaded once per element, called for each board current board opened already
-- Returns table having optional fields:
-- idpre  To be added before ID
-- idpost To be added after ID
-- For both, the special characters:
-- !, will not be visible
-- #num, useful for idpre - will define the starting number for the planks (not visible either)
-- =, as the first character will set the idpre as it is to the target
function GetPlankRenumData()
  local dx, mat_dx, dy, mat_dy, t, res
  
  t={}
  dx=ac_objectget("iCurrWidth")
  dy=ac_objectget("iCurrHeight")
  mat_dx=ac_objectget("iWidth")
  mat_dy=ac_objectget("iHeight")
  
  res=""
  if math.abs(dx - mat_dx)<0.0001 and math.abs(dy - mat_dy)<0.0001 then
	local info
	
	-- Make ID: (owning element ID)#FULL
    info=af_request("plankinfo")
	-- plankinfo is better: s = ac_getobjparam(gGuidElem, "#id")
    res="=" .. info.ownerelemid .. "#FULL"
  end

  t.idpre = res
  return t
end
]]>
        </script>

        <!-- Sets different pen for studs -->
        <script id="ibeamframe">
          <![CDATA[
gnPlankCount=0
gtblCreate = {}

for i=1,gnPlanks do
  ac_objectopen(string.format("#%d",i))
  
  -- Vertical (studs) with different fill
  z2=ac_objectget("iEndZ")
  if math.abs(z2)<0.001 then
    local i2, count, tblInfo
    
    count=ac_objectget("iMc",-1)
    i2=1
    while i2<=count do
      if ac_objectget("iMc",i2,1)==0 then
        found=true
        break
      end
      i2=i2+1
    end

    tblInfo=af_request("plankinfo")
    ac_objectset("iMc", 304, i2, 1)
    ac_objectset("iMc", 0.1, i2, 2)
    ac_objectset("iMc", tblInfo.height*0.5, i2, 3)
    ac_objectset("iMc", 0, i2, 4)
    ac_objectset("iMc", tblInfo.height - 0.096, i2, 5)
    ac_objectset("iMc", 0.018, i2, 6)
    ac_objectset("iMc", 2, i2, 7)
    ac_objectset("iMc", 1, i2, 8)
    ac_objectset("iMc", 1, i2, 9)
    ac_objectset("iMcStr", "", i2)
  end
  ac_objectclose()
 end
]]>
        </script>

        <!-- Lintels all -->
        <script id="lintels">
          <![CDATA[
function DoLintelNoLoad()
  gnPlankCount=0
  gtblCreate = {}     -- Need to have but not used

  -- From widest to narrowest
  tblLens={}

  -- >= 2 m
  item={}
  item.minwidth=2
  item.mat="L 90x225"
  item.front=1
  item.back=0
  item.delorg=1
  item.extorg=0
  item.cutabove=1
  item.studs=1
  tblLens[1] = item

  af_request("lintels", tblLens)
end


function DoLintelLoad()
  gnPlankCount=0
  gtblCreate = {}     -- Need to have but not used

  -- From widest to narrowest
  tblLens={}

  -- >= 1800 mm
  item={}
  item.minwidth=1.8
  item.mat="L 90x225"
  item.front=1
  item.back=0
  item.delorg=1
  item.extorg=0
  item.cutabove=1
  item.studs=1
  tblLens[1] = item

  item={}
  item.minwidth=1.2
  item.mat="48x223"
  item.front=2
  item.back=0
  item.delorg=1
  item.extorg=0
  item.cutabove=1
  item.studs=1
  tblLens[2] = item

  item={}
  item.minwidth=0.6
  item.mat="48x198"
  item.front=2
  item.back=0
  item.delorg=1
  item.extorg=0
  item.cutabove=1
  item.studs=1
  tblLens[3] = item

  item={}
  item.minwidth=0.1
  item.mat="48x98"
  item.front=2
  item.back=0
  item.delorg=1
  item.extorg=0
  item.cutabove=1
  item.studs=1
  tblLens[4] = item

  af_request("lintels", tblLens)
end


gtblSettings=nil

-- Uses global gtblSettings for optins
-- Returns: true=ok, false=canceled from settings dlg
function DoLintelCustom()
  local defMatId, defMat
  
  gnPlankCount=0
  gtblCreate = {}     -- Need to have but not used

  -- Settings
        
  tblMat=af_request("matlist")
  s=""
  strSep=""
      
  -- Select always element's default material
  defMatId=af_request("elem_getstudmat")
  if defMatId==nil then
    defMatId=""
  end
  defMat=1
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
    if v.id==defMatId then
      defMat=v.index
    end
  end

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end

  -- For options to handle creating multiple lintels with single click
  if gtblSettings==nil then
    gtblSettings={}
    gtblSettings[1]			={}
    gtblSettings[1].cfgonly	=0
    gtblSettings[1].type		=1
    gtblSettings[1].prompt	="Material"
    gtblSettings[1].key		="mat"
    gtblSettings[1].valuelist=s
    gtblSettings[1].defvalue	=defMat
    --gtblSettings[1].value 	=defMat

    gtblSettings[2]			={}
    gtblSettings[2].cfgonly	=1
    gtblSettings[2].type		=2
    gtblSettings[2].prompt	="Use element's material as default (affects prev setting)"
    gtblSettings[2].key		="usedefault"
    gtblSettings[2].defvalue	=1

    gtblSettings[3]			={}
    gtblSettings[3].cfgonly	=0
    gtblSettings[3].type		=3
    gtblSettings[3].prompt	="Thickness if not fixed"
    gtblSettings[3].key		="thickness"
    gtblSettings[3].defvalue	=0.050

    gtblSettings[4]			={}
    gtblSettings[4].cfgonly	=0
    gtblSettings[4].type		=3
    gtblSettings[4].prompt	="Height if not fixed"
    gtblSettings[4].key		="height"
    gtblSettings[4].defvalue	=0.100

    gtblSettings[5]			={}
    gtblSettings[5].cfgonly	=0
    gtblSettings[5].type		=4
    gtblSettings[5].prompt	="Beams to front side"
    gtblSettings[5].key		="beam_front"
    gtblSettings[5].defvalue	=1

    gtblSettings[6]			={}
    gtblSettings[6].cfgonly	=0
    gtblSettings[6].type		=4
    gtblSettings[6].prompt	="Beams to back side"
    gtblSettings[6].key		="beam_back"
    gtblSettings[6].defvalue	=0

    gtblSettings[7]			={}
    gtblSettings[7].cfgonly	=0
    gtblSettings[7].type		=2
    gtblSettings[7].prompt	="Remove original piece"
    gtblSettings[7].key		="delorg"
    gtblSettings[7].defvalue	=0

    gtblSettings[8]			={}
    gtblSettings[8].cfgonly	=0
    gtblSettings[8].type		=2
    gtblSettings[8].prompt	="Extend original piece"
    gtblSettings[8].key		="extorg"
    gtblSettings[8].defvalue	=0

    gtblSettings[9]			={}
    gtblSettings[9].cfgonly	=0
    gtblSettings[9].type		=2
    gtblSettings[9].prompt	="Cut studs above lintel (grooves if not)"
    gtblSettings[9].key		="cutabove"
    gtblSettings[9].defvalue	="0"

    gtblSettings[10]			={}
    gtblSettings[10].cfgonly	=0
    gtblSettings[10].type		=4
    gtblSettings[10].prompt	="Number of additional studs"
    gtblSettings[10].key		="numstuds"
    gtblSettings[10].defvalue	="1"

    gtblSettings[11]			={}
    gtblSettings[11].cfgonly	=0
    gtblSettings[11].type		=2
    gtblSettings[11].prompt	="Place below top plate"
    gtblSettings[11].key		="totop"
    gtblSettings[11].defvalue	=0

    gtblSettings[12]			={}
    gtblSettings[12].cfgonly	=0
    gtblSettings[12].type		=4
    gtblSettings[12].prompt	="Extra studs mat id (empty=original)"
    gtblSettings[12].key		="matidstud"
    gtblSettings[12].defvalue	=""

    gtblSettings[13]			={}
    gtblSettings[13].cfgonly	=0
    gtblSettings[13].type		=2
    gtblSettings[13].prompt	="Extend beams to furthest side of the king studs"
    gtblSettings[13].key		="extbeam"
    gtblSettings[13].defvalue	=0

    gtblSettings[14]			={}
    gtblSettings[14].cfgonly	=0
    gtblSettings[14].type		=3
    gtblSettings[14].prompt	="Join beams if closer than"
    gtblSettings[14].key		="joinbeams"
    gtblSettings[14].defvalue	=0

    gHelpAnchor="afdlgelemlintel"
    bRes,sErr=ac_optiondlg("LDEL", nil, gtblSettings)
    
    if gtblSettings[2].value and gtblSettings[2].value==1 then
      gtblSettings[1].value 	=defMat
    else
      gtblSettings[1].value 	=nil
    end
    
    bRes,sErr=ac_optiondlg("LDEL", "Lintel settings", gtblSettings)
    gHelpAnchor=nil
    if not bRes then
      return false
    end
  end
      
  mat=tblSorted[gtblSettings[1].value]
  thickness=mat.thickness
  height=mat.height
  if thickness==0.0 then
    thickness=gtblSettings[2].value
  end
  if height==0.0 then
    height=gtblSettings[3].value
  end

  -- Fill the lintel settings to single item
  tblLens={}

  item={}
  item.minwidth =0
  item.mat      =tblSorted[gtblSettings[1].value].id
  item.thickness=gtblSettings[3].value
  item.height   =gtblSettings[4].value
  item.front    =tonumber(gtblSettings[5].value)
  item.back     =tonumber(gtblSettings[6].value)
  item.delorg   =gtblSettings[7].value
  item.extorg   =gtblSettings[8].value

  item.cutabove =gtblSettings[9].value
  item.studs    =tonumber(gtblSettings[10].value)
  item.totop    =gtblSettings[11].value
  item.matstud  =gtblSettings[12].value
  item.extbeamtosides=gtblSettings[13].value
  item.joinbeamsdist =gtblSettings[14].value

  tblLens[1] = item
  af_request("lintels", tblLens)
  return true
end
]]>
        </script>


        <!-- Creates/removes second top&bottom wood -->
        <script id="doubletopbot">
          <![CDATA[

-- Dumps given variable into string
function DumpTblInt(o, nIndent)
  local s,k,v

  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end

    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end

    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end


-- For planks to be created
gnPlankCount=0
gtblCreate = {}

gbJoinSources=true   -- Set to true if you want single piece from automatic cut top/bottom

-- Formats message so that calling program shows just the msg
-- Message can be empty - nothing is showed then (if operation canceled)
function RaiseError(msg)
  msg="###>" ..  msg .. "<###"
  error( msg )
end


gtblSelPlanks=nil
gAddAllStuds=false      -- Set to true if making reinforcement (and grooves to every stud)

function GetThickness()
  local width

  width=ac_objectget("iWidth")
  if width==nil or width==0.0 then
    width=ac_objectget("A")
  end
   return width
end


function GetHeight()
	local	width

	width=ac_objectget("iHeight")
	if width==nil or width==0.0 then
		width=ac_objectget("B")
	end
   return width
end


function StrToXml(str)
  str=string.gsub(str, "&", "&amp;")
  str=string.gsub(str, "<", "&lt;")
  str=string.gsub(str, ">", "&gt;")
  str=string.gsub(str, "\"", "&quot;")
  str=string.gsub(str, "\'", "&apos;")
  return str
end


function Dot2D(dirX1, dirY1, dirX2, dirY2)
  return dirX1*dirX2+dirY1*dirY2
end


function IsVertical(edge)
  return math.abs(edge.x2-edge.x1)<0.01
end


function IsHorizontal(edge)
  return math.abs(edge.y2-edge.y1)<0.01
end


function HasValidDirection(edge)
  local dx=edge.x2-edge.x1
  local dy=edge.y2-edge.y1
  local dir=-1.0
  if not gbTop then
    dir=1.0
  end
  return Dot2D(dx, dy, dir, 0)>0.01
end


function IsValidEdge(edge)
  return 
    HasValidDirection(edge) and 
    (IsHorizontal(edge) or g_applyAngled==1) and 
    edge.tblPlankNumsAll~=nil and #edge.tblPlankNumsAll>0
end


function Sub2D(p1, p2)
  return {x=p2.x-p1.x, y=p2.y-p1.y}
end


function Add2D(vecA, vecB)
  return {x=vecA.x+vecB.x, y=vecA.y+vecB.y}
end


function Length2D(vec)
  return math.sqrt(vec.x*vec.x+vec.y*vec.y)
end


function Distance2D(p1, p2)
  return Length2D(Sub2D(p1, p2))
end


function Normalize2D(vec)
  local length=Length2D(vec)
  return {x=vec.x/length, y=vec.y/length}
end


function Flip2D(vec)
  return {x=-vec.x, y=-vec.y}
end


function FlipRight2D(vec)
  return {x=vec.y, y=-vec.x}
end


function FlipLeft2D(vec)
  return {x=-vec.y, y=vec.x}
end


function Scale2D(vec, length)
  return {x=vec.x*length, y=vec.y*length}
end


function Extend2D(source, dir, length)
  return Add2D(source, Scaled)
end


function FormatPt(pt)
  return string.format("x=%0.2f, y=%0.2f", pt.x, pt.y)
end


function CollectVerticalPlanks()
  local result={}
  for nPlank=1,gnPlanks do
    ac_objectopen(string.format("#%d", nPlank))
    local elemData=ac_objectget("#af_elemdata")
    ac_objectclose()
    if math.abs(elemData.x2-elemData.x1) < 0.01 then
      table.insert(result, elemData)
    end
  end

  function Cmp(a, b)
    return a.x1<b.x1
  end

  table.sort(result, Cmp)
  return result
end


function MoveLineLeft(p1, p2, offset)
  local dirForward=Normalize2D(Sub2D(p1, p2))
  local dirRight=FlipLeft2D(dirForward)
  local vecRight=Scale2D(dirRight, offset)
  p1=Add2D(p1, vecRight)
  p2=Add2D(p2, vecRight)
  return p1, p2
end


function log(what)
  ac_environment("tolog", what)
end


function TernaryIf(cond, T, F)
    if cond then return T else return F end
end

-- bAdd true=adding, false=deleting, nil=on/off
-- Globals: g_matidorg, g_matiddouble: Set to non-nil if forced materials
-- g_zofforg, g_zoffdouble: Z-offset for original and double piece
-- g_orglayer non-empty: set layer for original piece (if removing, will set the layer from existing piece to original)
-- g_orgebt, for wup cnc: mark original as EBT if double, 0=no, 1=yes
-- g_orgcnc, cnc-setting
function DoDoubleTopBot(orgMat, orgZOffset, orgLayer, orgEBT, orgCNC, doubleMat, doubleZOffset)
  local newOrigMaterial=nil
  if g_matidorg~=nil then
    newOrigMaterial=af_request("singlemat", g_matidorg)
  end

  local newOrigLayer=nil
  if g_orglayer~="" then
    newOrigLayer=ac_environment("layer", g_orglayer, -2)
    if newOrigLayer~=nil and newOrigLayer<0 then
      ac_environment("tolog", string.format("WARNING: Failed to create layer %s. Will not set double top/bottom layers", g_orglayer))
    end
  end

  local doubleMaterial=nil
  if g_matiddouble~=nil then
    doubleMaterial=af_request("singlemat", g_matiddouble)
  end

  local dir=TernaryIf(gbTop, 1, -1)
  local operations=""
  local horizontalEdges={}
  local angledEdges={}

  for i=1, #gtblEdges, 1 do
    local edge=gtblEdges[i]
    if edge.holeindex~=0 then
      break
    end

    if IsValidEdge(edge) then
      local firstId=edge.tblPlankNumsAll[1]
      ac_objectopen(string.format("#%d", firstId))
      local firstMaterialPreUpdate=af_request("singlemat", ac_objectget("iMatId"))
      local firstLayerPreUpdate=nil
      ac_objectclose()

    -- Update original planks along edge as required.
    -- In most cases there is only one plank per edge, but there can be multiple if for example the user cuts a plank
      for j=1, #edge.tblPlankNumsAll do
        ac_objectopen(string.format("#%d", edge.tblPlankNumsAll[j]))
        local origElemData=ac_objectget("#af_elemdata")
        local p1={x=origElemData.x1, y=origElemData.y1}
        local p2={x=origElemData.x2, y=origElemData.y2}
       
        if newOrigLayer~=nil then
          firstLayerPreUpdate=ac_getattrinfo(2, ac_objectget("#layer"))
          ac_objectset("#layer", newOrigLayer)
        end
  
        if g_orgebt==1 then
          ac_objectset("iCncFraming", 0)
        end

        ac_objectset("iCnc", g_orgcnc)
        if newOrigMaterial~=nil or g_zofforg~=0.0 then
          local origEdit={}
          local origMaterial=af_request("singlemat", ac_objectget("iMatId"))
          local thicknessDelta=0.0
          if newOrigMaterial~=nil then
            origEdit.mat=newOrigMaterial.id
            thicknessDelta=newOrigMaterial.thickness-origMaterial.thickness
          end

          local origElemData=ac_objectget("#af_elemdata")

          -- Move x1,y1,x2,y2 inwards keeping anchor when material thickness changes
          if thicknessDelta~=0.0 then
            local p1, p2=MoveLineLeft(
              {x=origElemData.x1, y=origElemData.y1}, 
              {x=origElemData.x2, y=origElemData.y2}, 
              -thicknessDelta*0.5*dir
            )
            origElemData.x1=p1.x
            origElemData.y1=p1.y
            origElemData.x2=p2.x
            origElemData.y2=p2.y
          end

          if g_zofforg~=0.0 then
            origElemData.z1=origElemData.z1+g_zofforg
            origElemData.z2=origElemData.z2+g_zofforg
          end

          origEdit.elemdata=origElemData

          local origBegPlane=af_request("getbegendplane", "beg")
          local origEndPlane=af_request("getbegendplane", "end")
          origEdit.guid=af_request("plankInfo").ptr
          af_request("editplank", origEdit)

          -- Need to adjust cut planes if material thickness changes,
          -- Has to be called after 'editplank' has been called
          if thicknessDelta~=0.0 then
            af_request("adjustbegend", "beg", origBegPlane)
            af_request("adjustbegend", "end", origEndPlane)
            af_request("flushmc")
          end
        end

        ac_objectclose()
      end
    
  
      local edgeP1={x=edge.x1, y=edge.y1}
      local edgeP2={x=edge.x2, y=edge.y2}
      
      ac_objectopen(string.format("#%d", firstId))
      local firstElemData=ac_objectget("#af_elemdata")
      local firstMaterialPostUpdate=af_request("singlemat", ac_objectget("iMatId"))
      local begPlane=af_request("getbegendplane", "beg")
      local endPlane=af_request("getbegendplane", "end") 
      local p1={x=firstElemData.x1, y=firstElemData.y1}
      local p2={x=firstElemData.x2, y=firstElemData.y2}

      if Distance2D(p2, edgeP1)<Distance2D(p1, edgeP1) then
        p1, p2=p2, p1
        begPlane, endPlane=endPlane, begPlane
      end

      ac_objectclose()

      -- If the edge contains multiple planks use p2 and end plane of last plank
      if #edge.tblPlankNumsAll>1 then
        local lastId=edge.tblPlankNumsAll[#edge.tblPlankNumsAll]
        ac_objectopen(string.format("#%d", lastId))
        local lastElemData=ac_objectget("#af_elemdata")
        local lastBegPlane=af_request("getbegendplane", "beg")
        local lastEndPlane=af_request("getbegendplane", "end")
        local lastP1={x=lastElemData.x1, y=lastElemData.y1}
        local lastP2={x=lastElemData.x2, y=lastElemData.y2}
 
        if Distance2D(lastP1, edgeP2)<Distance2D(lastP2, edgeP2) then
          lastP1, lastP2=lastP2, lastP1
          lastBegPlane, lastEndPlane=lastEndPlane, lastBegPlane
        end

        p2=lastP2
        endPlane=lastEndPlane
        ac_objectclose()
      end

      local doubleMaterial=TernaryIf(doubleMaterial~=nil, doubleMaterial, firstMaterialPreUpdate)
      p1, p2=MoveLineLeft(p1, p2, (firstMaterialPostUpdate.thickness+doubleMaterial.thickness)*0.5)

      -- Beg is always to the min x
      if p1.x>p2.x then
        p1,p2=p2,p1
        begPlane, endPlane=endPlane, begPlane
      end

      -- Create new double plank
      local doublePlank={}
      doublePlank.guidsettings=edge.ptr
      doublePlank.thickness=doubleMaterial.thickness
      doublePlank.height=doubleMaterial.height
      doublePlank.id=doubleMaterial.id
      doublePlank.rotangle=0
      doublePlank.zoff=g_zoffdouble
      doublePlank.mayturn=true
      doublePlank.force=3
      doublePlank.group=gsDoubleGroup
      doublePlank.x1=p1.x
      doublePlank.y1=p1.y
      doublePlank.x2=p2.x
      doublePlank.y2=p2.y


      local xmlSettings=""
      if firstLayerPreUpdate~=nil then
        xmlSettings=xmlSettings .."<layer>" .. StrToXml(firstLayerPreUpdate.name) .. "</layer>"
      end

      if g_orgebt==1 then
        -- Set iCncFraming=1 for the new piece
        xmlSettings=xmlSettings .. "<objparam name=\"iCncFraming\">1</objparam>"
      end

      if g_orgcnc==0 then
        -- Set iCnc=1 for the new piece if setting it off from original
        xmlSettings=xmlSettings .. "<objparam name=\"iCnc\">1</objparam>"
      end

      if xmlSettings~="" then
        doublePlank.xmlsettings="<s>" ..  xmlSettings .. "</s>"
      end

      table.insert(gtblCreate, doublePlank)

      -- Adjust beg/end plane of new plank 
      gtblCreate[#gtblCreate].postlua=
          string.format(
          "<s>\n" ..
          "begPlane={pa=%0.8f, pb=%0.8f, pc=%0.8f, pd=%0.8f }" ..
          "endPlane={pa=%0.8f, pb=%0.8f, pc=%0.8f, pd=%0.8f }" ..
          "ac_objectopen(\"#%d\")\n" ..
          "af_request(\"adjustbegend\", \"beg\", begPlane)\n" ..
          "af_request(\"adjustbegend\", \"end\", endPlane)\n" ..
          "af_request(\"flushmc\")" ..
          "ac_objectclose()\n" ..
          "</s>",
          begPlane.pa,
          begPlane.pb,
          begPlane.pc,
          begPlane.pd,
          endPlane.pa,
          endPlane.pb,
          endPlane.pc,
          endPlane.pd, 
          gnPlanks+#gtblCreate
        )

      local origBottomP1, origBottomP2=MoveLineLeft(edgeP1, edgeP2, firstMaterialPreUpdate.thickness)

      -- Save bottom edge of original plank,
      -- Vertical planks intersecting with it will be adjusted to the double plank.
      local bottomEdge={p1=origBottomP1, p2=origBottomP2, operatorId=gnPlanks+#gtblCreate }
      if IsHorizontal(edge) then
        table.insert(horizontalEdges, bottomEdge)
      else
        table.insert(angledEdges, bottomEdge)
      end
    end
  end
   
  local verticalPlanks=CollectVerticalPlanks()
  local removePart=TernaryIf(gbTop, "up", "down")
  
  -- Operations for adjusting vertical planks to angled edges needs to come before horizontal edges
  -- In the case where the vertical plank intersects both a horizontal and an angled edge.
  -- Since 'angleddelfirst' will clear previous operations
  for i, bottomEdge in ipairs(angledEdges) do
    for j, verticalPlank in ipairs(verticalPlanks) do
      if ac_geo("linepolyx", bottomEdge.p1.x, bottomEdge.p1.y, bottomEdge.p2.x, bottomEdge.p2.y, {verticalPlank.poly}) ~=nil then
        operations=string.format(
          "%s" ..
          "  <jointo target=\"#%s\" operator=\"#%s\">\n" ..
          "    <cut endshape=\"angleddelfirst\" removepart=\"%s\"></cut>\n" ..
          "  </jointo>\n",
          operations, verticalPlank.index, bottomEdge.operatorId, removePart)
      end
    end
  end

  for i, bottomEdge in ipairs(horizontalEdges) do
    for j, verticalPlank in ipairs(verticalPlanks) do
      if ac_geo("linepolyx", bottomEdge.p1.x, bottomEdge.p1.y, bottomEdge.p2.x, bottomEdge.p2.y,{verticalPlank.poly}) ~=nil then
        operations=string.format(
          "%s" ..
          "  <jointo target=\"#%s\" operator=\"#%s\">\n" ..
          "    <cut removepart=\"%s\"></cut>\n" ..
          "  </jointo>\n",
          operations, verticalPlank.index, bottomEdge.operatorId, removePart)
      end
    end
  end

  return string.format("<operations>\n%s</operations>", operations)
end 



-------------------------
-- FOR OPTION DLG

-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gsDoubleGroup .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


function Set(sSettings)
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    GetDefaults()
  end


  gxmlOperations=DoDoubleTopBot()
  af_request("elem_createplanks")
end

function Reset()
  gtblCreate={}
  local verticalPlanks=CollectVerticalPlanks()
  local verticalPlanksToReset={}

  -- Collect vertical planks to reset (i.e planks that intersects the new planks created)
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    if ac_objectget("iElemGroup")==gsDoubleGroup then
      local elemData=ac_objectget("#af_elemdata")
      local p1={x=elemData.x2, y=elemData.y2}
      local p2={x=elemData.x1, y=elemData.y1}
      local thickness=af_request("singlemat", ac_objectget("iMatId"))['thickness']
      local dir=1
      if not gbTop then
        dir=-1
      end
      p1, p2=MoveLineLeft(p1, p2, thickness*0.5*dir)
      for i, verticalPlank in ipairs(verticalPlanks) do
        if ac_geo("linepolyx", p1.x, p1.y, p2.x, p2.y, {verticalPlank.poly})~=nil then
          table.insert(verticalPlanksToReset, verticalPlank)
        end
      end
      af_request("delplank")
    end
    ac_objectclose()
  end

  af_request("elem_getpoly")
  local horizontalEdges={}
  local angledEdges={}
  local operations=""
  for i=1, #gtblEdges, 1 do
    local edge=gtblEdges[i]
    if edge.holeindex~=0 then
      break
    end
    if HasValidDirection(edge) and edge.tblPlankNumsAll~=nil and #edge.tblPlankNumsAll>0 then
      if IsHorizontal(edge) then
        table.insert(horizontalEdges, edge)
      else
        table.insert(angledEdges, edge)
      end
    end
  end

  for i, edge in ipairs(angledEdges) do
    for j, plankId in ipairs(edge.tblPlankNumsAll) do
      for k, verticalPlank in ipairs(verticalPlanksToReset) do
        operations=string.format(
          "%s" ..
          "  <jointo target=\"#%s\" operator=\"#%s\">\n" ..
          "    <cut endshape=\"angleddelfirst\"></cut>\n" ..
          "  </jointo>\n",
          operations, verticalPlank.index, plankId)
      end
    end
  end

  for i, edge in ipairs(horizontalEdges) do
    for j, plankId in ipairs(edge.tblPlankNumsAll) do
      for k, verticalPlank in ipairs(verticalPlanksToReset) do
        operations=string.format(
          "%s" ..
          "  <jointo target=\"#%s\" operator=\"#%s\">\n" ..
          "    <cut></cut>\n" ..
          "  </jointo>\n",
          operations, verticalPlank.index, plankId)
      end
    end
  end

  gxmlOperations=string.format("<operations>\n%s</operations>", operations)

  -- Need to call elem_createplanks even if we don't want to create any planks,
  -- since it seems that is when xml operations are run.
  af_request("elem_createplanks")
end


-- FOR OPTION DLG
-------------------------

-------------------------
-- SETTINGS


-- sSettings may be nil, otherwise matfront=xxx\nmatback=xxx
-- Returns two values: matfront, matback, ""=use default material
-- g_zofforg, g_zoffdouble, g_orglayer  are handled as globals
function DoSettingsDlg(sSettings)
  local tblSettings, bRes, sErr, s, s2, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat


  tblMat=af_request("matlist")
  s=""
  strSep=""

  tblSorted={}

  tblSorted[1]={}
  tblSorted[1].name="No change/Same as the top or bottom"
  tblSorted[1].id=""
  tblSorted[1].index=1

  i=2
  for id,v in pairs(tblMat) do
    if v.thickness>0.001 then
      tblSorted[i]=v
      i=i+1
    end
  end

  table.sort(tblSorted, function (n1, n2)
    return n1.index < n2.index
  end)

  for i,v in ipairs(tblSorted) do
    if v.id~="" then
      s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    else
      s=string.format("%s%s\"%s:%s\"", s, strSep, i, v.name)
    end
    strSep=","
  end

  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type   =1
  tblSettings[1].prompt ="Material original"
  tblSettings[1].key    ="matorg"
  tblSettings[1].valuelist=s
  tblSettings[1].value  =1

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type   =1
  tblSettings[2].prompt ="Material double"
  tblSettings[2].key    ="matdouble"
  tblSettings[2].valuelist=s
  tblSettings[2].value  =1

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type   =3
  tblSettings[3].prompt ="Distance from front original"
  tblSettings[3].key    ="distorg"

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type   =3
  tblSettings[4].prompt ="Distance from front double"
  tblSettings[4].key    ="distdouble"

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type   =4
  tblSettings[5].prompt ="Change layer name for original if doubled"
  tblSettings[5].key    ="orglayer"

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type   =2
  tblSettings[6].prompt ="Wup cnc: Mark original as EBT"
  tblSettings[6].key    ="orgebt"

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type   =2
  tblSettings[7].prompt ="Saw cnc: Include original in cnc-file:"
  tblSettings[7].defvalue = 1
  tblSettings[7].key    ="orgcnc"

  tblSettings[8]          = {}
  tblSettings[8].cfgonly  = 0
  tblSettings[8].type     = 2
  tblSettings[8].prompt   = "Apply to angled beams"
  tblSettings[8].defvalue = 0
  tblSettings[8].key      = "applyAngled"

  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      for i=1,#tblSorted do
        if tblSorted[i].id==g_matidorg then
          tblSettings[1].value=i
        end
        if tblSorted[i].id==g_matiddouble then
          tblSettings[2].value=i
        end
      end
      tblSettings[7].value  =g_orgcnc
    else
      ac_environment( "tolog", string.format("DoSettingsDlg/parse settings failed: %s", tostring(err)) )
    end
  end

  tblSettings[3].value  =g_zofforg
  tblSettings[4].value  =g_zoffdouble
  tblSettings[5].value  =g_orglayer
  tblSettings[6].value  =g_orgebt
  tblSettings[8].value  =g_applyAngled
  bRes,sErr=ac_optiondlg("LDDB", "Double top/bottom materials", tblSettings)
  if not bRes then
    return
  end

  s=""
  if tblSettings[1].value>0 then
    s=tblSorted[tblSettings[1].value].id
  end
  s2=""
  if tblSettings[2].value>0 then
    s2=tblSorted[tblSettings[2].value].id
  end

  g_zofforg     =tblSettings[3].value
  g_zoffdouble  =tblSettings[4].value
  g_orglayer    =tblSettings[5].value
  g_orgebt      =tblSettings[6].value
  g_orgcnc      =tblSettings[7].value

  g_applyAngled = tblSettings[8].value
  return s, s2
end




-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets globals: g_matidorg, g_matiddouble (nil if use default)
function ParseSettings(sSettings)
  local s, mat

  GetDefaults()
  mat=GetVal(sSettings, "matorg")
  if mat and mat~="" then
    g_matidorg=af_request("singlemat", mat).id
    string.format("%s", g_matidorg)   -- Will cause error if bad syntax
  end

  mat=GetVal(sSettings, "matdouble")
  if mat and mat~="" then
    g_matiddouble=af_request("singlemat", mat).id
    string.format("%s", g_matiddouble)    -- Will cause error if bad syntax
  end

  s=GetVal(sSettings, "zofforg")
  if s and s~="" then
    g_zofforg=tonumber(s)
    string.format("%f", g_zofforg)
  end

  s=GetVal(sSettings, "zoffdouble")
  if s and s~="" then
    g_zoffdouble=tonumber(s)
    string.format("%f", g_zoffdouble)
  end

  s=GetVal(sSettings, "orglayer")
  if s then
    g_orglayer=s
  end

  s=GetVal(sSettings, "orgebt")
  if s and s~="" then
    g_orgebt  =tonumber(s)
  end

  s=GetVal(sSettings, "orgcnc")
  if s and s~="" then
    g_orgcnc  =tonumber(s)
  end

  s = GetVal(sSettings, "applyAngled")
  if s and s ~= "" then
    g_applyAngled = tonumber(s)
  end
end



function GetDefaults()
  g_matidorg=nil
  g_zofforg=0
  g_matiddouble=nil
  g_zoffdouble=0
  g_orglayer=""
  g_orgebt=0
  g_orgcnc=1
  g_applyAngled=0
  return true
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  -- Ask material
  local m1, m2

  m1, m2 = DoSettingsDlg(sSettings)
  if m1==nil then
    return nil
  end

  s=string.format("matorg=%s\nmatdouble=%s\nzofforg=%.4f\nzoffdouble=%.4f\norglayer=%s\norgebt=%d\norgcnc=%d\napplyAngled=%d", m1, m2, g_zofforg, g_zoffdouble, g_orglayer, g_orgebt, g_orgcnc, g_applyAngled)
  return s
end


-- SETTINGS
-------------------------


-- ### Reinforce uses - dbl top/bottom not

g_reinforceOverEnd=0.010      -- Oversize towards stud end
g_reinforceOverIn=0.002       -- Other dir
g_reinforceOverSide=0.001     -- For sides
g_reinforceDist=0             -- Distance from top/bottom

function FindConnStuds(tblCurr, bTop)
  local tblRes, tblFind
  local y, x1, x2, y1, y2, nRes, m

  tblRes={}
  nRes=0

  if gAddAllStuds then
    for nPlank=1,gnPlanks do
      ac_objectopen(string.format("#%d", nPlank))
      s=ac_objectget("iElemGroup")
      if string.match(s, "vertical_%a*") then
        nRes=nRes+1
        tblRes[nRes]=nPlank
      end
      ac_objectclose()
    end
    return tblRes
  end

  y1 = tblCurr.tblElemData.y1 - tblCurr.thickness * 0.5
  if g_dontApplyAngled == 1 then
    y2 = y1 + tblCurr.thickness
  else
    x1 = tblCurr.tblElemData.x1
    x2 = tblCurr.tblElemData.x2
    y2 = tblCurr.tblElemData.y2 -- tblCurr.thickness * 0.5

    -- Calculate y on the angled sill with slope-intercept form
    local dy = y2 - y1
    local dx = x2 - x1
    m = dy/dx

    -- y1 & y2 is on the center line, so adjust to the lower edge and use the lower y as the y-intercept
    y = math.min(y1, y2)
  end

  x1=tblCurr.tblElemData.x1 - 0.001
  x2=tblCurr.tblElemData.x2 + 0.001

  if x1>x2 then
    x1,x2=x2,x1
  end

  for nPlank=1,gnPlanks do
    ac_objectopen(string.format("#%d", nPlank))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^vertical_%a*") then
      tblFind=ac_objectget("#af_elemdata")


      if g_dontApplyAngled == 0 then
        local x = math.max(tblFind.x2, tblFind.x1)
        y1 = m * x + y
      end

      -- ac_environment("tolog", string.format("math.abs(%f - %f)<0.0051=%s   %f<%f and %f>%f=%s", y1, tblFind.y2,tostring(math.abs(y1 - tblFind.y2)<0.0051), x1, tblFind.x2, x2, tblFind.x2, tostring(x1<tblFind.x2 and x2>tblFind.x2)))

      -- 0.0051 comes from 5 mm grooves
      if ((bTop==true and math.abs(y1 - tblFind.y2)<0.0051) or (bTop==false and math.abs(y2 - tblFind.y1)<0.0051)) and x1<tblFind.x2 and x2>tblFind.x2 then
        nRes=nRes+1
        tblRes[nRes]=nPlank
        -- ac_environment("tolog", string.format("%f - %f = %f --- x1=%f x2=%f tblFind.x2=%f", y1, tblFind.y2, math.abs(y1-tblFind.y2), x1, x2, tblFind.x2))
      else
      end
    end
    ac_objectclose()
  end

  return tblRes
end


function GetThickness()
  local width

  width=ac_objectget("iWidth")
  if width==nil or width==0.0 then
    width=ac_objectget("A")
  end
   return width
end


-- justCheck  true=do not connect, just check if there are split pieces
-- Returns: New number of planks
function DoJoin(tblPlanks, nPlanks)
  local i, firstInd, x1, y1, x2, y2, hasX, dist1, len1, dist2, len2, lenCurr, dx, dy, dest

  if nPlanks<2 then
    return nPlanks
  end

  table.sort( tblPlanks,  function(p1, p2)
                            return p1.tblElemData.x1<p2.tblElemData.x1
                          end )

  -- Join all connecting ones to the first piece
  firstInd=1
  dest=1
  for i=2,#tblPlanks do
    local currPlank, v, joined

    currPlank=tblPlanks[firstInd]
    v=tblPlanks[i]
    x1=currPlank.tblElemData.x1
    y1=currPlank.tblElemData.y1
    x2=currPlank.tblElemData.x2
    y2=currPlank.tblElemData.y2

    hasX=ac_geo("linex", x1, y1, x2, y2, v.tblElemData.x1, v.tblElemData.y1, v.tblElemData.x2, v.tblElemData.y2)
    dist1,len1 = ac_geo("linedist", x1, y1, x2, y2, v.tblElemData.x1, v.tblElemData.y1)
    dist2,len2 = ac_geo("linedist", x1, y1, x2, y2, v.tblElemData.x2, v.tblElemData.y2)

    joined=false
    if not hasX and math.abs(dist1)<0.0001 and math.abs(dist2)<0.0001 and math.abs(currPlank.plankinfo.width-v.plankinfo.width)<0.0001 and math.abs(currPlank.plankinfo.height-v.plankinfo.height)<0.0001 and currPlank.matid==v.matid then
      -- Parallel and same material
      if len2<len1 then
        len1,len2=len2,len1
      end

      dx=x2-x1
      dy=y2-y1
      lenCurr=math.sqrt(dx*dx+dy*dy)
      if len2>-0.001 and len1<lenCurr+0.001 then
        -- Join to this
        dx = dx / lenCurr
        dy = dy / lenCurr
        if len1 < 0 then
          -- Move beg
          currPlank.tblElemData.x1 = currPlank.tblElemData.x1 + dx * len1
          currPlank.tblElemData.y1 = currPlank.tblElemData.y1 + dy * len1
          currPlank.plankinfo.len = currPlank.plankinfo.len - len1
        end
        if len2 > lenCurr then
          -- Move end
          currPlank.tblElemData.x2 = currPlank.tblElemData.x2 + dx * (len2 - lenCurr)
          currPlank.tblElemData.y2 = currPlank.tblElemData.y2 + dy * (len2 - lenCurr)
          currPlank.plankinfo.len = currPlank.plankinfo.len + (len2 - lenCurr)
        end

        -- Studs
        local stud

        for stud=1,#v.tblStuds do
          currPlank.tblStuds[#currPlank.tblStuds+1]=v.tblStuds[stud]
        end

        currPlank.lastjoinedptr=v.ptr
        joined=true
      end
    end

    if not joined then
      tblPlanks[dest]=tblPlanks[firstInd]
      dest=dest+1
      firstInd=i
    end
  end
  return dest
end

-- Creates table of matching planks
-- Table fields: index, thickness, matid, tblElemData, tblStuds
-- Returns table, number of items
function FindPlanks(sGroup, bTop)
  local tblPlanks, nPlanks

  tblPlanks, nPlanks = FindPlanksInt(sGroup, bTop)
  if tblPlanks and gbJoinSources then
    -- Join cut planks if same dir, material
    nPlanks = DoJoin(tblPlanks, nPlanks)
  end

  return tblPlanks, nPlanks
end


function FindPlanksInt(sGroup, bTop)
  local nPlank, s
  local tblRes, tblNow, tblInfo
  local nRes, i, v

  nRes = 0
  tblRes = {}
  if gtblSelPlanks then
    -- Check if selection contains wanted group and use it if yes
    for i, v in pairs(gtblSelPlanks) do
      ac_objectopen(v)
      s = ac_objectget("iElemGroup")

      tblNow = nil
      tblInfo = af_request("plankinfo")
      if s ~= nil and s == sGroup and tblInfo and not tblInfo.del then
        tblNow = {}
        tblNow.ptr = tblInfo.ptr
        tblNow.plankinfo = tblInfo
        tblNow.elemgroup = s
        tblNow.thickness = GetThickness()
        tblNow.matid = ac_objectget("iMatId")
        tblNow.tblElemData = ac_objectget("#af_elemdata")
        if tblNow.tblElemData then      -- If selected from multiple elements - will return data only if related to current element
        tblNow.index = tblNow.tblElemData.index
        tblNow.index = tblNow.tblElemData.index
        nRes = nRes+1
        tblRes[nRes] = tblNow
       else
          tblNow = nil
       end
      end
      ac_objectclose()

      if tblNow ~= nil then
        tblNow.tblStuds = FindConnStuds(tblNow, bTop)
      end
    end

    if nRes > 0 then
      return tblRes, nRes
    end
  end

  for nPlank=1,gnPlanks do
    ac_objectopen(string.format("#%d", nPlank))
    s=ac_objectget("iElemGroup")
    tblNow=nil
    tblInfo=af_request("plankinfo")

    if s==sGroup and tblInfo and not tblInfo.del then
      nRes=nRes+1
      tblNow={}
      tblNow.ptr=tblInfo.ptr
      tblNow.plankinfo=tblInfo
      tblNow.elemgroup=s
      tblNow.thickness=GetThickness()
      tblNow.matid=ac_objectget("iMatId")
      tblNow.tblElemData=ac_objectget("#af_elemdata")
      tblNow.index=tblNow.tblElemData.index
      tblRes[nRes]=tblNow
    end
    ac_objectclose()

    if tblNow~=nil then
      tblNow.tblStuds=FindConnStuds(tblNow, bTop)
    end
  end


  return tblRes,nRes
end


-- Adds reinforcement plank next to top/bottom sill and to front or/and back
-- Returns xml to make grooves to the studs
function DoReinforce(bTop, sTopBotGroup, sDoubleGroup, sTiltedGroup, sMatId, bFront, sGroupName)
  local nPlank,s
  local tblDouble, tblTop   -- Fields: index, guid, thickness, matid, tblElemData, tblStuds
  local nDouble, nTop, nTopIndex, matInfo, tblTilt, nTilt

  gAddAllStuds=true
  gtblSelPlanks=af_request("getselplanks")
  tblTop,nTop=FindPlanks(sDoubleGroup, bTop)
  if nTop==0 then
    tblTop,nTop=FindPlanks(sTopBotGroup, bTop)
  end
  if sTiltedGroup~=nil then
    -- Handling also tilted (gable walls), add those
    tblTilt, nTilt=FindPlanks(sTiltedGroup, bTop)
    if nTilt>0 then
      -- Merge
      for nTopIndex=1,nTilt do
        nTop=nTop+1
        tblTop[nTop] = tblTilt[nTopIndex]
      end
    end
  end

  if nTop==0 then
    RaiseError("CANNOT FIND TOP/BOTTOM PLANK")
    return ""
  end

  if sMatId==nil or sMatId=="" then
    sMatId=af_request("elem_getstudmat")
  end

  matInfo=af_request("singlemat", sMatId)
  if matInfo==nil then
    RaiseError(string.format("CANNOT FIND MATERIAL ID=%s", sMatId))
    return ""
  end

  strXmlOp=""
  -- Add new
  local tblNew, tblTopNow, dx, dy, xOff, yOff, len, offset, sStuds

  for nPlank=1,nTop do
    tblTopNow=tblTop[nPlank]

    tblNew={}
    tblNew.force=3            -- Keep lintels
    tblNew.id=sMatId
    tblNew.guidsettings=tblTopNow.ptr
    tblNew.group=sGroupName
    dx=tblTopNow.tblElemData.x2 - tblTopNow.tblElemData.x1
    dy=tblTopNow.tblElemData.y2 - tblTopNow.tblElemData.y1
    len=math.sqrt(dx*dx + dy*dy)

    if len>0.001 then
      len=1/len
      dx=dx*len
      dy=dy*len
      offset=tblTopNow.thickness*0.5+g_reinforceDist
      dx,dy=-dy,dx        -- For bottom (comes ok if plank goes from left to right)
      if dy<0 then
        dx=-dx
        dy=-dy
      end
      if bTop then
        offset=offset+matInfo.height
        offset=-offset
      end
      tblNew.x1=tblTopNow.tblElemData.x1+offset*dx
      tblNew.y1=tblTopNow.tblElemData.y1+offset*dy
      tblNew.x2=tblTopNow.tblElemData.x2+offset*dx
      tblNew.y2=tblTopNow.tblElemData.y2+offset*dy
      tblNew.zoff=matInfo.thickness*0.5
      if not bFront then
        tblNew.zoff=af_request("elemcorethickness") - matInfo.thickness*0.5
      end

      tblNew.rotangle=90   -- refline at bottom
      tblNew.mayturn=1
      --tblNew.xmlsettings="<s><objparam name=\"iCnc\">0</objparam></s>"

      -- May have been joined pieces
      local endptr

      endptr=tblTopNow.lastjoinedptr
      if endptr==nil then
        endptr=tblTopNow.ptr
      end

      tblNew.postlua=
string.format(
"<s>\n" ..
"ac_objectopen(\"%s\")\n" ..
"planeBeg=af_request(\"getbegendplane\", \"beg\")\n" ..
"ac_objectclose()\n" ..
"ac_objectopen(\"%s\")\n" ..
"planeEnd=af_request(\"getbegendplane\", \"end\")\n" ..
"ac_objectclose()\n" ..
"ac_objectopen(\"#%d\")\n" ..
"af_request(\"adjustbegend\", \"beg\", planeBeg)\n" ..
"af_request(\"adjustbegend\", \"end\", planeEnd)\n" ..
"ac_objectclose()\n" ..
"</s>",
tblTopNow.ptr,
endptr,
gnPlanks+gnPlankCount+1 )

      gnPlankCount=gnPlankCount+1
      gtblCreate[gnPlankCount] = tblNew

      -- Grooves from this plank
      sStuds=""
      for i,v in ipairs(tblTopNow.tblStuds) do
        -- Set oversize to top&bottom, other side will be cutting air (and makes sure the groove goes all the way to the plank's end
        if sStuds~="" then
          sStuds=sStuds .. ","
        end
        sStuds=sStuds .. v
      end
      if sStuds~="" then
        local overbot, overtop

        -- Plank is always bottom down
        overbot=g_reinforceOverEnd
        overtop=g_reinforceOverIn
        if bTop then
          overbot=g_reinforceOverIn
          overtop=g_reinforceOverEnd
        end
        strXmlOp = string.format(
            "%s" ..
            "<groove target=\"#%s\" operator=\"#%d\">\n" ..
            "    <groove overtop=\"%.3f\" overbot=\"%.3f\" overside=\"%.3f\" overlen=\"0.1\" force90=\"1\"></groove>\n" ..
            "</groove>\n",
            strXmlOp, sStuds, gnPlanks+gnPlankCount, overtop, overbot, g_reinforceOverSide
          )
      end
    end
  end

  -- Join tilted planks together, NOPE ADJUST
  if false then
    strXmlOp = string.format(
        "%s" ..
        "<joinends target=\"%s\" operator=\"%s\">\n" ..
        "    <joinends conntype=\"linex\" jointgap=\"0\"></joinends>\n" ..
        "</joinends>\n",
        strXmlOp, sGroupName, sGroupName )
  end

  -- Add xml-operations to be run after new planks are initialized
  return strXmlOp
end

------------------------------------------------------------------------------------------------------------------------------------------------------
]]>
        </script>


        <!-- Splits to two pieces/joints back top&bottom woods -->
        <script id="splittopbot">
          <![CDATA[
-- For planks to be created
gnPlankCount=0
gtblCreate = {}

gnRotFront=0     -- Added 4/2021 to rotate piece outwards from the element: 0/1
gnRotBack=0


-- Formats message so that calling program shows just the msg
-- Message can be empty - nothing is showed then (if operation canceled)
function RaiseError(msg)
	msg="###>" ..  msg .. "<###"
	error( msg )
end


gtblSelPlanks=nil

function GetThickness()
	local	width
	
	width=ac_objectget("iWidth")
	if width==nil or width==0.0 then
		width=ac_objectget("A")
	end
   return width
end

function GetHeight()
	local	width
	
	width=ac_objectget("iHeight")
	if width==nil or width==0.0 then
		width=ac_objectget("B")
	end
   return width
end

-- Creates table of matching planks
-- Table fields: index, thickness, height, matid, tblElemData
-- Returns table, number of items
function FindPlanks(sGroup, bTop)
  local nPlank,s
  local tblRes, tblNow, tblInfo
  local nRes, i, v
  
  nRes=0
  tblRes={}
  if gtblSelPlanks then
    -- Check if selection contains wanted group and use it if yes
    for i,v in pairs(gtblSelPlanks) do
      ac_objectopen(v)
      s=ac_objectget("iElemGroup")
      
      tblNow=nil
      if s~=nil and s==sGroup then
        tblInfo=af_request("plankinfo")
        if tblInfo.del~=true then
          tblNow={}
          tblNow.ptr=tblInfo.ptr
          tblNow.thickness=GetThickness()
          tblNow.height=GetHeight()
          tblNow.matid=ac_objectget("iMatId")
          tblNow.tblElemData=ac_objectget("#af_elemdata")
          if tblNow.tblElemData then      -- If selected from multiple elements - will return data only if related to current element
            tblNow.index=tblNow.tblElemData.index
            nRes=nRes+1
            tblRes[nRes]=tblNow
          else
            tblNow=nil
          end

        end
      end
      ac_objectclose()

    end

    if nRes>0 then
      return tblRes,nRes
    end
  end

  for nPlank=1,gnPlanks do
    ac_objectopen(string.format("#%d", nPlank))
    s=ac_objectget("iElemGroup")
    tblNow=nil
    if s==sGroup then
      tblInfo=af_request("plankinfo")
      if tblInfo.del~=true then
        nRes=nRes+1
        tblNow={}
        tblNow.ptr=tblInfo.ptr
        tblNow.thickness=GetThickness()
        tblNow.height=GetHeight()
        tblNow.matid=ac_objectget("iMatId")
        tblNow.tblElemData=ac_objectget("#af_elemdata")
        tblNow.index=tblNow.tblElemData.index
        tblRes[nRes]=tblNow
      end
    end
    ac_objectclose()
  end

  return tblRes,nRes
end


function ChangeMat(guidPlank, matId, bTop)
  local tblMat, level, prevThick

  tblMat=af_request("singlemat", matId)
  ac_objectopen(guidPlank)
  prevThick=GetThickness()
  ac_objectset("iMatId", matId)
  ac_objectset("iWidth", tblMat.thickness)
  ac_objectset("iHeight", tblMat.height)

  level=ac_objectget("#level")
  if bTop then
    level=level+(tblMat.thickness-prevThick)*0.5
  else
    level=level-(tblMat.thickness-prevThick)*0.5
  end

  ac_objectset("#level", level)
  ac_objectclose()
end


-- bAdd true=adding, false=deleting, nil=on/off
function DoSplitTopBot(bTop, sTopBotGroup, sDoubleGroup, bAdd, idSplitFront, idSplitBack)
  local nPlank,s
  local tblDouble, tblTop   -- Fields: index, guid, thickness, matid, tblElemData
  local nDouble, nTop, nTopIndex
  local thicknessSplit


  --idSplitFront="42x98"
  --idSplitBack="42x42"

  gtblSelPlanks=af_request("getselplanks")
  tblDouble,nDouble=FindPlanks(sDoubleGroup, bTop)
  tblTop,nTop=FindPlanks(sTopBotGroup, bTop)
  
  if nTop==0 then
    -- No error msg if from option dlg
    if gbTop==nil then
      RaiseError("CANNOT FIND TOP/BOTTOM PLANK")
    end
    return
  end

  if bAdd~=nil then
    if bAdd then
      if nDouble>0 then
        return
      end
    else
      -- Removing
      if nDouble==0 then
        return
      end
    end
  end

  strXmlOp=""
  if nDouble>0 then
    -- Remove
    for nPlank=1,nDouble do
      -- Set zero length to be cleaned away
      ac_objectopen(string.format("#%d", tblDouble[nPlank].index))
      af_request("delplank")
      ac_objectclose()
    end
    
    -- Change material to default
    local matId
    
    matId=af_request("elem_getstudmat")
    for nPlank=1,nTop do
      tblTopNow=tblTop[nPlank]
      ChangeMat(string.format("#%d", tblTopNow.index), matId, bTop)
      
      -- Unrotate if was rotated by new feature added 4/2021      
      local tblEdit, info

      tblEdit={}
          
      ac_objectopen(string.format("#%d", tblTopNow.index))
      tblEdit.elemdata=ac_objectget("#af_elemdata")
      info=af_request("plankinfo")
      ac_objectclose()

      if math.abs(tblEdit.elemdata.rotangle+90)<0.01 then
        -- Unrotate and offset
        tblEdit.guid=info.ptr

        tblEdit.elemdata.rotangle=0
        tblEdit.elemdata.y1=tblEdit.elemdata.y1-info.width*0.5
        tblEdit.elemdata.y2=tblEdit.elemdata.y2-info.width*0.5
        tblEdit.elemdata.z1=0
        tblEdit.elemdata.z2=0

        af_request("editplank", tblEdit)
      end
    end

  else
    -- Change existing to smaller and add new
    local tblNew, tblTopNow, tblMat, level

    for nPlank=1,nTop do
      tblTopNow=tblTop[nPlank]
      
      -- Back piece
      tblMat=af_request("singlemat", idSplitBack)
      if not tblMat then
        error(string.format("No material %s. ### PLEASE OPEN SETTINGS ### ", idSplitBack))
      end

      tblNew={}
      tblNew.guidsettings=tblTopNow.ptr
      tblNew.group=sDoubleGroup
      tblNew.x1=tblTopNow.tblElemData.x1
      tblNew.x2=tblTopNow.tblElemData.x2
      if bTop then
        tblNew.y1=tblTopNow.tblElemData.y1+(tblMat.thickness-tblTopNow.thickness)*0.5
        tblNew.y2=tblTopNow.tblElemData.y2+(tblMat.thickness-tblTopNow.thickness)*0.5
      else
        tblNew.y1=tblTopNow.tblElemData.y1-(tblMat.thickness-tblTopNow.thickness)*0.5
        tblNew.y2=tblTopNow.tblElemData.y2-(tblMat.thickness-tblTopNow.thickness)*0.5
      end

      tblNew.zoff=tblTopNow.height-tblMat.height
      tblNew.id=idSplitBack
      tblNew.rotAngle=0
      
      if gnRotBack==1 then
        -- We put just to bottom
        tblNew.rotangle=-90
        tblNew.y1=tblNew.y1+tblMat.thickness*0.5
        tblNew.y2=tblNew.y2+tblMat.thickness*0.5
        tblNew.zoff=tblNew.zoff+tblMat.height-tblMat.thickness*0.5
      end

      gnPlankCount=gnPlankCount+1
      gtblCreate[gnPlankCount] = tblNew

      -- Change front piece material
      ChangeMat(string.format("#%d", tblTopNow.index), idSplitFront, bTop)
      if gnRotFront==1 then
        -- We put just to bottom
        local tblEdit, info

        tblEdit={}
          
        ac_objectopen(string.format("#%d", tblTopNow.index))
        tblEdit.elemdata=ac_objectget("#af_elemdata")
        info=af_request("plankinfo")
        ac_objectclose()

        tblEdit.guid=info.ptr
        tblMat=af_request("singlemat", idSplitFront)
        if not tblMat then
          error(string.format("No material %s. ### PLEASE OPEN SETTINGS ### ", idSplitBack))
        end

        tblEdit.elemdata.rotangle=-90
        tblEdit.elemdata.y1=tblEdit.elemdata.y1+tblMat.thickness*0.5
        tblEdit.elemdata.y2=tblEdit.elemdata.y2+tblMat.thickness*0.5
        tblEdit.elemdata.z1=tblMat.thickness*0.5
        tblEdit.elemdata.z2=tblMat.thickness*0.5

        af_request("editplank", tblEdit)
      end
    end
  end

  return ""
end



-------------------------
-- FOR OPTION DLG

--Set these:
--gbTop
--gsTopBotGroup
--gsSplitGroup


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gsSplitGroup .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


function Set(sSettings)
  local default, res, errStr

  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end
  
  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end  

--ac_environment("tolog", string.format("g_matidfront=%s, g_matidback=%s", tostring(g_matidfront), tostring(g_matidback)) )
  res=DoSplitTopBot(gbTop, gsTopBotGroup, gsSplitGroup, true, g_matidfront, g_matidback)

  af_request("elem_createplanks")
end


function Reset()
  local res

  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end

  res=DoSplitTopBot(gbTop, gsTopBotGroup, gsSplitGroup, false, nil, nil)
  af_request("elem_createplanks")     -- To adjust the studs
  return res
end


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Asks for the material to use
-- sSettings may be nil, otherwise matfront=xxx\nmatback=xxx
-- Returns two values: matfront, matback
function AskMat(sSettings)
  local	tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    
    
  tblMat=af_request("matlist")
  s=""
  strSep=""

--ac_environment("tolog", dump(tblMat))
  tblSorted={}
  i=1
  for id,v in pairs(tblMat) do
    if v.thickness>0.001 then
  		tblSorted[i]=v
	  	i=i+1
	  end
  end

	table.sort(tblSorted, function (n1, n2)
    return n1.index < n2.index
	end)

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end

	tblSettings={}
	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=1
	tblSettings[1].prompt	="Material front"
	tblSettings[1].key		="matfront"
	tblSettings[1].valuelist=s
	tblSettings[1].defvalue	=1

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=1
	tblSettings[2].prompt	="Material back"
	tblSettings[2].key		="matback"
	tblSettings[2].valuelist=s
	tblSettings[2].defvalue	=1

  tblSettings[3]			={}
  tblSettings[3].cfgonly	=0
  tblSettings[3].type		=2
  tblSettings[3].prompt	="Rotate front 90 deg"
  tblSettings[3].key		="rotfront"
  tblSettings[3].defvalue	=0

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=2
  tblSettings[4].prompt	="Rotate back 90 deg"
  tblSettings[4].key		="rotback"
  tblSettings[4].defvalue	=0


  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      for i=1,#tblSorted do
        if tblSorted[i].id==g_matidfront then
          tblSettings[1].value=i
        end
        if tblSorted[i].id==g_matidback then
          tblSettings[2].value=i
        end
      end
    else
      ac_environment( "tolog", string.format("AskMat/parse settings failed: %s", tostring(err)) )
    end
  end

	bRes,sErr=ac_optiondlg("LDSB", "Split materials", tblSettings)
	if not bRes then
    return
  end

  gnRotFront=tblSettings[3].value
  gnRotBack=tblSettings[4].value

  return tblSorted[tblSettings[1].value], tblSorted[tblSettings[2].value]
end




-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals: g_matidfront, g_matidback
function ParseSettings(sSettings)
  local s, mat, val
  
  --ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )

  mat=GetVal(sSettings, "matfront")
  g_matidfront=af_request("singlemat", mat).id
  mat=GetVal(sSettings, "matback")
  g_matidback=af_request("singlemat", mat).id

  gnRotFront=0
  val=GetVal(sSettings, "rotfront")
  if val then
    gnRotFront=tonumber(val)
  end

  gnRotBack=0
  val=GetVal(sSettings, "rotback")
  if val then
    gnRotBack=tonumber(val)
  end

  -- Will cause error if bad syntax
  s = string.format("%s, %s", g_matidfront, g_matidback)
end


function GetDefaults()
  g_matidfront="42x42"
  g_matidback="42x42"
  gnRotFront=0
  gnRotBack=0
  return true
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("matfront=%s\nmatback=%s\nrotfront=%d\nrotback=%d", g_matidfront, g_matidback, gnRotFront, gnRotBack)
    end
  end
  -- Ask material
  local matfront, matback

  matfront, matback = AskMat(sSettings)
  if matfront==nil then
    return nil
  end

  s=string.format("matfront=%s\nmatback=%s\nrotfront=%d\nrotback=%d", matfront.id, matback.id, gnRotFront, gnRotBack)
  return s
end


-- FOR OPTION DLG
-------------------------

]]>
        </script>

<script id="boardedgesupport">
<![CDATA[

------------------------------------------------------------------------------------------------------------
-- HELPERS
--

PI  = 3.141592653589793
PI2 = PI * 0.5
EPS = 0.001


-- Dumps given variable into string
function DumpTblInt(o, nIndent)
  local s,k,v
  
  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end

    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end

    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end


-- 
-- LineList
--
-- A small utility class for storing unique 2D-lines with (c1, c2 -coordinates) in 1-based table.
-- Operations:
-- LineList:New()
-- LineList:Insert(l)
-- LineList:InsertFlat(l)
-- LineList:Find(c)
-- LineList:Get()
-- LineList:ToFlat()
-- Linelist:Print()

LineList = {}

function LineList:New()
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  self.lines = {}
  return o
end


function LineList:Insert(l)
  local v
  local found = false
  for _, v in ipairs(self.lines) do
    if math.abs(v.c1.x - l.c1.x) < EPS and
       math.abs(v.c1.y - l.c1.y) < EPS and
       math.abs(v.c2.x - l.c2.x) < EPS and
       math.abs(v.c2.y - l.c2.y) < EPS then
      found = true
      break
    end
  end

  if not found then
    self.lines[#self.lines + 1] = l
    return true
  end

  return false
end


function LineList:InsertFlat(l)
  local ll = { c1 = {x = l.x1, y = l.y1 }, c2 = { x = l.x2, y = l.y2 } }
  return self:Insert(ll)
end


function LineList:Find(c)
  local v
  for _, v in ipairs(self.lines) do
    if math.abs(v.c1.x - c.x) < EPS and math.abs(v.c1.y - c.y) < EPS or
       math.abs(v.c2.x - c.x) < EPS and math.abs(v.c2.y - c.y) < EPS then
      return v
    end
  end
  return nil
end


-- Get the 1-based table of lines:
-- ll = LineList:new() 
-- ll:insert({ c1 = { x = 0, y = 0}, c2 = { x = 1, y = 1} })
-- #ll:get()        => 1
-- ll:get()[1].c1.x => 0
function LineList:Get()
  return self.lines
end


-- Returns a new table consisting of the LineList's lines converted into a flat format of (x1,y1,x2,y2).
function LineList:ToFlat()
  local r, v
  r = {}
  for _, v in ipairs(self.lines) do
    r[#r + 1] = { x1 = v.c1.x, y1 = v.c1.y, x2 = v.c2.x, y2 = v.c2.y }
  end
  return r
end


function LineList:Print()
  local v
  for _, v in ipairs(self.lines) do
    ac_environment("tolog", string.format("c1.x=%f c1.y=%f c2.x=%f c2.y=%f", v.c1.x, v.c1.y, v.c2.x, v.c2.y))
  end
end


--
-- Higher-order helpers on tables
--

function filter(t, f)
  local v
  local r = {}

  for _, v in ipairs(t) do
    if not f(v) then r[#r + 1] = v end
  end

  return r
end


function collect(t, f)
  local r = {}
  local v

  for _, v in ipairs(t) do
    if f(v) then r[#r + 1] = v end
  end

  return r
end


-- Gets AF's default material list and sorts it. Returns the sorted table and string of the the material IDs suitable for dialogs.
function GetSortedMaterials()
  local tblMaterials, tblSortedMaterials
  local strMaterials
  local s = ""
  local strSep = ""
  local i, id, v

  tblMaterials = af_request("matlist")

  tblSortedMaterials = {}
  for id, v in pairs(tblMaterials) do
      tblSortedMaterials[v.index] = v
  end
   
  for i, v in ipairs(tblSortedMaterials) do					
    s = string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep = ","
  end
  
  return tblSortedMaterials, s
end


function Normalized(dx, dy)
  local len = math.sqrt(dx * dx + dy * dy)
  if len > 0.0001 then
    local inv = 1.0 / len
    return dx * inv, dy * inv
  else
    return 0, 0
  end
end


function Direction(x1, y1, x2, y2)
  local dx = x2 - x1
  local dy = y2 - y1
  return Normalized(dx, dy)
end


function Length(x1, y1, x2, y2)
  local dx = x2 - x1
  local dy = y2 - y1
  return math.sqrt(dx * dx + dy * dy)
end


--
-- HELPERS
------------------------------------------------------------------------------------------------------------



------------------------------------------------------------------------------------------------------------
-- SETTINGS
--

-- Constants
SIDE_FRONT = 1
SIDE_BACK  = 2

SPACING_FIXED     = 1
SPACING_OVERRIDE  = 2
SPACING_AUTOMATIC = 3

SPACING_START_TOP    = 1
SPACING_START_BOTTOM = 2

MATERIAL_ROTATION_0  = 1
MATERIAL_ROTATION_90 = 2

ADJUST_GROOVES        = 1
ADJUST_BETWEEN_STUDS  = 2

FRAMING_ROTATION_0    = 1
FRAMING_ROTATION_90   = 2

-- Global configuration variables
g_partsToAdjust    = ADJUST_GROOVES
g_side             = 1
g_material         = 4
g_materialRotation = MATERIAL_ROTATION_90
g_topMaterial      = 1
g_bottomMaterial   = 1
g_oversizeTop      = 0.001
g_oversizeBottom   = 0.001
g_oversizeBehind   = 0.001
g_oversizeEnds     = 0.100
g_spacingStartOffset = 0
g_spacingRuleStart = SPACING_START_BOTTOM
g_spacingRule      = SPACING_AUTOMATIC
g_spacingValue     = 2.7
g_addToTop         = 0
g_addToBottom      = 0
g_tblSpacingPos    = {}
g_framingRotAngle  = FRAMING_ROTATION_0

function GetDefaults()
  local tblSortedMaterials, strMaterials = GetSortedMaterials()
  local matId

  for id, v in pairs(tblSortedMaterials) do
    if v.height ~= 0 and v.thickness ~= 0 then
      matId = v.index
      break
    end
  end

  g_partsToAdjust    = ADJUST_GROOVES
  g_material         = matId
  g_materialRotation = MATERIAL_ROTATION_90
  g_topMaterial      = 1
  g_bottomMaterial   = 1

  g_oversizeTop    = 0.001
  g_oversizeBottom = 0.001
  g_oversizeBehind = 0.001
  g_oversizeEnds   = 0.100
  
  g_spacingStartOffset = 0.0
  
  g_spacingRuleStart = SPACING_START_BOTTOM
  g_spacingRule      = SPACING_AUTOMATIC
  g_spacingValue     = 2.7
  g_framingRotAngle  = FRAMING_ROTATION_0

  g_addToTop = 0
  g_addToBottom = 0
  
  g_tblSpacingPos = {}
  for i = 1, 10 do
    g_tblSpacingPos[i] = 999.999
  end
  
  return true
end

-- Gets a value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    -- ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Helpers for getting values / index from tblSettings -table.
function GetValueFromTable(tbl, key)
  for i = 1,#tbl do
	  if tbl[i].key == key then
	    return tbl[i].value
	  end
	end
  error(string.format("key [%s] not found", key))
	--return nil
end


function GetTableIndex(tbl, key)
  for i = 1,#tbl do
    if tbl[i].key == key then
	    return i
    end
  end
  return 0
end


function RunSettingsDialog(sSettings)
  local tblSettings, bRes, sErr, s, i
  
  local strSpacingRule = "Spacing rule"
  local strSpacingRuleVal = "\"1:Fixed spacing\",\"2:Override\",\"3:Automatic\""
  
  local tblSortedMaterials, strMaterials = GetSortedMaterials()

  local defaultMaterial
  for id, v in pairs(tblSortedMaterials) do
    if v.height ~= 0 and v.thickness ~= 0 then
      defaultMaterial = v.index
      break
    end
  end

  tblSettings = {}
  idx = 1

  local strPartsToAdjust = "Parts to adjust"
  local strPartsToAdjustVal = "\"1:Grooves to studs\",\"2:Cut board edge support piece between studs\""

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 1 
  tblSettings[idx].prompt     = strPartsToAdjust
  tblSettings[idx].key        = "partsToAdjust"
  tblSettings[idx].valuelist  = strPartsToAdjustVal
  tblSettings[idx].defvalue   = ADJUST_GROOVES
  idx = idx + 1

  
  tblSettings[idx]	          = {}
  tblSettings[idx].cfgonly	  = 0
  tblSettings[idx].type		    = 1 
  tblSettings[idx].prompt     = "Material"
  tblSettings[idx].key        = "material"
  tblSettings[idx].valuelist  = strMaterials
  tblSettings[idx].defvalue   = defaultMaterial
  idx = idx + 1

  local strMaterialRotation = "Material rotation"
  local strMaterialRotationVal = "\"1:0 degrees\",\"2:90 degrees\""

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 1
  tblSettings[idx].prompt     = strMaterialRotation
  tblSettings[idx].key        = "materialRotation"
  tblSettings[idx].valuelist  = strMaterialRotationVal
  tblSettings[idx].defvalue   = 2
  idx = idx + 1
  
  -- tblSettings[idx]			      = {}
  -- tblSettings[idx].cfgonly	  = 0
  -- tblSettings[idx].type		    = 1
  -- tblSettings[idx].prompt     = "Top horizontal piece material"
  -- tblSettings[idx].valuelist  = strMaterials
  -- tblSettings[idx].key        = "topMaterial"
  -- tblSettings[idx].defvalue   = defaultLoadBearingMaterial
  -- idx = idx + 1
  
  -- tblSettings[idx]			      = {}
  -- tblSettings[idx].cfgonly	  = 0
  -- tblSettings[idx].type		    = 1
  -- tblSettings[idx].prompt     = "Bottom horizontal piece material"
  -- tblSettings[idx].valuelist  = strMaterials
  -- tblSettings[idx].key        = "bottomMaterial"
  -- tblSettings[idx].defvalue   = defaultMaterial
  -- idx = idx + 1

  local strFramingRotAngle = "Framing rotation"
  local strFramingRotAngleVal = "\"1:0 degrees\",\"2:90 degrees\""

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 1
  tblSettings[idx].prompt     = strFramingRotAngle
  tblSettings[idx].key        = "framingRotAngle"
  tblSettings[idx].valuelist  = strFramingRotAngleVal
  tblSettings[idx].defvalue   =  1
  idx = idx + 1

  local strSpacingStart = "Spacing rule start"
  local strSpacingStartVal = "\"1:Top\",\"2:Bottom\""
  
  tblSettings[idx]			      = {}
  tblSettings[idx].cfgonly	  = 0
  tblSettings[idx].type		    = 1 
  tblSettings[idx].prompt     = strSpacingStart
  tblSettings[idx].key        = "spacingRuleStart"
  tblSettings[idx].valuelist  = strSpacingStartVal
  tblSettings[idx].defvalue   =  1
  idx = idx + 1
 
  tblSettings[idx]			      = {}
  tblSettings[idx].cfgonly	  = 0
  tblSettings[idx].type		    = 3
  tblSettings[idx].prompt     = "Spacing start offset"
  tblSettings[idx].key        = "spacingStartOffset"
  tblSettings[idx].defvalue   = 0.0
  idx = idx + 1
     
  tblSettings[idx]			      = {}
  tblSettings[idx].cfgonly	  = 0
  tblSettings[idx].type		    = 1 
  tblSettings[idx].prompt     = strSpacingRule
  tblSettings[idx].key        = "spacingRule"
  tblSettings[idx].valuelist  = strSpacingRuleVal
  idx = idx + 1
  
  tblSettings[idx]			      = {}
  tblSettings[idx].cfgonly	  = 0
  tblSettings[idx].type		    = 3
  tblSettings[idx].prompt     = "Fixed spacing value"
  tblSettings[idx].key        = "spacingValue"
  tblSettings[idx].defvalue   = 2.7
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 2
  tblSettings[idx].prompt     = "Add to top"
  tblSettings[idx].key        = "addToTop"
  tblSettings[idx].defvalue   = 0
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 2
  tblSettings[idx].prompt     = "Add to bottom"
  tblSettings[idx].key        = "addToBottom"
  tblSettings[idx].defvalue   = 0
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 3 
  tblSettings[idx].prompt     = "Oversize top"
  tblSettings[idx].key        = "oversizeTop"
  tblSettings[idx].defvalue   = 0.001
  idx = idx + 1
  
  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 3 
  tblSettings[idx].prompt     = "Oversize bottom"
  tblSettings[idx].key        = "oversizeBottom"
  tblSettings[idx].defvalue   = 0.001
  idx = idx + 1
  
  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 3
  tblSettings[idx].prompt     = "Oversize behind"
  tblSettings[idx].key        = "oversizeBehind"
  tblSettings[idx].defvalue   = 0.001
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 3
  tblSettings[idx].prompt     = "Oversize ends"
  tblSettings[idx].key        = "oversizeEnds"
  tblSettings[idx].defvalue   = 0.001
  idx = idx + 1

  for i = 1, 10 do 
    tblSettings[idx]			      = {}
    tblSettings[idx].cfgonly	  = 0
    tblSettings[idx].type		    = 3 
    tblSettings[idx].prompt     = string.format("Spacing override #%d", i)
    tblSettings[idx].key        = string.format("spacingPos%d", i)
    tblSettings[idx].defvalue   = 999.999
    idx = idx + 1
  end
  
  if sSettings ~= nil and sSettings ~= "" then
    local res, err = pcall(ParseSettings, sSettings)
    if res then
      -- Populate saved settings to the actual table.
      tblSettings[GetTableIndex(tblSettings, "partsToAdjust")].value     = g_partsToAdjust
  	  tblSettings[GetTableIndex(tblSettings, "material")].value          = g_material
      tblSettings[GetTableIndex(tblSettings, "materialRotation")].value  = g_materialRotation
  	  -- tblSettings[GetTableIndex(tblSettings, "topMaterial")].value       = g_topMaterial
  	  -- tblSettings[GetTableIndex(tblSettings, "bottomMaterial")].value    = g_bottomMaterial
  	  tblSettings[GetTableIndex(tblSettings, "oversizeTop")].value       = g_oversizeTop
  	  tblSettings[GetTableIndex(tblSettings, "oversizeBottom")].value    = g_oversizeBottom
  	  tblSettings[GetTableIndex(tblSettings, "oversizeBehind")].value    = g_oversizeBehind
      tblSettings[GetTableIndex(tblSettings, "oversizeEnds")].value      = g_oversizeEnds
      tblSettings[GetTableIndex(tblSettings, "framingRotAngle")].value   = g_framingRotAngle
  	  tblSettings[GetTableIndex(tblSettings, "spacingStartOffset")].value = g_spacingStartOffset
  	  tblSettings[GetTableIndex(tblSettings, "spacingRuleStart")].value  = g_spacingRuleStart
  	  tblSettings[GetTableIndex(tblSettings, "spacingRule")].value       = g_spacingRule
  	  tblSettings[GetTableIndex(tblSettings, "spacingValue")].value      = g_spacingValue
      tblSettings[GetTableIndex(tblSettings, "addToTop")].value          = g_addToTop
      tblSettings[GetTableIndex(tblSettings, "addToBottom")].value       = g_addToBottom
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos1")].value       = g_tblSpacingPos[1]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos2")].value       = g_tblSpacingPos[2]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos3")].value       = g_tblSpacingPos[3]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos4")].value       = g_tblSpacingPos[4]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos5")].value       = g_tblSpacingPos[5]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos6")].value       = g_tblSpacingPos[6]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos7")].value       = g_tblSpacingPos[7]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos8")].value       = g_tblSpacingPos[8]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos9")].value       = g_tblSpacingPos[9]
  	  tblSettings[GetTableIndex(tblSettings, "spacingPos10")].value      = g_tblSpacingPos[10]
    else
      ac_environment( "tolog", string.format("RunSettingsDialog/parse settings failed: %s", tostring(err)) )
    end
  end

  gHelpAnchor="afdlgelemboardedge"
  bRes, sErr = ac_optiondlg("LDHP", "Board edge support", tblSettings)
  if not bRes then
    return false
  end
  
  -- User accepted the new settings, so store them into the globals.
  g_partsToAdjust    = GetValueFromTable(tblSettings, "partsToAdjust")
  g_material         = GetValueFromTable(tblSettings, "material")
  g_materialRotation = GetValueFromTable(tblSettings, "materialRotation")
  -- g_topMaterial      = GetValueFromTable(tblSettings, "topMaterial")
  -- g_bottomMaterial   = GetValueFromTable(tblSettings, "bottomMaterial")
  g_oversizeTop      = GetValueFromTable(tblSettings, "oversizeTop")
  g_oversizeBottom   = GetValueFromTable(tblSettings, "oversizeBottom")
  g_oversizeBehind   = GetValueFromTable(tblSettings, "oversizeBehind")
  g_oversizeEnds     = GetValueFromTable(tblSettings, "oversizeEnds")
  g_framingRotAngle = GetValueFromTable(tblSettings, "framingRotAngle")
  g_spacingStartOffset = GetValueFromTable(tblSettings, "spacingStartOffset")
  g_spacingRuleStart = GetValueFromTable(tblSettings, "spacingRuleStart")
  g_spacingRule      = GetValueFromTable(tblSettings, "spacingRule")
  g_spacingValue     = GetValueFromTable(tblSettings, "spacingValue")
  g_addToTop         = GetValueFromTable(tblSettings, "addToTop")
  g_addToBottom      = GetValueFromTable(tblSettings, "addToBottom")
  g_tblSpacingPos[1] = GetValueFromTable(tblSettings, "spacingPos1")
  g_tblSpacingPos[2] = GetValueFromTable(tblSettings, "spacingPos2")
  g_tblSpacingPos[3] = GetValueFromTable(tblSettings, "spacingPos3")
  g_tblSpacingPos[4] = GetValueFromTable(tblSettings, "spacingPos4")
  g_tblSpacingPos[5] = GetValueFromTable(tblSettings, "spacingPos5")
  g_tblSpacingPos[6] = GetValueFromTable(tblSettings, "spacingPos6")
  g_tblSpacingPos[7] = GetValueFromTable(tblSettings, "spacingPos7")
  g_tblSpacingPos[8] = GetValueFromTable(tblSettings, "spacingPos8")
  g_tblSpacingPos[9] = GetValueFromTable(tblSettings, "spacingPos9")
  g_tblSpacingPos[10] = GetValueFromTable(tblSettings, "spacingPos10")
  
  return true
end


-- Gives defVal if setting is missing from sSettings (new setting added)
function GetSettingNum(sSettings, key, defVal)
  local val
  
  val = GetVal(sSettings, key)
  if val then
    return tonumber(val)
  end
  return defVal
end


function ParseSettings(sSettings)
  -- Debugging helper for your sanity.
  -- ac_environment("tolog", string.format("%s", tostring(g_partsToAdjust)))
  -- ac_environment("tolog", string.format("%s", tostring(g_material)))
  -- ac_environment("tolog", string.format("%s", tostring(g_materialRotation)))
  -- ac_environment("tolog", string.format("%s", tostring(g_oversizeTop)))
  -- ac_environment("tolog", string.format("%s", tostring(g_oversizeBottom)))
  -- ac_environment("tolog", string.format("%s", tostring(g_oversizeBehind)))
  -- ac_environment("tolog", string.format("%s", tostring(g_oversizeEnds)))
  -- ac_environment("tolog", string.format("%s", tostring(g_spacingStartOffset)))
  -- ac_environment("tolog", string.format("%s", tostring(g_spacingRuleStart)))
  -- ac_environment("tolog", string.format("%s", tostring(g_spacingRule)))
  -- ac_environment("tolog", string.format("%s", tostring(g_spacingValue)))
  -- for i = 1, 10 do
  --   ac_environment("tolog", string.format("%s", tostring(g_tblSpacingPos[i])))
  -- end

  -- Defaults in case of new settings
  GetDefaults()
  
  g_partsToAdjust     = GetSettingNum(sSettings, "partsToAdjust", g_partsToAdjust)
  g_material          = GetSettingNum(sSettings, "material", g_material)
  g_materialRotation  = GetSettingNum(sSettings, "materialRotation", g_materialRotation)
  -- g_topMaterial       = tonumber(GetVal(sSettings, "topMaterial"))
  -- g_bottomMaterial    = tonumber(GetVal(sSettings, "bottomMaterial"))
  g_oversizeTop       = GetSettingNum(sSettings, "oversizeTop", g_oversizeTop)
  g_oversizeBottom    = GetSettingNum(sSettings, "oversizeBottom", g_oversizeBottom)
  g_oversizeBehind    = GetSettingNum(sSettings, "oversizeBehind", g_oversizeBehind)
  g_oversizeEnds      = GetSettingNum(sSettings, "oversizeEnds", g_oversizeEnds)
  g_framingRotAngle = GetSettingNum(sSettings, "framingRotAngle", g_framingRotAngle)
  g_spacingStartOffset        = GetSettingNum(sSettings, "spacingStartOffset", g_spacingStartOffset)
  g_spacingRuleStart  = GetSettingNum(sSettings, "spacingRuleStart", g_spacingRuleStart)
  g_spacingRule       = GetSettingNum(sSettings, "spacingRule", g_spacingRule)
  g_spacingValue      = GetSettingNum(sSettings, "spacingValue", g_spacingValue)
  g_addToTop          = GetSettingNum(sSettings, "addToTop", g_addToTop)
  g_addToBottom       = GetSettingNum(sSettings, "addToBottom", g_addToBottom)
  g_tblSpacingPos[1]  = GetSettingNum(sSettings, "spacingPos1", g_tblSpacingPos[1])
  g_tblSpacingPos[2]  = GetSettingNum(sSettings, "spacingPos2", g_tblSpacingPos[2])
  g_tblSpacingPos[3]  = GetSettingNum(sSettings, "spacingPos3", g_tblSpacingPos[3])
  g_tblSpacingPos[4]  = GetSettingNum(sSettings, "spacingPos4", g_tblSpacingPos[4])
  g_tblSpacingPos[5]  = GetSettingNum(sSettings, "spacingPos5", g_tblSpacingPos[5])
  g_tblSpacingPos[6]  = GetSettingNum(sSettings, "spacingPos6", g_tblSpacingPos[6])
  g_tblSpacingPos[7]  = GetSettingNum(sSettings, "spacingPos7", g_tblSpacingPos[7])
  g_tblSpacingPos[8]  = GetSettingNum(sSettings, "spacingPos8", g_tblSpacingPos[8])
  g_tblSpacingPos[9]  = GetSettingNum(sSettings, "spacingPos9", g_tblSpacingPos[9])
  g_tblSpacingPos[10] = GetSettingNum(sSettings, "spacingPos10", g_tblSpacingPos[10])

  SettingsToStr()
end


function Settings(sSettings)
  if sSettings == nil or sSettings == "" then
    if GetDefaults() then
      sSettings = SettingsToStr()
    end
  end
  
  if not RunSettingsDialog(sSettings) then
    return nil
  end

  local s = SettingsToStr()
  return s
end


-- Format a Settings String from the global setting variables and return it.
function SettingsToStr()
  -- use multiline string for easier editing
  local s = string.format([[
partsToAdjust=%s
material=%s
materialRotation=%0.6f
topMaterial=%s
bottomMaterial=%s
oversizeTop=%0.6f
oversizeBottom=%0.6f
oversizeBehind=%0.6f
oversizeEnds=%0.6f
framingRotAngle=%0.6f
spacingStartOffset=%0.6f
spacingRuleStart=%s
spacingRule=%s
spacingValue=%0.6f
addToTop=%d
addToBottom=%d
spacingPos1=%0.6f
spacingPos2=%0.6f
spacingPos3=%0.6f
spacingPos4=%0.6f
spacingPos5=%0.6f
spacingPos6=%0.6f
spacingPos7=%0.6f
spacingPos8=%0.6f
spacingPos9=%0.6f
spacingPos10=%0.6f
]], g_partsToAdjust, g_material, g_materialRotation, g_topMaterial, g_bottomMaterial, g_oversizeTop, g_oversizeBottom, g_oversizeBehind, g_oversizeEnds, g_framingRotAngle,
    g_spacingStartOffset, g_spacingRuleStart, g_spacingRule, g_spacingValue, g_addToTop, g_addToBottom, g_tblSpacingPos[1], g_tblSpacingPos[2], g_tblSpacingPos[3],
    g_tblSpacingPos[4], g_tblSpacingPos[5], g_tblSpacingPos[6], g_tblSpacingPos[7], g_tblSpacingPos[8], g_tblSpacingPos[9], g_tblSpacingPos[10])

--ac_environment("tolog", s)
  return s
end

--
-- SETTINGS
------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------
-- Board Edge Support SCRIPT
--

-- Check whether we have Board Edge Support pieces, and remove them if so.
-- Returns true if Board Edge Support pieces were found and deleted, false if not.
function Reset()
  local res = false
  local i, s

  af_request("elem_getpoly")
  for i=1, gnPlanks do
    ac_objectopen(string.format("#%d", i))

    s = ac_objectget("iElemGroup")
    if string.match(s, g_OptGroupName) then
      s = af_request("delplank")
      res = true
    end

    ac_objectclose()
  end

  return res
end

-- Check whether we already have Board Edge Support pieces.
-- Returns: -1 = Not known / no planks
--           0 = No Board Edge Support pieces
--           1 = Has Board Edge Support pieces
function Has()
  local i

  af_request("elem_getpoly")

  if gnPlanks == 0 then
    return -1
  end

  for i = 1, gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s = ac_objectget("iElemGroup")

    if string.match(s, g_OptGroupName) then
      ac_objectclose()
      return 1
    end

    ac_objectclose()
  end

  return 0
end


function GetName(sSettings, baseName)
  return baseName
end


function Set(sSettings)
  af_request("elem_getpoly")
  if gnPlanks == 0 then
    return
  end

  if sSettings ~= nil then
    res, errStr = pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end

  DoBoardEdgeSupport()
  
end


function GetElemCamera(guid)
  local tblQuantSettings = {}
  tblQuantSettings.quant = 0
  local tblQuantities = af_request("elem_quantities", guid, 1, tblQuantSettings)
  if not tblQuantities then
    return nil
  end

  local tblCam = {}
  tblCam.begc = tblQuantities.geoframing.orig
  tblCam.vecx = tblQuantities.geoframing.vecx
  tblCam.vecy = tblQuantities.geoframing.vecy
  tblCam.vecz = tblQuantities.geoframing.vecz

  return tblCam
end


function PrintCamera(o, x, y, z)
    ac_environment("tolog", string.format("o.x=%f\t\to.y=%f\t\to.z=%f", o.x, o.y, o.z))
    ac_environment("tolog", string.format("x.x=%f\t\tx.y=%f\t\tx.z=%f", x.x, x.y, x.z))
    ac_environment("tolog", string.format("y.x=%f\t\ty.y=%f\t\ty.z=%f", y.x, y.y, y.z))
    ac_environment("tolog", string.format("z.x=%f\t\tz.y=%f\t\tz.z=%f\n\n", z.x, z.y, z.z))
end


-- Gets element's polygon by projecting the polygon based on the framing direction.
function GetElemPoly(guid, addHoles)
  local tblCam = GetElemCamera(guid)
  if not tblCam then
    return nil
  end

  local tblPolySettings = {}
  tblPolySettings.side = 2
  tblPolySettings.givelist = 1
  tblPolySettings.holes = 0
  if addHoles then
    tblPolySettings.holes = nil
  end
  tblPolySettings.camera = tblCam
  return af_request("getpoly", tblPolySettings, guid)
end


-- GetRelatedBoardPolygons
-- 
-- Arguments:
--   nDirToBoard  -1 = check prev layer (front)
--                 1 = check next layer (back)
-- Returns: tblRelatedBoards or nil if there are no related boards in the requested direction.
function GetRelatedBoardPolygons(nDirToBoard)
  local nCurrentLayer, i, v, nDir

  if nDirToBoard == SIDE_FRONT then
    nDir = -1
  elseif nDirToBoard == SIDE_BACK then
    nDir = 1
  else
    ac_environment("tolog", string.format("GetRelatedBoards: invalid direction argument: %s", tostring(nDirToBoard)))
    return nil
  end

  local tblSettings = {}
  tblSettings.quant = 0

  -- Find current element layer from the composite
  local tblQuantities = af_request("elem_quantities", gGuidElem, 1, tblSettings)

  for i = 1, #tblQuantities.tblelems do
    v = tblQuantities.tblelems[i]
    if v.guid == gGuidElem then
      nCurrentLayer = i
      break
    end
  end

  -- Project all planks to current layer
  tblCam = {}
  tblCam.begc = tblQuantities.geoframing.orig
  tblCam.vecx = tblQuantities.geoframing.vecx
  tblCam.vecy = tblQuantities.geoframing.vecy
  tblCam.vecz = tblQuantities.geoframing.vecz

  -- PrintCamera(tblCam.begc, tblCam.vecx, tblCam.vecy, tblCam.vecz)

  -- Find board layer
  local tblElemBoard = tblQuantities.tblelems[nCurrentLayer + nDir]
  if not tblElemBoard or not tblElemBoard.tblboards then
    -- ac_environment("tolog", string.format("No layer having boards at index %d", nCurrentLayer + nDirToBoard))
    return nil
  end

  local nPolys = 0
  local tblPolys = {}
  local tblGuids = {}

  tblSettings = {}
  tblSettings.side = 2    -- Front ok for now
  tblSettings.givelist = 1
  tblSettings.holes = 0
  tblSettings.camera = tblCam

  for i, v in ipairs(tblElemBoard.tblboards) do
    if not v.ispanel or v.ispanel == 0 then
      local tblPoly = af_request("getpoly", tblSettings, v.guid)

      nPolys = nPolys + 1
      tblPolys[nPolys] = tblPoly
      tblGuids[nPolys] = v.guid
    end
  end

  -- DumpTbl(tblPolys)

  tblSettings.tblguids = tblGuids
  tblUnified = af_request("getpoly", tblSettings, nil)

  return tblPolys, tblUnified
end



-- Round value to `places` decimal places
function RoundTo(x, places)
  local n = 10 ^ places
  local r = 0.5
  if x * n < 0 then
    r = -0.5
  end
  local i, f = math.modf(x * n + r)
  return i / n
end


-- Returns VECTOR x,y,z transformed
function MatTransformVec( x, y, z, tblTran )
  local xnew, ynew, znew

  xnew=x*tblTran[1]+ y*tblTran[2]+ z*tblTran[3]
  ynew=x*tblTran[5]+ y*tblTran[6]+ z*tblTran[7]
  znew=x*tblTran[9]+ y*tblTran[10]+ z*tblTran[11]
  return xnew, ynew, znew
end


-- Returns point x,y,z transformed
function MatTransformPt( x, y, z, tblTran )
  return MatTransformVec( x+tblTran[4], y+tblTran[8], z+tblTran[12], tblTran )
end


function SidePointToElem(currSide, x2d, y2d, tranElem, z2d)
  local x,y,z

  if z2d==nil then
    z2d=0
  end

  x=currSide.origc.x + x2d*currSide.vecx.x + y2d*currSide.vecy.x + z2d*currSide.vecz.x
  y=currSide.origc.y + x2d*currSide.vecx.y + y2d*currSide.vecy.y + z2d*currSide.vecz.y
  z=currSide.origc.z + x2d*currSide.vecx.z + y2d*currSide.vecy.z + z2d*currSide.vecz.z

  return MatTransformPt(x, y, z, tranElem)
end


-- tblPolyPoints  For example af_request("getpoly", nil, elem.guid). CHANGED HERE (Note, seems not to be changed)
function GetLayerPolyLines(tblPolyPoints, skipHoles)
  -- First collect lines (to be able to change those to opening top/bottom cuts and to filter out vecNoCuts with simpler logic)
  -- c1 has always code isendcontour. c2 is then the contour begin pt
  local tblLine, endv
  local tblLines = {}
  local nLines = 0
  local begInd = 1
  local prev = nil

  for i,v in ipairs(tblPolyPoints) do
    if prev then
      tblLine={}
      tblLine.cutfromobj=prev.cutfromobj
      tblLine.c1=prev
      tblLine.c2=v
      nLines=nLines+1
      tblLines[nLines]=tblLine
    end

    prev = v
    if v.isendcontour then
      -- Duplicate start point, coordinates already changed
      endv = tblPolyPoints[begInd]

      tblLine = {}
      tblLine.cutfromobj = v.cutfromobj
      tblLine.c1 = v
      tblLine.c2 = endv

      nLines = nLines+1
      tblLines[nLines] = tblLine

      if v.isendpolygon or skipHoles then
        break
      end

      begInd = i+1
      prev = nil
    end
  end

  return tblLines

end -- GetLayerPoly


--  vecX,vecY,vecZ  Vektori, jonka ympärillä pyöritellään. Yksikkövektori!!
--  addX,addY,addZ  Siirto
--  angle     Pyörityskulma
-- out:
--  tranTbl[12]
function Rotate3Dinit(vecX, vecY, vecZ, addX, addY, addZ, angle)
  local cosAngle, sinAngle, ucosAngle, tranTbl

  cosAngle=math.cos(angle)
  sinAngle=math.sin(angle)
  ucosAngle=1-cosAngle
  tranTbl={}

  tranTbl[1]=ucosAngle*vecX*vecX+cosAngle
  tranTbl[2]=ucosAngle*vecX*vecY-vecZ*sinAngle
  tranTbl[3]=ucosAngle*vecZ*vecX+vecY*sinAngle
  tranTbl[4]=addX

  tranTbl[5]=ucosAngle*vecX*vecY+vecZ*sinAngle
  tranTbl[6]=ucosAngle*vecY*vecY+cosAngle
  tranTbl[7]=ucosAngle*vecY*vecZ-vecX*sinAngle
  tranTbl[8]=addY

  tranTbl[9]=ucosAngle*vecZ*vecX-vecY*sinAngle
  tranTbl[10]=ucosAngle*vecY*vecZ+vecX*sinAngle
  tranTbl[11]=ucosAngle*vecZ*vecZ+cosAngle
  tranTbl[12]=addZ

  return tranTbl
end


-- ### Pyörittää 3D-pistettä annetun vektorin ympäri. Kutsu Rotate3Dinit ennen tätä.
-- in:
-- xin, yin, zin
-- out:
-- x, y, z
function Rotate3D(tranTbl, xin, yin, zin)
  local x, y, z
  x=tranTbl[1]*xin + tranTbl[2]*yin + tranTbl[3]*zin  + tranTbl[4]
  y=tranTbl[5]*xin + tranTbl[6]*yin + tranTbl[7]*zin + tranTbl[8]
  z=tranTbl[9]*xin + tranTbl[10]*yin + tranTbl[11]*zin + tranTbl[12]
  return x,y,z
end


-- ### Pyörittää 3D-pistettä annetun vektorin ympäri pitäen edellisen Rotate3DInit-arvot kuosissa
-- in:
-- xin, yin, zin, angle
-- vecX, vecY, vecZ Minkä vektorin ympäri pyöritellään
-- out:
-- _x, _y, _z
function RotateSingle3D(xin, yin, zin, vecX, vecY, vecZ, angle)
  local tranTbl = Rotate3Dinit(vecX, vecY, vecZ, 0, 0, 0, angle)
  return Rotate3D(tranTbl, xin, yin, zin)
end


function GetRotationMatrices()
  local rot, inv

  rot = Rotate3Dinit(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, PI2)
  inv = Rotate3Dinit(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -PI2)

  return rot, inv
end


-- Returns true if the element has 90 deg rotated framing in the core layer
function ElemHasRotatedFraming(tblElemQuant)
  local s, e, k, v

  if tblElemQuant.tblelems then
    for k, v in pairs(tblElemQuant.tblelems) do
      s, e = string.find(v.xmlutf8, "rotframing=")
      if s and e then
        if string.sub(v.xmlutf8, e+2, e+3) == "90" then
          return true
        end
      end
    end
  end
  return false
end


function FindBucket(buckets, k)
  for i, v in ipairs(buckets) do
    if math.abs(v.key - k) < EPS then return v end
  end
  return nil
end


function CreateBuckets(tblLines)
  local buckets = {}

  for i, v in ipairs(tblLines) do
    local bucket = FindBucket(buckets, v.c1.y)

    if bucket then
      local n = #bucket.values + 1
      bucket.values[n] = v
    else
      local n = #buckets + 1
      buckets[n] = {}
      buckets[n].key = v.c1.y
      buckets[n].values = {}
      buckets[n].values[1] = v
    end
  end

  return buckets
end


function Unify(tblLines)
  local i, v, res
  local tblBuckets = CreateBuckets(tblLines)

  res = {} 

  for k, v in pairs(tblBuckets) do 
    local pt = {}
    pt.c1 = {x = v.values[1].c1.x, y = v.key}
    pt.c2 = {x = v.values[1].c2.x, y = v.key}

    if pt.c1.x > pt.c2.x then
      pt.c1, pt.c2 = pt.c2, pt.c1
    end

    if #v.values > 1 then
      for i = 2, #v.values do
        local p = v.values[i]

        if p.c1.x > p.c2.x then
          p.c1, p.c2 = p.c2, p.c1
        end

        if p.c1.x < pt.c1.x then
          pt.c1.x = p.c1.x
        end

        if p.c2.x > pt.c2.x then
          pt.c2.x = p.c2.x
        end
      end
    end

    res[#res + 1] = pt
  end

  return res
end


function WholeElement(tblElemPoly, l)
  -- ac_environment("tolog", string.format("c1.x=%f x1=%f c2.x=%f x2=%f", l.c1.x, tblElemPoly.x1, l.c2.x, tblElemPoly.x2))
  return math.abs(l.c1.x - tblElemPoly.x1) < EPS and math.abs(l.c2.x - tblElemPoly.x2) < EPS
end


function OnElementEdge(tblElemPoly, l)
  return math.abs(l.c1.y - tblElemPoly.y1) < EPS or math.abs(l.c2.y - tblElemPoly.y2) < EPS or
         math.abs(l.c1.y - tblElemPoly.y2) < EPS or math.abs(l.c2.y - tblElemPoly.y1) < EPS
end


function PointEq(p1, p2)
  return math.abs(p1.x - p2.x) < EPS and math.abs(p1.y - p2.y) < EPS
end


-- Helper for printing tables of lines (c1, c2 pairs)
function PrintTbl(sHeader, tblLines)
  ac_environment("tolog", sHeader)
  for _, v in ipairs(tblLines) do
    ac_environment("tolog", string.format("  v.c1.x=%f v.c1.y=%f v.c2.x=%f v.c2.y=%f", v.c1.x, v.c1.y, v.c2.x, v.c2.y))
  end
end



-- Segment handling beg ***
-- Data is 1-based table of structs having fields x1,x2
function SegInitSingle(x1, x2)
  local tblCoords,t

  t={}
  t.x1=x1
  t.x2=x2
  tblCoords={}
  tblCoords[1]=t
  return tblCoords
end

-- Returns new segment array taking x1,x2 away from seg
function SegDifference(seg, x1, x2)
  local u1, curr1, currx1, currx2
  local tblDest, destn, t
  local eps=0.0005

  tblDest={}
  destn=0
  for u1,curr1 in ipairs(seg) do
    currx1=curr1.x1
    currx2=curr1.x2
    if currx1+eps>x2 or currx2-eps<x1 then
      -- No removing, add as whole
      t={}
      t.x1=currx1
      t.x2=currx2
      destn=destn+1
      tblDest[destn]=t
    else
      -- Perhaps overlaps, add perhaps split parts
      if currx1<x1-eps then
        t={}
        t.x1=currx1
        t.x2=x1
        destn=destn+1
        tblDest[destn]=t
      end
      
      if currx2>x2+eps then
        t={}
        t.x1=x2
        t.x2=currx2
        destn=destn+1
        tblDest[destn]=t
      end
    end
  end
  
  return tblDest
end

function SegDump(prompt, seg)
  local u1, curr1, s
  
  s=prompt
  for u1,curr1 in ipairs(seg) do
    s=s..string.format(" x1=%f x2=%f", curr1.x1, curr1.x2)
  end
  ac_environment("tolog", s)
end

-- Segment handling end ***


-- Adds parts of lv not intersecting with elemLines to target polyLines
function AddNoEdgeX(elemLines, lv, polyLines)
  local seg, k, v, len, d1, l1, d2, l2
  local eps=0.005   -- Big eps used on purpose
  
  len=Length(lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y)
  seg = SegInitSingle(0, len)
  
  for k,v in ipairs(elemLines) do
    d1, l1 = ac_geo("linedist", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v.c1.x, v.c1.y)
    d2, l2 = ac_geo("linedist", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v.c2.x, v.c2.y)
--ac_environment("tolog", string.format("d1=%f, l1=%f, lv.c1.x=%f, lv.c1.y=%f, lv.c2.x=%fx, lv.c2.y=%f, v.c1.x=%f, v.c1.y=%f", d1, l1, lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v.c1.x, v.c1.y))
--ac_environment("tolog", string.format("d2=%f, l2=%f, lv.c1.x=%f, lv.c1.y=%f, lv.c2.x=%fx, lv.c2.y=%f, v.c2.x=%f, v.c2.y=%f", d2, l2, lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v.c2.x, v.c2.y))
    if math.abs(d1)<eps and math.abs(d2)<0.005  then
      -- On the same line, subtract common part
      if l1>l2 then
        l1, l2 = l2, l1
      end
      
      if l2>0 and l1<len then
        -- Subtract part
--ac_environment("tolog", string.format("e: x1=%f y1=%f x2=%f y2=%f, l: x1=%f y1=%f x2=%f y2=%f, l1=%f l2=%f", v.c1.x, v.c1.y, v.c2.x, v.c2.y, lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, l1, l2))
        seg = SegDifference(seg, l1, l2)
      end
    end
  end
  
  local dx, dy, t
  
  dx, dy = Direction(lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y)

  for k,v in ipairs(seg) do
    if v.x2 - v.x1 > eps then
      t={}
      t.c1={}
      t.c1.x = lv.c1.x + v.x1 * dx
      t.c1.y = lv.c1.y + v.x1 * dy

      t.c2={}
      t.c2.x = lv.c1.x + v.x2 * dx
      t.c2.y = lv.c1.y + v.x2 * dy
      
      polyLines[#polyLines + 1] = t
--ac_environment("tolog", string.format("a: x1=%f y1=%f x2=%f y2=%f", t.c1.x, t.c1.y, t.c2.x, t.c2.y))
    end
  end
  
end


-- Support should be created for all horizontal (w.r.t framing orientation) board polygon edges that are not on the element edges.
-- BUT these polygon edges are not the ones that are on the hole/opening edges.
-- UNUSED: tblRot, tblInvRot, framingRotAngle
function AutomaticPositions(tblElemPolyWithHoles, tblPolys, tblUnified, tblRot, tblInvRot, tblMaterial, materialRotation, framingRotAngle)
  local v, vp, lv
  --local tblPlankInfo = af_request("plankinfo", gGuidElem)
  
  
--DumpTbl(tblElemPolyWithHoles)  
--DumpTbl(tblPolys)  

  local matOffset = 0.0
  if materialRotation == MATERIAL_ROTATION_90 then
    matOffset = tblMaterial.height / 2.0
  end

  -- Collect all edge lines from the main element so that we can subtract these edges from board polygon edges
  local elemLines = {}
  for _, vp in ipairs(tblElemPolyWithHoles.poly) do
    local t = GetLayerPolyLines(vp)     -- Elem poly with holes
    for _, lv in ipairs(t) do
      if math.abs(lv.c1.y - lv.c2.y) < 0.001 then
        -- Collect only support dir candidates
        elemLines[#elemLines + 1] = lv
      end
    end
  end

--PrintTbl("elemLines", elemLines)

  -- Lines from board
  local polyLines = {}
  for _, v in ipairs(tblPolys) do
    for _, vp in ipairs(v.poly) do
      local t = GetLayerPolyLines(vp, true)
      for _, lv in ipairs(t) do
        if math.abs(lv.c1.y - lv.c2.y) < 0.001 then
          -- Collect only support dir candidates, now subtract any element edge from this
          -- Clip to the framing polygon (this will also remove exact edge lines)
          local clipLines = ac_geo("linepolyx", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, tblElemPolyWithHoles.poly, false, false)   
        
          if clipLines then
            for _, cv in ipairs(clipLines) do
              local tl={}
          
              tl.c1={}
              tl.c1.x=cv.x1
              tl.c1.y=cv.y1
          
              tl.c2={}
              tl.c2.x=cv.x2
              tl.c2.y=cv.y2
          
              AddNoEdgeX(elemLines, tl, polyLines)
            end
          end
          
        end
      end
    end
  end

--PrintTbl("PolyLines", polyLines)

  -- Same here.
  local lines = polyLines     -- We collected only right ones: collect(polyLines, function(l) return math.abs(l.c1.y - l.c2.y) < EPS end)
  table.sort(lines, function(l1, l2) return l1.c1.y < l2.c1.y end)
  lines = Unify(lines)

--PrintTbl("Lines", lines)

  -- Results are inserted here.
  local uniqueLines = LineList:New()

  for _, v in pairs(lines) do
    -- ac_environment("tolog", string.format("c1.x=%f c1.y=%f c2.x=%f c2.y=%f", v.c1.x, v.c1.y, v.c2.x, v.c2.y))

    -- y-placement adjusted by the material size
    local vy = v.c1.y - matOffset

    uniqueLines:InsertFlat({ x1 = v.c1.x, y1 = vy, x2 = v.c2.x, y2 = vy })
  end

  return uniqueLines:ToFlat()
end -- AutomaticPositions


-- Helper function for calculating plank line position for SPACING_FIXED.
--
-- tblMaterial        => selected material's table
-- materialRotation   => 0.0 or 90.0
-- spacingStartOffset => [0.0, X]
-- spacingStartRule   => SPACING_START_BOTTOM or SPACING_START_TOP
-- spacingValue       => x > 0

function FixedPositions(tblElemPoly, tblMaterial, materialRotation, spacingStartRule, spacingStartOffset, spacingValue)
  local tblRet = {}

  local min = math.min(tblElemPoly.y1, tblElemPoly.y2)
  local max = math.max(tblElemPoly.y1, tblElemPoly.y2)

  local y = spacingValue
  local startY = spacingStartOffset
  if spacingStartRule == SPACING_START_BOTTOM then
    startY = min + startY
  else
    startY = max - startY
  end

  if materialRotation == MATERIAL_ROTATION_90 then
    startY = startY - (tblMaterial.height * 0.5)
  end

  tblRet[#tblRet + 1] = {x1=tblElemPoly.x1, x2=tblElemPoly.x2, y1=startY, y2=startY}

  prev = startY
  local i = 1
  while true do
    local tblLine = {}
    tblLine.x1 = tblElemPoly.x1
    tblLine.x2 = tblElemPoly.x2
    if spacingStartRule == SPACING_START_TOP then
      tblLine.y1 = prev - y * i
    else
      tblLine.y1 = prev + y * i
    end
    tblLine.y2 = tblLine.y1

    if tblLine.y1 < min or tblLine.y1 > max then
      return tblRet
    end

    i = i + 1
    tblRet[#tblRet + 1] = tblLine
  end

  return tblRet
end


-- Helper function for calculating plank line position for SPACING_OVERRIDE.
--
-- tblMaterial        => selected material's table
-- materialRotation   => 0.0 or 90.0
-- spacingStartRule   => SPACING_START_BOTTOM or SPACING_START_TOP
-- spacingStartOffset => [0.0, X]
-- tblSpacingPos      => table of spacing positions
--
-- Returns: tblLine = {x1,y1,x2,y2} or nil on error.
function OverridenPositions(tblElemPoly, tblMaterial, materialRotation, spacingStartRule, spacingStartOffset, tblSpacingPos)
  local tblRet = {}
  local i = 1

  local min = math.min(tblElemPoly.y1, tblElemPoly.y2)
  local max = math.max(tblElemPoly.y1, tblElemPoly.y2)

  while true do
    local spacingPos = tblSpacingPos[i]
    if spacingPos == 999.999 then
      return tblRet
    end

    spacingPos = spacingPos + spacingStartOffset

    local tblLine = {}
    tblLine.x1 = tblElemPoly.x1
    tblLine.x2 = tblElemPoly.x2

    -- Account for material rotation, otherwise the piece will jump upwards half the material thickness
    if spacingStartRule == SPACING_START_BOTTOM then
      if materialRotation == MATERIAL_ROTATION_0 then
        tblLine.y1 = min + spacingPos
      else
        tblLine.y1 = min + spacingPos - (tblMaterial.height * 0.5)
      end
    else -- SPACING_START_TOP
      if materialRotation == MATERIAL_ROTATION_0 then
        tblLine.y1 = max - spacingPos
      else
        tblLine.y1 = max - spacingPos - (tblMaterial.height * 0.5)
      end
    end

    tblLine.y2 = tblLine.y1

    if tblLine.y1 < min or tblLine.y1 > max then
      return tblRet
    end

    tblRet[#tblRet + 1] = tblLine

    i = i + 1
  end

  return tblRet
end


-- Rotates in-place
-- tblRot Rotation matrix
-- poly   Polygon fetched with setting givelist=1 producing poly.poly as 1-based list of separate polygons
function RotPolyList(tblRot, poly)
  local kpoly, vpoly, k, v

  for kpoly, vpoly in ipairs(poly.poly) do
    for k, v in ipairs(vpoly) do
      -- ac_environment("tolog", string.format("x=%f y=%f z=0.0", v.x, v.y))
      v.x, v.y = Rotate3D(tblRot, v.x, v.y, 0.0)
      -- ac_environment("tolog", string.format("x'=%f y'=%f z=%f", v.x, v.y, z))
    end
  end

--ac_environment("tolog", string.format("pre: x1=%f y1=%f x2=%f y2=%f", poly.x1, poly.y1, poly.x2, poly.y2))
  -- Polygon bounds
  poly.x1, poly.y1 = Rotate3D(tblRot, poly.x1, poly.y1, 0.0)
  poly.x2, poly.y2 = Rotate3D(tblRot, poly.x2, poly.y2, 0.0)
  if poly.x1 > poly.x2 then
    poly.x1, poly.x2 = poly.x2, poly.x1
  end

  if poly.y1 > poly.y2 then
    poly.y1, poly.y2 = poly.y2, poly.y1
  end
--ac_environment("tolog", string.format("pos: x1=%f y1=%f x2=%f y2=%f", poly.x1, poly.y1, poly.x2, poly.y2))
end


--
-- The actual script.
--
function DoBoardEdgeSupport()
  local i, s, v, id
  local settingsGuid, info

  for i=1, gnPlanks do
    ac_objectopen(string.format("#%d", i))
      local t         = ac_objectget("#af_elemdata")
      info            = af_request("plankinfo")
      -- tblElemPlankMat = af_request("singlemat", info.matname)
    ac_objectclose()

    if not settingsGuid then
      settingsGuid = info.ptr
      break
    end
  end

  --
  -- Material selection
  --
  local hasTopMaterial = false
  if g_topMaterial then
    hasTopMaterial = true
  end

  local hasBottomMaterial = false
  if g_bottomMaterial then
    hasBottomMaterial = true
  end

  -- Store material tables for placement calculations.
  local tblMaterial, tblTopMaterial, tblBottomMaterial
  local tblSortedMaterials, strMaterials = GetSortedMaterials()
  for id, v in pairs(tblSortedMaterials) do
    if v.index == g_material then
      tblMaterial = v
    end

    if hasTopMaterial and v.index == g_topMaterial then
      tblTopMaterial = v
    end

    if hasBottomMaterial and v.index == g_bottomMaterial then
      tblBottomMaterial = v
    end
  end

  if not tblMaterial then
    error("primary material selection failed")
  end

    if hasTopMaterial and not tblTopMaterial then
    error("top material selection failed")
  end

  if hasBottomMaterial and not tblBottomMaterial then
    error("bottom material selection failed")
  end

  --
  -- Calculations
  --
  local materialId        = tblMaterial.id
  local materialThickness = tblMaterial.thickness
  local materialHeight    = tblMaterial.height

  local tblRot, tblInvRot = GetRotationMatrices()

  local tblElemPoly = GetElemPoly(gGuidElem)
  local tblElemPolyWithHoles = GetElemPoly(gGuidElem, true)
  local infoElem = af_request("plankinfo", gGuidElem)

  -- DumpTbl(tblElemPoly)

  -- Acquire polygons for the element holes and openings (if any).
  local tblElemQuant = af_request("elem_quantities", gGuidElem, 0)

  local tblPolys, tblPolyUnified
  if g_spacingRule == SPACING_AUTOMATIC then
    tblPolys, tblPolyUnified = GetRelatedBoardPolygons(g_side)
    if tblPolys==nil then
      ac_environment("tolog", "Board support: Cannot find related boards, skipped")
      return
    end
  end

  -- Rotate everything to the common orientation if we're using FRAMING_ROTATION_90 from the dialog.
  -- This is otherwise handled by rotframing in the element.
  if g_framingRotAngle == FRAMING_ROTATION_90 then
    RotPolyList(tblRot, tblElemPoly)
    RotPolyList(tblRot, tblElemPolyWithHoles)
  
    local p, k

    for k, p in pairs(tblPolys) do
      RotPolyList(tblRot, p)
    end

    RotPolyList(tblRot, tblUnified)
  end

  local tblPositions
  local nPositions = 1

  if g_spacingRule == SPACING_AUTOMATIC then
    tblPositions = AutomaticPositions(tblElemPolyWithHoles, tblPolys, tblUnified, tblRot, tblInvRot, tblMaterial, g_materialRotation, g_framingRotAngle)
  elseif g_spacingRule == SPACING_FIXED then
    tblPositions = FixedPositions(tblElemPoly, tblMaterial, g_materialRotation, g_spacingRuleStart, g_spacingStartOffset, g_spacingValue)
  elseif g_spacingRule == SPACING_OVERRIDE then
    tblPositions = OverridenPositions(tblElemPoly, tblMaterial, g_materialRotation, g_spacingRuleStart, g_spacingStartOffset, g_tblSpacingPos)
  end

  if not tblPositions then
    ac_environment("tolog", "failed to generate support positions")
    return
  end

  -- DumpTbl(tblPositions)

  -- For plank creation
  local rotAngle = 0.0
  if g_materialRotation == MATERIAL_ROTATION_90 then
    rotAngle = 90.0
  end

  -- zoff moves the piece on the horizontal plane (from the front toward the back)
  local zoff = 0.0
  if g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_0 then
    zoff = infoElem.width - materialHeight
  elseif g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_90 then
    zoff = infoElem.width - (materialThickness * 0.5)
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_0 then
    zoff = 0.0
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_90 then
    zoff = 0.5 * materialThickness
  end

  --
  -- Create the planks.
  --
  local tblPlankCuts = {}
  local nPlankCuts = 0

  gnPlankCount = 0
  gtblCreate = {}

  local nTotalPlanks = 0

  while true do
    local nPlank = 1
    local tblPlanks = {}

    tblPlanks[nPlank] = {}
    tblPlanks[nPlank].id = materialId

    local tblLine = nil
    if tblPositions[nPositions] then
      tblLine = tblPositions[nPositions]
      nPositions = nPositions + 1
    end

    if not tblLine then
      break
    end

    tblPlanks[nPlank].x1 = tblLine.x1
    tblPlanks[nPlank].x2 = tblLine.x2
    tblPlanks[nPlank].y1 = tblLine.y1
    tblPlanks[nPlank].y2 = tblLine.y2

    -- Check if we're still inside the bounding box of the element.
    if nTotalPlanks > 0 then
      -- in some cases we can generate a line this is actually inside the opening, and thus it doesn't hit the polygon (is 'outside' it)
      local ret = ac_geo("linepolyx", tblPlanks[nPlank].x1, tblPlanks[nPlank].y1, tblPlanks[nPlank].x2, tblPlanks[nPlank].y2, tblElemPoly.poly)
      if ret == nil then
        -- DumpTbl(tblElemPoly.poly)
        -- DumpTbl(tblPlanks[nPlank])
        -- Stop creating planks once we're out of the element's bounds.
        break
      end
    end

    local plankDirX, plankDirY = Direction(tblPlanks[nPlank].x1, tblPlanks[nPlank].y1, tblPlanks[nPlank].x2, tblPlanks[nPlank].y2)

    local off
    if g_materialRotation == MATERIAL_ROTATION_0 then
      off = materialThickness * 0.5
    else
      off = materialHeight * 0.5
    end

    local tblPlankY = {}
    tblPlankY[1] = tblPlanks[nPlank].y1 - off * 2
    tblPlankY[2] = tblPlanks[nPlank].y1 - off
    tblPlankY[3] = tblPlanks[nPlank].y1

    -- Inspect the element's planks, see if they're in the same direction as the new plank we're about to place
    for i = 1, gnPlanks do
      ac_objectopen(string.format("#%d", i))
        local tblElemData         = ac_objectget("#af_elemdata")

        if g_framingRotAngle == FRAMING_ROTATION_90 then
          local tblRot, tblInvRot = GetRotationMatrices()
          tblElemData.x1, tblElemData.y1, _ = Rotate3D(tblRot, tblElemData.x1, tblElemData.y1, 0.0)
          tblElemData.x2, tblElemData.y2, _ = Rotate3D(tblRot, tblElemData.x2, tblElemData.y2, 0.0)
        end

        local pdx, pdy = Direction(tblElemData.x1, tblElemData.y1, tblElemData.x2, tblElemData.y2)
        -- ac_environment("tolog", string.format("pdx=%f pdy=%f plankDirX=%f plankDirY=%f", pdx, pdy, plankDirX, plankDirY))

        -- DumpTbl(tblPlanks[nPlank])
        -- ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f", tblPlanks[nPlank].x1, tblPlanks[nPlank].y1, tblPlanks[nPlank].x2, tblPlanks[nPlank].y2))
        -- ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f", tblElemData.x1, tblElemData.y1, tblElemData.x2, tblElemData.y2))
        -- ac_environment("tolog", "\n")

        -- Same direction, check if the bounding boxes match

        if math.abs(plankDirX - math.abs(pdx)) < 0.01 and math.abs(plankDirY - math.abs(pdy)) < 0.01 then
          local tblPoly = {}
          tblPoly[1] = {}

          if g_framingRotAngle == FRAMING_ROTATION_90 then
            for nVertex = 1, #tblElemData.poly do
              local polyX, polyY, _ = Rotate3D(tblRot, tblElemData.poly[nVertex].x, tblElemData.poly[nVertex].y, 0.0)
              tblPoly[1][nVertex] = { x = polyX, y = polyY }
            end
          end

          for j = 1, #tblPlankY do
            local intersected, x1, x2, y1, y2

            x1 = tblPlanks[nPlank].x1
            x2 = tblPlanks[nPlank].x2
            y1 = tblPlankY[j]
            y2 = tblPlankY[j]

            intersected = ac_geo("linepolyx", x1, y1, x2, y2, tblPoly)
            if intersected then
              -- ac_environment("tolog", string.format("Plank %s %s %s %s", tostring(tblPlanks[nPlank].x1), tostring(tblPlankY[j]), tostring(tblPlanks[nPlank].x2), tostring(tblPlankY[j])))
              -- ac_environment("tolog", string.format("HolePlank (%f, %f), (%f, %f), (%f, %f), (%f, %f)", tblPoly[1][1].x, tblPoly[1][1].y, tblPoly[1][2].x, tblPoly[1][2].y, tblPoly[1][3].x, tblPoly[1][3].y, tblPoly[1][4].x, tblPoly[1][4].y))
              -- ac_environment("tolog", string.format("Plank x1=%f y1=%f x2=%f y2=%f", x1, y1, x2, y2))

              nPlankCuts = nPlankCuts + 1
              tblPlankCuts[nPlankCuts] = {}
              tblPlankCuts[nPlankCuts].plankNum = gnPlanks + gnPlankCount + 1
              tblPlankCuts[nPlankCuts].plankToCut = i
              break
            end
          end -- for
        end -- if abs
      ac_objectclose()
    end -- for #gnPlanks

    for i = 1, #tblPlanks do

      tblPlanks[i].thickness = materialThickness
      tblPlanks[i].height = materialHeight
      tblPlanks[i].zoff = zoff
      tblPlanks[i].force = 3
      tblPlanks[i].extendtoelem = 2
      tblPlanks[i].rotangle = rotAngle
      tblPlanks[i].guidsettings = settingsGuid
      tblPlanks[i].group = g_OptGroupName
      tblPlanks[i].id = materialId
      tblPlanks[i].lineside = 0 -- 'center'
      tblPlanks[i].xmlsettings = "<root><objparam name=\"iElemModule\"></objparam></root>\n"

      if g_framingRotAngle == FRAMING_ROTATION_90 then
        local tblRot, tblInvRot = GetRotationMatrices()
        tblPlanks[i].x1, tblPlanks[i].y1, _ = Rotate3D(tblInvRot, tblPlanks[i].x1, tblPlanks[i].y1, 0.0)
        tblPlanks[i].x2, tblPlanks[i].y2, _ = Rotate3D(tblInvRot, tblPlanks[i].x2, tblPlanks[i].y2, 0.0)
      end

      gnPlankCount = gnPlankCount + 1
      gtblCreate[gnPlankCount] = tblPlanks[i]

    end -- for #tblPlanks

    nTotalPlanks = nTotalPlanks + 1

  end -- end of while

  ---------------------------------------------------------------------------------------------------------------------
  -- As a special case, add top and/or bottom plank if the user wants

  local tblTopBot = {}

  if g_addToTop == 1 or g_addToBottom == 1 then

    -- Acquire this again since we have rotated the polygon bounds at an earlier stage.
    if g_framingRotAngle == FRAMING_ROTATION_90 then
      tblElemPoly = GetElemPoly(gGuidElem)
    end

    for i = 1, 2 do
      tblTopBot[i] = {}
      tblTopBot[i].id = materialId
      tblTopBot[i].force = 3
      tblTopBot[i].thickness = materialThickness
      tblTopBot[i].height = materialHeight
      tblTopBot[i].extendtoelem = 2
      tblTopBot[i].rotangle = rotAngle
      tblTopBot[i].guidsettings = settingsGuid
      tblTopBot[i].group = g_OptGroupName
      tblTopBot[i].lineside = 0 -- 'center'
      tblTopBot[i].xmlsettings = "<root><objparam name=\"iElemModule\"></objparam></root>\n"
      tblTopBot[i].zoff = zoff
    end

    -- Find the materials for the top and bottom forces, since they might be different from what we have specified
    -- as the material. We'll use the material's thickness for positioning.
    local tblTopMat = {}
    local tblTopMat2nd = {}
    local tblBottomMat = {}
    local tblBottomMat2nd = {}

    for i=1,gnPlanks do
      ac_objectopen(string.format("#%d",i))

      s = ac_objectget("iElemGroup")

      local isTop = false
      local isTop2nd = false
      local isBottom = false
      local isBottom2nd = false
      if string.match(s, "^bottom_force.*") then
        isBottom = true
      elseif string.match(s, "^2ndbottom_force.*") then
        isBottom2nd = true
      elseif string.match(s, "^top_force.*") then
        isTop = true
      elseif string.match(s, "^2ndtop_force.*") then
        isTop2nd = true
      end

      if isTop or isTop2nd or isBottom or isBottom2nd then
        local tblPlankInfo = af_request("plankinfo")
        local sMatName = tblPlankInfo.matname
        local tblMat = af_request("singlemat", sMatName)

        if isTop then
          tblTopMat = tblMat
        elseif isTop2nd then
          tblTopMat2nd = tblMat
        elseif isBottom then
          tblBottomMat = tblMat
        else
          tblBottomMat2nd = tblMat
        end
      end

      ac_objectclose()
    end

    -- 'Top Piece'
    if g_addToTop == 1 then
      local topThick = 0.0
      if tblTopMat and tblTopMat.thickness then
        topThick = tblTopMat.thickness
      end

      local topThick2 = 0.0
      if tblTopMat2nd and tblTopMat2nd.thickness then
        topThick2 = tblTopMat2nd.thickness
      end

      local matY = 0.0
      if g_materialRotation == MATERIAL_ROTATION_90 then
        if g_framingRotAngle == FRAMING_ROTATION_0 then
          matY = materialHeight
        else
          matY = 0
        end
      else
        matY = materialThickness * 0.5
      end

      if g_framingRotAngle == FRAMING_ROTATION_0 then
        local y = tblElemPoly.y2 - matY - topThick - topThick2
        tblTopBot[1].x1 = tblElemPoly.x1
        tblTopBot[1].y1 = y
        tblTopBot[1].x2 = tblElemPoly.x2
        tblTopBot[1].y2 = y
      else
        local x = tblElemPoly.x2 - matY
        tblTopBot[1].x1 = x
        tblTopBot[1].y1 = tblElemPoly.y1
        tblTopBot[1].x2 = x
        tblTopBot[1].y2 = tblElemPoly.y2
      end

      gnPlankCount = gnPlankCount + 1
      gtblCreate[gnPlankCount] = tblTopBot[1]
    end -- g_addToTop == 1

    -- 'Bottom Piece'
    if g_addToBottom == 1 then
      local bottomThick = 0.0
      if tblBottomMat and tblBottomMat.thickness then
        bottomThick = tblBottomMat.thickness
      end

      local bottomThick2 = 0.0
      if tblBottomMat2nd and tblBottomMat2nd.thickness then
        bottomThick2 = tblBottomMat2nd.thickness
      end

      local matY = 0.0
      if g_materialRotation == MATERIAL_ROTATION_0 then
        matY = materialThickness * 0.5
      else
        if g_framingRotAngle == FRAMING_ROTATION_90 then
          matY = materialHeight
        end
      end

      if g_framingRotAngle == FRAMING_ROTATION_0 then
        local y = tblElemPoly.y1 + matY + bottomThick + bottomThick2
        tblTopBot[2].x1 = tblElemPoly.x1
        tblTopBot[2].y1 = y
        tblTopBot[2].x2 = tblElemPoly.x2
        tblTopBot[2].y2 = y
      else
        local x = tblElemPoly.x1 + matY + bottomThick + bottomThick2
        tblTopBot[2].x1 = x
        tblTopBot[2].y1 = tblElemPoly.y1
        tblTopBot[2].x2 = x
        tblTopBot[2].y2 = tblElemPoly.y2
      end

      gnPlankCount = gnPlankCount + 1
      gtblCreate[gnPlankCount] = tblTopBot[2]
    end -- g_addToBottom == 1

  end

  -- DumpTbl(gtblCreate)

  ---------------------------------------------------------------------------------------------------------------------

  -- Material rotation value affects how the oversize is done. (As the oversize operations are done in planks local coordinate system)
  -- To not cause confusion in usage we will adjust these to be in relation to the elements coordinate system.
  local overLeft   = 0.0
  local overRight  = 0.0
  local overTop    = 0.0
  local overBottom = 0.0

  if g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_0 then
    overRight   = g_oversizeTop
    overBottom  = g_oversizeBehind
    overLeft    = g_oversizeBottom
  elseif g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_90 then
    overRight   = g_oversizeBehind
    overTop     = g_oversizeTop
    overBottom  = g_oversizeBottom
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_0 then
    overRight   = g_oversizeTop
    overLeft    = g_oversizeBottom
    overTop     = g_oversizeBehind
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_90 then
    overLeft    = g_oversizeBehind
    overTop     = g_oversizeTop
    overBottom  = g_oversizeBottom
  end

  if g_partsToAdjust == ADJUST_GROOVES then

    if g_framingRotAngle == FRAMING_ROTATION_90 then
      s = string.format("<groove target=\"vertical_x*|vertical_spacing|vertical_force*|contour_x|contour_y|contour_unused\" operator=\"%s\">\n" ..
            "\t<groove overtop=\"%.4f\" overbot=\"%.4f\" overleft=\"%.4f\" overright=\"%.4f\" overlen=\"%.4f\" forcedepth=\"0\"></groove>\n" ..
          "</groove>\n\n", g_OptGroupName, overTop, overBottom, overLeft, overRight, g_oversizeEnds)
    else
      s = string.format("<groove target=\"vertical_y*|vertical_spacing|vertical_force*|contour_y|contour_unused\" operator=\"%s\">\n" ..
            "\t<groove overtop=\"%.4f\" overbot=\"%.4f\" overleft=\"%.4f\" overright=\"%.4f\" overlen=\"%.4f\" forcedepth=\"0\"></groove>\n" ..
          "</groove>\n\n", g_OptGroupName, overTop, overBottom, overLeft, overRight, g_oversizeEnds)
    end

    s = s .. string.format("<groove target=\"contourtilted*|contourtilted_opening*\" operator=\"%s\">\n" ..
          "\t<groove overtop=\"%.4f\" overbot=\"%.4f\" overleft=\"%.4f\" overright=\"%.4f\" overlen=\"%.4f\" forcedepth=\"0\"></groove>\n" ..
        "</groove>\n\n", g_OptGroupName, overTop, overBottom, overLeft, overRight, g_oversizeEnds)

    for i = 1, #tblPlankCuts do
      s = s .. string.format("<jointo target=\"#%d\" operator=\"#%d\">\n" ..
          "\t<cut extendmaxlen=\"0.0\" expandopfind=\"0.0\" endshape=\"angled\"></cut>\n" ..
          "</jointo>\n\n", tblPlankCuts[i].plankNum, tblPlankCuts[i].plankToCut)
    end

    s = s .. string.format("<jointo target=\"%s\" operator=\"lintel*\">" ..
      "\t<cut extendmaxlen=\"0.0\" expandopfind\"0.0\" endshape=\"anglednoext\"></cut>\n" ..
      "</jointo>\n\n", g_OptGroupName)

  elseif g_partsToAdjust == ADJUST_BETWEEN_STUDS then
    s = string.format("<jointo target=\"%s\" operator=\"*\">\n" ..
     "\t<cut extendmaxlen=\"0.0\" expandopfind=\"0.0\" endshape=\"angleddelfirst\"></cut>\n" ..
      "</jointo>\n", g_OptGroupName)
  end

  if not gxmlOperations then
    gxmlOperations = ""
  end

  gxmlOperations = string.format("<operations>\n%s</operations>", s)

  -- ac_environment("tolog", gxmlOperations)
 
  af_request("elem_createplanks")
end

--
-- BOARD EDGE SUPPORT SCRIPT
------------------------------------------------------------------------------------------------------------
]]>
</script>

        <!-- Adds top beam  -->
        <script id="balktop">
          <![CDATA[
-- Lua script, see ArchiFrame manual

-- For planks to be created
gnPlankCount=0
gtblCreate = {}


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Asks for the material to use
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
-- Returns five values: matid, thickness, height, top offset, number of planks
function AskMat(sSettings)
	local	tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    
    
  tblMat=af_request("matlist")
  s=""
  strSep=""
    
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
  end

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end

	tblSettings={}
	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=1
	tblSettings[1].prompt	="Material"
	tblSettings[1].key		="balkmat"
	tblSettings[1].valuelist=s
	tblSettings[1].defvalue	=1

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=3
	tblSettings[2].prompt	="Thickness if not fixed"
	tblSettings[2].key		="thickness"
	tblSettings[2].defvalue	=0.050

	tblSettings[3]			={}
	tblSettings[3].cfgonly	=0
	tblSettings[3].type		=3
	tblSettings[3].prompt	="Height if not fixed"
	tblSettings[3].key		="height"
	tblSettings[3].defvalue	=0.100

	tblSettings[4]			={}
	tblSettings[4].cfgonly	=0
	tblSettings[4].type		=3
	tblSettings[4].prompt	="Balk distance from element top (top wood thickness)"
	tblSettings[4].key		="topoff"
	tblSettings[4].defvalue	=0.041
  
	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	="Number of planks to add"
	tblSettings[5].key		="numplanks"
	tblSettings[5].valuelist="\"1:1\",\"2:2\",\"3:3\""
	tblSettings[5].defvalue	=1

	tblSettings[6]			={}
	tblSettings[6].cfgonly	=0
	tblSettings[6].type		=3
	tblSettings[6].prompt	="Oversize below the beam"
	tblSettings[6].key		="overbelow"
	tblSettings[6].defvalue	=0

	tblSettings[7]			={}
	tblSettings[7].cfgonly	=0
	tblSettings[7].type		=3
	tblSettings[7].prompt	="Oversize above the beam"
	tblSettings[7].key		="overabove"
	tblSettings[7].defvalue	=0

	tblSettings[8]			={}
	tblSettings[8].cfgonly	=0
	tblSettings[8].type		=3
	tblSettings[8].prompt	="Oversize at the side of the beam"
	tblSettings[8].key		="overinside"
	tblSettings[8].defvalue	=0

	tblSettings[9]			={}
	tblSettings[9].cfgonly	=0
	tblSettings[9].type		=3
	tblSettings[9].prompt	="Beam distance from stud surface"
	tblSettings[9].key		="distsurf"
	tblSettings[9].defvalue	=0

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      for i=1,#tblSorted do
        if tblSorted[i].id==g_mat.id then
          tblSettings[1].value=i
          break
        end
      end
      tblSettings[2].value=g_thickness
      tblSettings[3].value=g_height
      tblSettings[4].value=g_topOff
      tblSettings[5].value=g_numPlanks
      tblSettings[6].value=g_overBelow
      tblSettings[7].value=g_overAbove
      tblSettings[8].value=g_overInside
      tblSettings[9].value=g_distSurf
    else
      ac_environment( "tolog", string.format("AskMat/parse settings failed: %s", tostring(err)) )
    end
  end

	bRes,sErr=ac_optiondlg("LDEM", "Top balk material", tblSettings)
	if not bRes then
    return
  end
    
  mat=tblSorted[tblSettings[1].value]
  thickness=mat.thickness
  height=mat.height
  if thickness==0.0 then
    thickness=tblSettings[2].value
  end
  if height==0.0 then
    height=tblSettings[3].value
  end

  -- New way of passing settings as globals
  g_overBelow=tblSettings[6].value
  g_overAbove=tblSettings[7].value
  g_overInside=tblSettings[8].value
  g_distSurf=tblSettings[9].value

  return mat, thickness, height, tblSettings[4].value, tblSettings[5].value
end


function DumpTblInt(o, nIndent)
  local s,k,v

  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end

    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end

    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end


-- Adds top balk(s) below the upper with group names:
-- balktop Horizontal balk
-- balktopinclined  Inclined one
-- nZoff  -100=to front side, 100=to back side, others=value to use
-- nOffsetToIn  Move inwards from edge with this value, nil=use mat thickness
-- nMatThickness, nMatHeight If generic "block", "round" etc type. nil if defined by strMatId
-- sInOut "in", "out" or nil=""
-- numPlanks  Number of planks to add, nil=1
-- distSurf   Distance towards inside of the stud
-- Returns two values:
-- 1. join gable planks togeteher operations without <operations>-tag or "" if none
-- 2. table of innest added piece in format "#num", empty tbl=not added
function DoTopBelow( strMatId, nZoff, nOffsetToIn, nMatThickness, nMatHeight, sInOut, numPlanks, distSurf )
  local i, v, tblNew, nx, ny, len, dist, lastContour, i2, edgeNew, edgeOp, x, y, nPlank, thickness
  local nNewCount, preNewCount, tblNewEdges, strXmlOp, tblMat, tblLastAdded, nLastAdded
  
  if sInOut==nil then
    sInOut=""
  end

  if numPlanks==nil then
    numPlanks=1
  end

  nNewCount=0
  tblNewEdges={}
  gxmlOperations=nil
  strXmlOp=""
  tblLastAdded={}
  nLastAdded=0

  -- Actually not used always
  tblMat=af_request( "singlemat", strMatId )
  if tblMat==nil then
    error( string.format("Material %s not found", strMatId) )
  end
  
  thickness=tblMat.thickness
  if nMatThickness then
    if nMatThickness>0 then
      thickness=nMatThickness
    end
  end

  if nZoff>99 then
    -- Assume the element has same material as top balk, back side
    nZoff=tblMat.height - 0.5 * thickness
  end
  if nZoff<-99 then
    -- Assume the element has same material as top balk, front side
    nZoff=0.5 * thickness
  end
  if nOffsetToIn==nil then
    nOffsetToIn=thickness
  end
 
  lastContour=#gtblEdges      -- #=Number of items in tbl
  for nPlank=1,numPlanks do
    preNewCount=nNewCount

    for i,v in ipairs(gtblEdges) do
      -- Process only contour line
      if v.holeindex~=0 then
        lastContour=i-1
        break
      end

      if math.abs(v.x1-v.x2)>0.010 and af_hasedgex(i, 0, 1)==false then
        -- Topmost edge, add to temporary tbl and apply offset
        -- Calc normal to left
        nx=-(v.y2-v.y1)
        ny=v.x2-v.x1
        len=math.sqrt(nx*nx + ny*ny)
        if len>0.001 then
          nx=nOffsetToIn*nx/len
          ny=nOffsetToIn*ny/len

          tblNew={}
          if v.tblPlankNums~=nil then
            -- need to set to have projections updated ok
            tblNew.guidsettings=v.ptr
          else
            -- Comes ok 12/2017: ac_environment("tolog", "Lua Warning: Created plank not in projections - please update element manually\n" )
          end

          tblNew.group=string.format("balktop%s", sInOut)
          if math.abs(v.y1-v.y2)>0.001 then
            tblNew.group=string.format("balktop%sinclined", sInOut)
          end
      
          tblNew.id=strMatId
          tblNew.thickness=nMatThickness
          tblNew.height=nMatHeight
          tblNew.zoff=nZoff
          if sInOut=="in" then
            tblNew.zoff=tblNew.zoff-(nPlank-1)*thickness-distSurf
          else
            tblNew.zoff=tblNew.zoff+(nPlank-1)*thickness+distSurf
          end
          tblNew.rotangle=90
          tblNew.orgx1=v.x1
          tblNew.orgy1=v.y1
          tblNew.orgx2=v.x2
          tblNew.orgy2=v.y2
        
          -- Apply offset
          tblNew.x1=v.x1+nx
          tblNew.y1=v.y1+ny
          tblNew.x2=v.x2+nx
          tblNew.y2=v.y2+ny

          -- To calcl connections later
          tblNew.orgIndex=i
          tblNew.begHandled=false
          tblNew.endHandled=false
          tblNew.force=3            -- Keep lintels

          nNewCount=nNewCount+1
          tblNewEdges[nNewCount]=tblNew
          
          if nPlank==numPlanks then
            nLastAdded=nLastAdded+1
            tblLastAdded[nLastAdded]=string.format("#%d", gnPlanks+nNewCount)
          end
        end
      end
    end

    -- Adjust end points for connected planks (remember ccw direction for edges)
    local i2
    for i=preNewCount+1,nNewCount+1 do
      i2=i+1
      if i2>nNewCount then
        i2=preNewCount+1
      end
      if tblNewEdges[i]~=nil and i2<=nNewCount then
        if math.abs(tblNewEdges[i].orgx2-tblNewEdges[i2].orgx1)<0.001 and math.abs(tblNewEdges[i].orgy2-tblNewEdges[i2].orgy1)<0.001 then

          -- Curr end connected to next beg, adjust
          nx,ny=ac_geo("linex", tblNewEdges[i].x1, tblNewEdges[i].y1, tblNewEdges[i].x2, tblNewEdges[i].y2, tblNewEdges[i2].x1, tblNewEdges[i2].y1, tblNewEdges[i2].x2, tblNewEdges[i2].y2)
          if nx~=nil then
            -- has intersection, check if deleted totally
            dist,len=ac_geo("linedist", tblNewEdges[i].x1, tblNewEdges[i].y1, tblNewEdges[i].x2, tblNewEdges[i].y2, nx, ny)
            if len<0.001 then
              -- deleted totally
              tblNewEdges[i]=nil
            else
              -- Adjust
              tblNewEdges[i].x2=nx
              tblNewEdges[i].y2=ny
              tblNewEdges[i].endHandled=true
            end
          
            -- Check next edge
            dist,len,lineLen=ac_geo("linedist", tblNewEdges[i2].x2, tblNewEdges[i2].y2, tblNewEdges[i2].x1, tblNewEdges[i2].y1, nx, ny)
            if len<0.001 then
              -- deleted totally
              tblNewEdges[i2]=nil
            else
              -- Adjust
              tblNewEdges[i2].x1=nx
              tblNewEdges[i2].y1=ny
              tblNewEdges[i2].begHandled=true
            end
          end
        end
      end

      if tblNewEdges[i]~=nil then
        -- Finally add
        gnPlankCount=gnPlankCount+1
        gtblCreate[gnPlankCount]=tblNewEdges[i]
        gtblCreate[gnPlankCount].mayturn=true
      
        if tblNewEdges[i2]~=nil then
          -- Adjust these two together
          strXmlOp = string.format( 
              "%s" ..
              "<joinends target=\"#%d\" operator=\"#%d\">\n" ..
              "    <joinends conntype=\"endtoend\" jointgap=\"0\"></joinends>\n" ..
              "</joinends>\n",
              strXmlOp, gnPlanks+i, gnPlanks+i2
            )
        end
      end
    end
  
    -- Extend at corner edges to contour studs
    for i=preNewCount+1,nNewCount do
      if tblNewEdges[i]~=nil then
        if tblNewEdges[i].begHandled==false then
          -- Connect beg with previous edge
          i2=tblNewEdges[i].orgIndex-1
          if i2==0 then
             i2=lastContour
          end

          if gtblEdges[i2].tblPlankNums~=nil then
            edgeNew=tblNewEdges[i]
            edgeOp=gtblEdges[i2]
            x,y=ac_geo( "linex", edgeNew.x1, edgeNew.y1, edgeNew.x2, edgeNew.y2, edgeOp.x1, edgeOp.y1, edgeOp.x2, edgeOp.y2 )
            if x~=nil then
              -- Adjust end pt to the crossing to make it clear of which end to save in jointo-operation
              edgeNew.x1=x
              edgeNew.y1=y
            end

            strXmlOp = string.format( 
                "%s" ..
                "<jointo target=\"#%d\" operator=\"#%d\">\n" ..
                "    <cut toend=\"1\"></cut>\n" ..
                "</jointo>\n",
                strXmlOp, gnPlanks+i, gtblEdges[i2].tblPlankNums[1]
              )
          end
        end

        if tblNewEdges[i].endHandled==false then
          -- Connect beg with previous edge
          i2=tblNewEdges[i].orgIndex+1
          if i2>lastContour then
             i2=1
          end

          if gtblEdges[i2].tblPlankNums~=nil then
            edgeNew=tblNewEdges[i]
            edgeOp=gtblEdges[i2]
            x,y=ac_geo( "linex", edgeNew.x1, edgeNew.y1, edgeNew.x2, edgeNew.y2, edgeOp.x1, edgeOp.y1, edgeOp.x2, edgeOp.y2 )
            if x~=nil then
              -- Adjust end pt to the crossing to make it clear of which end to save in jointo-operation
              edgeNew.x2=x
              edgeNew.y2=y
            end

            strXmlOp = string.format( 
                "%s" ..
                "<jointo target=\"#%d\" operator=\"#%d\">\n" ..
                "    <cut toend=\"1\"></cut>\n" ..
                "</jointo>\n",
                strXmlOp, gnPlanks+i, gtblEdges[i2].tblPlankNums[1]
              )
          end
        end
      end
    end
  end
  
  -- Add xml-operations to be run after new planks are initialized
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end

  return strXmlOp, tblLastAdded
end


-------------------------
-- FOR OPTION DLG

--Set these:
--gOptGroupName="balktopin"
--gOptInOut="in"



-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height, g_topOff, 
function ParseSettings(sSettings)
  local s, mat, val
  
  mat=GetVal(sSettings, "mat")
  g_mat=af_request("singlemat", mat)
  
  if g_mat==nil then
    mat=af_request("elem_getstudmat")
    if mat~=nil then
      g_mat=af_request("singlemat", mat)
    end
  end

  g_thickness=g_mat.thickness
  g_height=g_mat.height
  if g_thickness==0.0 then
    g_thickness=tonumber(GetVal(sSettings, "thickness"))
  end
  if g_height==0.0 then
    g_height=tonumber(GetVal(sSettings, "height"))
  end
  g_topOff=tonumber(GetVal(sSettings, "topoff"))
  
  g_numPlanks=1
  val=GetVal(sSettings, "numplanks")
  if val then
    g_numPlanks=tonumber(val)
  end
  
  g_overBelow=0
  val=GetVal(sSettings, "overbelow")
  if val then
    g_overBelow=tonumber(val)
  end
  
  g_overAbove=0.010   -- Default here also
  val=GetVal(sSettings, "overabove")
  if val then
    g_overAbove=tonumber(val)
  end
  
  g_overInside=0
  val=GetVal(sSettings, "overinside")
  if val then
    g_overInside=tonumber(val)
  end
  
  g_distSurf=0
  val=GetVal(sSettings, "distsurf")
  if val then
    g_distSurf=tonumber(val)
  end  

  -- Will cause error if bad syntax
  s = string.format("%s,thickness=%f,height=%f,topOff=%f,numPlanks=%d,overbelow=%f,overabove=%f,overinside=%f,distsurf=%f\n", g_mat.id, g_thickness, g_height, g_topOff, g_numPlanks, g_overBelow, g_overAbove, g_overInside, g_distSurf)
end


-- Top balk options
function GetDefaults()
  local mat, i, secondWidth, tblInfo, s, nPlanks
  
  mat=af_request("elem_getstudmat")
  if mat==nil then
    return false
  end

  g_mat=af_request("singlemat", mat)
  if g_mat==nil then
    return false
  end

  g_thickness=g_mat.thickness
  g_height=g_mat.height
  
  -- Look for "top_force" plank
  g_topOff=nil
  secondWidth=0
  nPlanks=gnPlanks
  if not nPlanks then
    nPlanks=0
  end
  for i=1,nPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^top_force.*") or string.match(s, "^contourtilted.*") then
      tblInfo=af_request("plankinfo")
      g_topOff=tblInfo.width
    elseif string.match(s, "^2ndtop_force.*") then
      tblInfo=af_request("plankinfo")
      if not tblInfo.del then
        secondWidth=tblInfo.width
      end
    end
    ac_objectclose()
  end

  if g_topOff==nil then
    g_topOff=g_thickness
  else
    g_topOff=g_topOff+secondWidth
  end

  g_numPlanks=1
  g_overBelow=0
  g_overAbove=0.010
  g_overInside=0
  g_distSurf=0
  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("mat=%s\nthickness=%f\nheight=%f\ntopoff=%f\nnumplanks=%d", g_mat.id, g_thickness, g_height, g_topOff, g_numPlanks)
    end
  end
  -- Ask material
  local mat, thickness, height, topOff, numPlanks
  mat, thickness, height, topOff, numPlanks = AskMat(sSettings)
  if mat==nil then
    return nil
  end

  s=string.format("mat=%s\nthickness=%f\nheight=%f\ntopoff=%f\nnumplanks=%d\noverbelow=%f\noverabove=%f\noverinside=%f\ndistsurf=%f\n", mat.id, thickness, height, topOff, numPlanks, g_overBelow, g_overAbove, g_overInside, g_distSurf)

  return s
end


function Set(sSettings)
  local res, errStr, zoff, tblLastAdded, i, v, s, overL, overR, thickness
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  GetDefaults()
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end

  elemThick=af_request("elemcorethickness")
  custThick=nil
  thickness=g_mat.thickness
  if g_mat.thickness==0.0 then
    custThick=g_thickness
    thickness=g_thickness
  end

  custHeight=nil
  if g_mat.height==0.0 then
    custHeight=g_height
  end

  zoff=g_thickness*0.5
  if gOptInOut=="in" then
    zoff=elemThick-zoff
  end
  res, tblLastAdded=DoTopBelow( g_mat.id, zoff, g_topOff, custThick, custHeight, gOptInOut, g_numPlanks, g_distSurf )
  
  if gxmlOperations==nil then
    gxmlOperations=""
  end

  -- Single groove for the deepest plank
  overL=0
  overR=0
  if gOptInOut=="in" then
    overR=thickness*(g_numPlanks-1)+g_distSurf+0.001
    overL=g_overInside
  else
    overL=thickness*(g_numPlanks-1)+g_distSurf+0.001
    overR=g_overInside
  end

  s=""
  for i,v in ipairs(tblLastAdded) do
    s=string.format(
      "%s" ..
      "  <groove target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"%s\">\n" ..
      "    <groove overtop=\"%.4f\" overbot=\"%.4f\" overleft=\"%.4f\" overright=\"%.4f\" overlen=\"0.1\"></groove>\n" ..
      "  </groove>\n",
      s, v, g_overBelow, g_overAbove, overL, overR )
  end
  
  -- Added 4/2023: Auto cut to lintels
  s = string.format( 
      "%s" ..
      "<jointo target=\"%s\" operator=\"lintel*\">\n" ..
      "    <cut extendmaxlen=\"0.0\" expandopfind\"0.0\" endshape=\"anglednoext\"></cut>\n" ..
      "</jointo>\n",
      s, gOptGroupName
    )

  gxmlOperations = string.format( "<operations>%s%s</operations>", res, s )
  af_request("elem_createplanks")
end


function Reset()
  res=false
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      s=af_request("delplank")
      res=true
    end
    ac_objectclose()
  end
  return res
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      if g_mat.thickness~=0 then
        baseName=string.format("%s %s", baseName, g_mat.id)
      else
        baseName=string.format("%s %sx%s", baseName, ac_environment("ntos", g_thickness, "length", "work"), ac_environment("ntos", g_height, "length", "work"))
      end
      
      if g_numPlanks>1 then
        baseName=string.format("%s %d pcs", baseName, g_numPlanks)
      end
    end
  end
  return baseName
end

-- FOR OPTION DLG
-------------------------


]]>
        </script>


        <!-- Wall top joint to floor -->
        <script id="walltofloortop">
          <![CDATA[
-- For planks to be created
gnPlankCount=0
gtblCreate = {}


-- Global settings variablset set in GetDefaults() and ParseSettings()
-- TOP PLATE:
-- g_topmatid Just the material ID unlike g_mat, ""=no change
-- FOR THE SLOT:
-- g_side, 1=front, 2=back
-- g_slotDepth, depth including OSB
-- g_slotHeight, height including OSB
-- g_botThickness, 6 mm osb
-- g_botOversize, oversize for the bottom piece towards inside
-- g_vertThickness, 3 mm osb
-- g_vertHeight, 0=slot height-bottom thickness
-- THESE ARE FOR THE BEAM:
-- g_mat.id, the material ID
-- g_thickness, g_height, size of previous (which may be generic block)
-- g_numPlanks, number of beams to add
-- g_overBelow, oversize below the beam
-- g_overInside, to inner side
-- g_distSurf, how deep the beam is placed into the studs
-- g_topOff, distance from top of the element under lowest top plate (calculated - not saved, add g_slotHeight)



function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Settings dialog
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
-- Reads & sets globals
-- Returns: true=ok, false=cancel
function AskMat(sSettings)
  local  tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    

	-- Localized strings BEG
	local strTopMat="Top plate material ID"
  local strTopNoChange="No change - keep original"
	local strSide="Side of the joint"
	local strSideVal="\"1:Front\",\"2:Back\""
	local strDepth="Slot depth"
	local strHeight="Slot height"
	local strBotThick="Bottom horizontal OSB thickness"
	local strBotOversize="Bottom horizontal OSB oversize inside"
	local strVertThick="Vertical OSB thickness (0=no)"
	local strVertHeight="Vertical OSB height (0=default)"
	local strBeamMat="Supporting beam mat"
	local strBlockThick="Thickness if not fixed"
	local strBlockHeight="Height if not fixed"
	local strNumBeams="Number of beams to add"
	local strOverBelow="Oversize below the beam"
	local strOverSide="Oversize at the side of the beam"
	local strBeamFromSurf="Beam distance from stud surface"
	local strTitle="Floor joint settings"

	s=af_request("aflang")
	if s=="fin" then
    strTopMat="Yläjuoksun materiaali"
    strTopNoChange="Ei muutosta - pidä alkuperäinen"
		strSide="Liitoksen puoli"
		strSideVal="\"1:Etu\",\"2:Taka\""
		strDepth="Kolon syvyys"
		strHeight="Kolon korkeus"
		strBotThick="Kolon alareunan levyn paksuus"
	  strBotOversize="Kolon alareunan levyn sovitusvara sisälle"
		strVertThick="Kolon takareunan pystylevyn paksuus (0=ei)"
    strVertHeight="Takareunan levyn korkeus (0=kolon kork)"
		strBeamMat="Tukipalkin materiaali"
		strBlockThick="Palkin paksuus jos ei vakio"
		strBlockHeight="Palkin korkeus jos ei vakio"
		strNumBeams="Montako palkkia lisätään"
		strOverBelow="Sovitusvara palkin alla"
		strOverSide="Sovitusvara palkin sisäpuolella"
		strBeamFromSurf="Palkin upotus kohdepinnasta"
		strTitle="Välipohjaliitoksen asetukset"
	end
	-- Localized strings END

  -- Material ID for the beam
  tblMat=af_request("matlist")
  s=""
  strSep=""
    
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
  end

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end
  
  -- Material ID for the top plate (no free size block etc)
  local stopmat, tblSortedTop
  
  stopmat=""
  strSep=""

  tblSortedTop={}
  
  tblSortedTop[1]={}
  tblSortedTop[1].name=strTopNoChange
  tblSortedTop[1].id=""
  tblSortedTop[1].index=-1

  i=2
  for id,v in pairs(tblMat) do
    if v.thickness>0.001 then
		  tblSortedTop[i]=v
		  i=i+1
	  end
  end

	table.sort(tblSortedTop, function (n1, n2)
    return n1.index < n2.index
	end)

  for i,v in ipairs(tblSortedTop) do
    if v.id~="" then
      stopmat=string.format("%s%s\"%s:%s (%s)\"", stopmat, strSep, i, v.name, v.id)
    else
      stopmat=string.format("%s%s\"%s:%s\"", stopmat, strSep, i, v.name)
    end
    strSep=","
  end
  

  -- GetDefault() sets the defaults if no settings yet
  tblSettings={}

  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =1
  tblSettings[1].prompt  =strTopMat
  tblSettings[1].key    ="topmat"
  tblSettings[1].valuelist=stopmat
  tblSettings[1].defvalue  =1

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type    =1
  tblSettings[2].prompt  =strSide
  tblSettings[2].key    ="jointside"
  tblSettings[2].valuelist=strSideVal

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  =strDepth
  tblSettings[3].key    ="slotdepth"
  
  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type    =3
  tblSettings[4].prompt  =strHeight
  tblSettings[4].key    ="slotheight"

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type    =3
  tblSettings[5].prompt  =strBotThick
  tblSettings[5].key    ="botthick"
  
  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type    =3
  tblSettings[6].prompt  =strBotOversize
  tblSettings[6].key    ="botover"

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type    =3
  tblSettings[7].prompt  =strVertThick
  tblSettings[7].key    ="vertthick"

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type    =3
  tblSettings[8].prompt  =strVertHeight
  tblSettings[8].key    ="vertheight"

  tblSettings[9]      ={}
  tblSettings[9].cfgonly  =0
  tblSettings[9].type    =1
  tblSettings[9].prompt  =strBeamMat
  tblSettings[9].key    ="balkmat"
  tblSettings[9].valuelist=s
  tblSettings[9].defvalue  =1

  tblSettings[10]      ={}
  tblSettings[10].cfgonly  =0
  tblSettings[10].type    =3
  tblSettings[10].prompt  =strBlockThick
  tblSettings[10].key    ="thickness"
  tblSettings[10].defvalue  =0.050

  tblSettings[11]      ={}
  tblSettings[11].cfgonly  =0
  tblSettings[11].type    =3
  tblSettings[11].prompt  =strBlockHeight
  tblSettings[11].key    ="height"
  tblSettings[11].defvalue  =0.100

  tblSettings[12]      ={}
  tblSettings[12].cfgonly  =0
  tblSettings[12].type    =1
  tblSettings[12].prompt  =strNumBeams
  tblSettings[12].key    ="numplanks"
  tblSettings[12].valuelist="\"99:0\",\"1:1\",\"2:2\",\"3:3\""    -- Valu zero not good for an option
  tblSettings[12].defvalue  =1

  tblSettings[13]      ={}
  tblSettings[13].cfgonly  =0
  tblSettings[13].type    =3
  tblSettings[13].prompt  =strOverBelow
  tblSettings[13].key    ="overbelow"
  
  tblSettings[14]      ={}
  tblSettings[14].cfgonly  =0
  tblSettings[14].type    =3
  tblSettings[14].prompt  =strOverSide
  tblSettings[14].key    ="overinside"

  tblSettings[15]      ={}
  tblSettings[15].cfgonly  =0
  tblSettings[15].type    =3
  tblSettings[15].prompt  =strBeamFromSurf
  tblSettings[15].key    ="distsurf"

  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
  end
  
  tblSettings[1].value=1
  if g_topmatid then
    for i=1,#tblSortedTop do
      if tblSortedTop[i].id==g_topmatid then
        tblSettings[1].value=i
        break
      end
    end
  end

  tblSettings[2].value=g_side
  tblSettings[3].value=g_slotDepth
  tblSettings[4].value=g_slotHeight
  tblSettings[5].value=g_botThickness
  tblSettings[6].value=g_botOversize
  tblSettings[7].value=g_vertThickness
  tblSettings[8].value=g_vertHeight

  if g_mat then
    for i=1,#tblSorted do
      if tblSorted[i].id==g_mat.id then
        tblSettings[9].value=i
        break
      end
    end
  end

  tblSettings[10].value=g_thickness
  tblSettings[11].value=g_height
  tblSettings[12].value=g_numPlanks
  if g_numPlanks==0 then
    tblSettings[12].value=99
  end
  
  tblSettings[13].value=g_overBelow
  tblSettings[14].value=g_overInside
  tblSettings[15].value=g_distSurf

  bRes,sErr=ac_optiondlg("LDFJ", strTitle, tblSettings)
  if not bRes then
    return bRes
  end

  g_topmatid=tblSortedTop[tblSettings[1].value].id
  g_side=tblSettings[2].value
  g_slotDepth=tblSettings[3].value
  g_slotHeight=tblSettings[4].value
  g_botThickness=tblSettings[5].value
  g_botOversize=tblSettings[6].value
  g_vertThickness=tblSettings[7].value
  g_vertHeight=tblSettings[8].value

  g_mat=tblSorted[tblSettings[9].value]
  g_thickness=g_mat.thickness
  g_height=g_mat.height
  if g_thickness==0.0 then
    g_thickness=tblSettings[10].value
  end
  if g_height==0.0 then
    g_height=tblSettings[11].value
  end

  g_numPlanks=tblSettings[12].value
  if g_numPlanks==99 then
    g_numPlanks=0
  end
  g_overBelow=tblSettings[13].value
  g_overInside=tblSettings[14].value
  g_distSurf=tblSettings[15].value

  return bRes
end


-- Adds top balk(s) below the upper with group names:
-- balktop Horizontal balk
-- balktopinclined  Inclined one
-- nZoff  -100=to front side, 100=to back side, others=value to use
-- nMatThickness, nMatHeight If generic "block", "round" etc type. nil if defined by strMatId
-- numPlanks  Number of planks to add, nil=1
-- distSurf   Distance towards inside of the stud
-- elemThick  Elem layer's thickness
-- Returns values:
-- 1. join gable planks togeteher operations without <operations>-tag or "" if none
-- 2. table of innest added piece in format "#num", empty tbl=not added
-- 3. table of bottom plywoods as previous
function AddFloorSuppBeam( strMatId, nZoff, nMatThickness, nMatHeight, numPlanks, distSurf, elemThick )
  local i, v, tblNew, nx, ny, len, dist, lastContour, i2, edgeNew, edgeOp, x, y, nPlank, thickness, loopmax
  local nNewCount, preNewCount, tblNewEdges, strXmlOp, tblMat, tblLastAdded, nLastAdded, nOffsetToIn
  local tblPlywoods={}      -- Add these at the end to keep previous logic of making grooves 
  
  
  nOffsetToIn=g_topOff+g_slotHeight
  if numPlanks==nil then
    numPlanks=1
  end

  nNewCount=0
  tblNewEdges={}
  gxmlOperations=nil
  strXmlOp=""
  tblLastAdded={}
  nLastAdded=0

  -- Actually not used always
  tblMat=af_request( "singlemat", strMatId )
  if tblMat==nil then
    error( string.format("Material %s not found", strMatId) )
  end
  
  thickness=tblMat.thickness
  if nMatThickness then
    if nMatThickness>0 then
      thickness=nMatThickness
    end
  end

  if nZoff>99 then
    -- Assume the element has same material as top balk, back side
    nZoff=tblMat.height - 0.5 * thickness
  end
  if nZoff<-99 then
    -- Assume the element has same material as top balk, front side
    nZoff=0.5 * thickness
  end
 
  lastContour=#gtblEdges      -- #=Number of items in tbl
  loopmax=numPlanks
  if loopmax==0 then          -- Following loop will calculate also the plywood - do that even if numplanks is zero
    loopmax=1
  end
  for nPlank=1,loopmax do
    preNewCount=nNewCount

    for i,v in ipairs(gtblEdges) do
      -- Process only contour line
      if v.holeindex~=0 then
        lastContour=i-1
        break
      end

      if math.abs(v.x1-v.x2)>0.010 and af_hasedgex(i, 0, 1)==false then
        -- Topmost edge, add to temporary tbl and apply offset
        -- Calc normal to left
        nx=-(v.y2-v.y1)
        ny=v.x2-v.x1
        len=math.sqrt(nx*nx + ny*ny)
        if len>0.001 then
          local nxOrg, nyOrg
          
          nxOrg=nx
          nyOrg=ny
          nx=nOffsetToIn*nx/len
          ny=nOffsetToIn*ny/len

          tblNew={}
          if v.tblPlankNums~=nil then
            -- need to set to have projections updated ok
            tblNew.guidsettings=v.ptr
          else
            -- Comes ok 12/2017: ac_environment("tolog", "Lua Warning: Created plank not in projections - please update element manually\n" )
          end

          tblNew.group="balktop_floor"
          if math.abs(v.y1-v.y2)>0.001 then
            tblNew.group="balktop_floor_inclined"
          end
      
          tblNew.id=strMatId
          tblNew.thickness=nMatThickness
          tblNew.height=nMatHeight
          tblNew.zoff=nZoff
          if g_side==2 then
            tblNew.zoff=tblNew.zoff-(nPlank-1)*thickness-distSurf
          else
            tblNew.zoff=tblNew.zoff+(nPlank-1)*thickness+distSurf
          end
--ac_environment("tolog", string.format("g_side=%f, tblNew.zoff=%f, nZoff=%f", g_side, tblNew.zoff, nZoff))

          tblNew.rotangle=90
          tblNew.orgx1=v.x1
          tblNew.orgy1=v.y1
          tblNew.orgx2=v.x2
          tblNew.orgy2=v.y2
        
          -- Apply offset
          tblNew.x1=v.x1+nx
          tblNew.y1=v.y1+ny
          tblNew.x2=v.x2+nx
          tblNew.y2=v.y2+ny

          -- To calc connections later
          tblNew.orgIndex=i
          tblNew.begHandled=false
          tblNew.endHandled=false

          if nPlank<=numPlanks then   -- numPlanks may be zero
            nNewCount=nNewCount+1
            tblNewEdges[nNewCount]=tblNew
          end

          if nPlank==loopmax then
            nLastAdded=nLastAdded+1
            tblLastAdded[nLastAdded]=string.format("#%d", gnPlanks+nNewCount)
            
            -- Add bigger slot and the bottom plyvwood making the groove
            tblNew={}
            if v.tblPlankNums~=nil then
              tblNew.guidsettings=v.ptr
            end

            tblNew.group="balktop_floorbot"
            if math.abs(v.y1-v.y2)>0.001 then
              tblNew.group="balktop_floor_inclinedbot"
            end
      
            tblNew.id="block"
            tblNew.thickness=g_botThickness
            tblNew.height=g_slotDepth
            tblNew.rotangle=0
            tblNew.zoff=0
            if g_side==2 then
              tblNew.zoff=elemThick-g_slotDepth
            end
--ac_environment("tolog", string.format("g_side=%f, tblNew.zoff=%f, nZoff=%f", g_side, tblNew.zoff, nZoff))

            -- Apply offset
            local nx2, ny2
            
            nx2=-g_botThickness*0.5*nxOrg/len
            ny2=-g_botThickness*0.5*nyOrg/len

            tblNew.x1=v.x1+nx+nx2
            tblNew.y1=v.y1+ny+ny2
            tblNew.x2=v.x2+nx+nx2
            tblNew.y2=v.y2+ny+ny2
            tblNew.isbot=true

            tblPlywoods[#tblPlywoods+1]=tblNew

            if g_vertThickness>0.0001 then
              -- Plywood to the back of the slot
              tblNew={}
              if v.tblPlankNums~=nil then
                tblNew.guidsettings=v.ptr
              end

              tblNew.group="balktop_floorback"
              if math.abs(v.y1-v.y2)>0.001 then
                tblNew.group="balktop_floor_inclinedback"
              end
      
              tblNew.id="block"
              tblNew.thickness=g_vertThickness
              tblNew.height=g_slotHeight-g_botThickness
              if g_vertHeight>0 then
                tblNew.height=g_vertHeight
              end
              tblNew.rotangle=-90
              tblNew.zoff=g_slotDepth+g_botOversize-g_vertThickness*0.5
              if g_side==2 then
                tblNew.zoff=elemThick-tblNew.zoff
              end
  --ac_environment("tolog", string.format("g_side=%f, tblNew.zoff=%f, nZoff=%f", g_side, tblNew.zoff, nZoff))

              -- Apply offset
              local nx2, ny2
            
              nx2=-g_botThickness*nxOrg/len
              ny2=-g_botThickness*nyOrg/len

              tblNew.x1=v.x1+nx+nx2
              tblNew.y1=v.y1+ny+ny2
              tblNew.x2=v.x2+nx+nx2
              tblNew.y2=v.y2+ny+ny2
              tblPlywoods[#tblPlywoods+1]=tblNew
            end
          end
        end
      end
    end

    -- Adjust end points for connected planks (remember ccw direction for edges)
    local i2
    for i=preNewCount+1,nNewCount+1 do
      i2=i+1
      if i2>nNewCount then
        i2=preNewCount+1
      end
      if tblNewEdges[i]~=nil and i2<=nNewCount then
        if math.abs(tblNewEdges[i].orgx2-tblNewEdges[i2].orgx1)<0.001 and math.abs(tblNewEdges[i].orgy2-tblNewEdges[i2].orgy1)<0.001 then

          -- Curr end connected to next beg, adjust
          nx,ny=ac_geo("linex", tblNewEdges[i].x1, tblNewEdges[i].y1, tblNewEdges[i].x2, tblNewEdges[i].y2, tblNewEdges[i2].x1, tblNewEdges[i2].y1, tblNewEdges[i2].x2, tblNewEdges[i2].y2)
          if nx~=nil then
            -- has intersection, check if deleted totally
            dist,len=ac_geo("linedist", tblNewEdges[i].x1, tblNewEdges[i].y1, tblNewEdges[i].x2, tblNewEdges[i].y2, nx, ny)
            if len<0.001 then
              -- deleted totally
              tblNewEdges[i]=nil
            else
              -- Adjust
              tblNewEdges[i].x2=nx
              tblNewEdges[i].y2=ny
              tblNewEdges[i].endHandled=true
            end
          
            -- Check next edge
            dist,len,lineLen=ac_geo("linedist", tblNewEdges[i2].x2, tblNewEdges[i2].y2, tblNewEdges[i2].x1, tblNewEdges[i2].y1, nx, ny)
            if len<0.001 then
              -- deleted totally
              tblNewEdges[i2]=nil
            else
              -- Adjust
              tblNewEdges[i2].x1=nx
              tblNewEdges[i2].y1=ny
              tblNewEdges[i2].begHandled=true
            end
          end
        end
      end

      if tblNewEdges[i]~=nil then
        -- Finally add
        gnPlankCount=gnPlankCount+1
        gtblCreate[gnPlankCount]=tblNewEdges[i]
        gtblCreate[gnPlankCount].mayturn=true
      
        if tblNewEdges[i2]~=nil then
          -- Adjust these two together
          strXmlOp = string.format( 
              "%s" ..
              "<joinends target=\"#%d\" operator=\"#%d\">\n" ..
              "    <joinends conntype=\"endtoend\" jointgap=\"0\"></joinends>\n" ..
              "</joinends>\n",
              strXmlOp, gnPlanks+i, gnPlanks+i2
            )
        end
      end
    end
  
    -- Extend at corner edges to contour studs
    for i=preNewCount+1,nNewCount do
      if tblNewEdges[i]~=nil then
        if tblNewEdges[i].begHandled==false then
          -- Connect beg with previous edge
          i2=tblNewEdges[i].orgIndex-1
          if i2==0 then
             i2=lastContour
          end

          if gtblEdges[i2].tblPlankNums~=nil then
            edgeNew=tblNewEdges[i]
            edgeOp=gtblEdges[i2]
            x,y=ac_geo( "linex", edgeNew.x1, edgeNew.y1, edgeNew.x2, edgeNew.y2, edgeOp.x1, edgeOp.y1, edgeOp.x2, edgeOp.y2 )
            if x~=nil then
              -- Adjust end pt to the crossing to make it clear of which end to save in jointo-operation
              edgeNew.x1=x
              edgeNew.y1=y
            end

            strXmlOp = string.format( 
                "%s" ..
                "<jointo target=\"#%d\" operator=\"#%d\">\n" ..
                "    <cut toend=\"1\"></cut>\n" ..
                "</jointo>\n",
                strXmlOp, gnPlanks+i, gtblEdges[i2].tblPlankNums[1]
              )
          end
        end

        if tblNewEdges[i].endHandled==false then
          -- Connect beg with previous edge
          i2=tblNewEdges[i].orgIndex+1
          if i2>lastContour then
             i2=1
          end

          if gtblEdges[i2].tblPlankNums~=nil then
            edgeNew=tblNewEdges[i]
            edgeOp=gtblEdges[i2]
            x,y=ac_geo( "linex", edgeNew.x1, edgeNew.y1, edgeNew.x2, edgeNew.y2, edgeOp.x1, edgeOp.y1, edgeOp.x2, edgeOp.y2 )
            if x~=nil then
              -- Adjust end pt to the crossing to make it clear of which end to save in jointo-operation
              edgeNew.x2=x
              edgeNew.y2=y
            end

            strXmlOp = string.format( 
                "%s" ..
                "<jointo target=\"#%d\" operator=\"#%d\">\n" ..
                "    <cut toend=\"1\"></cut>\n" ..
                "</jointo>\n",
                strXmlOp, gnPlanks+i, gtblEdges[i2].tblPlankNums[1]
              )
          end
        end
      end
    end
  end

  -- Add plywoods
  tblPlywoodNums={}
  for i,v in ipairs(tblPlywoods) do
    gnPlankCount=gnPlankCount+1
    gtblCreate[gnPlankCount]=v
    gtblCreate[gnPlankCount].mayturn=true
    
    gtblCreate[gnPlankCount].xmlsettings="<s><objparam name=\"iColLines\">0</objparam></s>"
    
    if v.isbot then
      -- Add groove to bottom piece
      strXmlOp=string.format(
        "%s" ..
        "<groove target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"#%d\">\n" ..
        "  <groove overtop=\"%.5f\" overbot=\"0\" overleft=\"0\" overright=\"%.5f\" overlen=\"0.1\"></groove>\n" ..
        "</groove>\n",
        strXmlOp, gnPlanks+gnPlankCount, g_botOversize, g_slotHeight-g_botThickness+1 )
    end
  end
--ac_environment("tolog", strXmlOp)
  
  -- Add xml-operations to be run after new planks are initialized
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end


  return strXmlOp, tblLastAdded
end


-- Sets give material ID to the top_force and 2ndtop_force
function AdjustTopMat(matIdNew)
  local i, nPlanks, s, tblMat, info, tblEdit, dz


  tblMat=af_request("singlemat", matIdNew)
  if not tblMat then
    ac_environment("tolog", string.format("walltofloortop: no material id \"%s\", cannot adjust top plate", matIdNew))
    return
  end
    
  nPlanks=gnPlanks
  if not nPlanks then
    nPlanks=0
  end
  
  for i=1,nPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^top_force.*") or string.match(s, "^2ndtop_force.*") then
      info=af_request("plankinfo")
      
      -- Move in z-direction to reflect change in material height
	    tblEdit={}
	    tblEdit.guid=info.ptr
	    tblEdit.mat=matIdNew
	    tblEdit.elemdata=ac_objectget("#af_elemdata")
      
      dz = info.height - tblMat.height
      if g_side==2 then
        dz = -dz
      end

      if g_side==1 and tblEdit.elemdata.rotangle < -0.0001 then
        dz = 0
      elseif g_side==2 and tblEdit.elemdata.rotangle > -0.0001 then
        dz = 0
      end

	    tblEdit.elemdata.z1=tblEdit.elemdata.z1+dz
	    tblEdit.elemdata.z2=tblEdit.elemdata.z2+dz

	    af_request("editplank", tblEdit)
    end
    ac_objectclose()
  end


	-- Change mat id
	local tblEdit, dx, dy, len, t3


end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Makes the settings str to save from globals
function SettingsToStr()
  return string.format("topmat=%s\nside=%d\ndepth=%f\nheight=%f\nbot_thick=%f\nbot_over=%f\nvert_thick=%f\nvert_height=%f\nmat=%s\nthickness=%f\nheight=%f\nnumplanks=%d\noverbelow=%f\noverinside=%f\ndistsurf=%f\n", g_topmatid, g_side, g_slotDepth, g_slotHeight, g_botThickness, g_botOversize, g_vertThickness, g_vertHeight, g_mat.id, g_thickness, g_height, g_numPlanks, g_overBelow, g_overInside, g_distSurf)
end

-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  local s, mat, val


  -- Top mat
  g_topmatid=""
  s=GetVal(sSettings, "topmat")
  if s then
    g_topmatid=s
  end

  -- For the slot
  g_side=math.floor(GetVal(sSettings, "side"))
  g_slotDepth=tonumber(GetVal(sSettings, "depth"))
  g_slotHeight=tonumber(GetVal(sSettings, "height"))
  g_botThickness=tonumber(GetVal(sSettings, "bot_thick"))
  g_botOversize=tonumber(GetVal(sSettings, "bot_over"))
  g_vertThickness=tonumber(GetVal(sSettings, "vert_thick"))
  g_vertHeight=tonumber(GetVal(sSettings, "vert_height"))

  -- For the beam
  mat=GetVal(sSettings, "mat")
  g_mat=af_request("singlemat", mat)
  g_thickness=g_mat.thickness
  g_height=g_mat.height
  if g_thickness==0.0 then
    g_thickness=tonumber(GetVal(sSettings, "thickness"))
  end
  if g_height==0.0 then
    g_height=tonumber(GetVal(sSettings, "height"))
  end
  
  g_numPlanks=1
  val=GetVal(sSettings, "numplanks")
  if val then
    g_numPlanks=tonumber(val)
  end
  
  g_overBelow=0
  val=GetVal(sSettings, "overbelow")
  if val then
    g_overBelow=tonumber(val)
  end
  
  g_overInside=0
  val=GetVal(sSettings, "overinside")
  if val then
    g_overInside=tonumber(val)
  end
  
  g_distSurf=0
  val=GetVal(sSettings, "distsurf")
  if val then
    g_distSurf=tonumber(val)
  end  

  -- Will cause error if bad syntax
  SettingsToStr()
end


function GetDefaults()
  local mat, i, secondWidth, tblInfo, s, nPlanks
  
  g_topmatid=""
  g_side=1
  g_slotDepth=0.075
  g_slotHeight=0.324
  g_botThickness=0.006
  g_botOversize=0
  g_vertThickness=0.003
  g_vertHeight=0
  
  mat=af_request("elem_getstudmat")
  if mat==nil then
    return false
  end

  g_mat=af_request("singlemat", mat)
  if g_mat==nil then
    return false
  end

  g_thickness=g_mat.thickness
  g_height=g_mat.height
  
  -- Look for "top_force" plank
  g_topOff=nil
  secondWidth=0
  nPlanks=gnPlanks
  if not nPlanks then
    nPlanks=0
  end
  for i=1,nPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^top_force.*") or string.match(s, "^contourtilted.*") then
      tblInfo=af_request("plankinfo")
      g_topOff=tblInfo.width
    elseif string.match(s, "^2ndtop_force.*") then
      tblInfo=af_request("plankinfo")
      if not tblInfo.del then
        secondWidth=tblInfo.width
      end
    end
    ac_objectclose()
  end

  if g_topOff==nil then
    g_topOff=g_thickness
  else
    g_topOff=g_topOff+secondWidth
  end

  g_numPlanks=1
  g_overBelow=0
  g_overInside=0
  g_distSurf=0
  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  -- Ask material
  if not AskMat(sSettings) then
    return nil
  end

  return SettingsToStr()
end


function Set(sSettings)
  local res, errStr, zoff, tblLastAdded, i, v, s, overL, overR, thickness
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  GetDefaults()
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end

  elemThick=af_request("elemcorethickness")
  custThick=nil
  thickness=g_mat.thickness
  if g_mat.thickness==0.0 then
    custThick=g_thickness
    thickness=g_thickness
  end

  custHeight=nil
  if g_mat.height==0.0 then
    custHeight=g_height
  end

  zoff=g_thickness*0.5
  if g_side==2 then
    zoff=elemThick-zoff
  end
--ac_environment("tolog", string.format("g_side=%f, zoff=%f, elemThick=%f", g_side, zoff, elemThick))
  res, tblLastAdded=AddFloorSuppBeam( g_mat.id, zoff, custThick, custHeight, g_numPlanks, g_distSurf, elemThick )
--ac_environment("tolog", string.format("res=%s", res))
  if gxmlOperations==nil then
    gxmlOperations=""
  end

  s=""
  -- Single groove for the deepest plank
  overL=0
  overR=0
  if g_side==2 then
    overR=thickness*(g_numPlanks-1)+g_distSurf+0.001
    overL=g_overInside
  else
    overL=thickness*(g_numPlanks-1)+g_distSurf+0.001
    overR=g_overInside
  end

  s=""
  for i,v in ipairs(tblLastAdded) do
    s=string.format(
      "%s" ..
      "  <groove target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"%s\">\n" ..
      "    <groove overtop=\"%.4f\" overbot=\"0\" overleft=\"%.4f\" overright=\"%.4f\" overlen=\"0.1\"></groove>\n" ..
      "  </groove>\n",
      s, v, g_overBelow, overL, overR )
      
  end

  gxmlOperations = string.format( "<operations>%s%s</operations>", res, s )

  af_request("elem_createplanks")
  
  if g_topmatid~="" then
    AdjustTopMat(g_topmatid)
  end
end


function Reset()
  local res, i, matidbot

  res=false
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^balktop_floor.*") then
      af_request("delplank")
      res=true
    end
    if string.match(s, "^bottom_force.*") then
      matidbot=ac_objectget("iMatId")
    end
    ac_objectclose()
  end
  
  if res and g_topmatid~="" and matidbot then
    -- Restore the same mat as in bottom plate
    AdjustTopMat(matidbot)
  end
  
  return res
end


function GetName(sSettings, baseName)
  return baseName
end
]]>
        </script>


        <!-- Creates/removes grooves top/bottom -->
        <script id="grotopbot">
          <![CDATA[
-- For planks to be created
gnPlankCount=0
gtblCreate = {}
gnGroDepth=0.002


-- Returns string of ptrs for rotateted studs (to be excluded for making grooves)
function FindRotStuds()
  local i, rotStuds, s, v

  rotStuds=""
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    v=ac_objectget("#af_elemdata")
    if string.match(s, "^vertical_%a*") and math.abs(v.rotangle)>1 and math.abs(v.rotangle-180)>1 then
      if rotStuds~="" then
        rotStuds=rotStuds .. ","
      end
      rotStuds=rotStuds .. v.ptr
    end

    ac_objectclose()
  end
  return rotStuds
end



function RemoveGrooves(bSave)
  local tblInfo, tblGroPlanks, nGroPlanks, bRes, bFoundGro, tblOps, k, v, klink, vlink, s

  -- To know which is top and which is bottom
  tblInfo=af_request("elem_getinfo")
  if gOptGroTop then
    -- Set vecy to point outside of top/bottom wood
    tblInfo.vecy.x=-tblInfo.vecy.x
    tblInfo.vecy.y=-tblInfo.vecy.y
    tblInfo.vecy.z=-tblInfo.vecy.z
  end
  
  -- Find top/bottom planks (having grooves)
  bFoundGro=false
  tblGroPlanks={}
  nGroPlanks=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if gOptGroTop then
      bRes=(string.match(s, "^top.*") or string.match(s, "^2ndtop.*") or string.match(s, "^contourtilted.*"))
    else
      bRes=(string.match(s, "^bottom.*") or string.match(s, "^2ndbottom.*"))
    end

    tblOps=nil
    if bRes then
--ac_environment("tolog", string.format("s=%s", s))
      tblOps=af_request("op_get")
    end
    ac_objectclose()

    if tblOps~=nil and #tblOps>0 then
      -- Check if related planks are vertical*
      for k,v in pairs(tblOps) do
        if v.typenum==7 and #v.tbllinks>0 then
          for klink,vlink in pairs(v.tbllinks) do
            ac_objectopen(vlink.guid)
            s=ac_objectget("iElemGroup")
            if string.match(s, "^vertical.*") then
              bFoundGro=true
              if bSave then
                -- Delete male operation
                af_request("op_del", vlink.opid)
              else
                ac_objectclose()
                break
              end
            end
           ac_objectclose()
          end
        end
      end
    end   -- if

  end
  return bFoundGro
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  
  if RemoveGrooves(false) then
    return 1
  end
  return 0
end


function Set(sSettings)
  local rotStuds

  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end
  
  rotStuds=FindRotStuds()
  if gOptGroTop then
      gxmlOperations=
    "<operations>\n" ..  
    string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" targetskip=\"%s\" operator=\"top*|2ndtop*|contourtilted\">\n", rotStuds) ..
    string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\"></cut>\n", gnGroDepth) ..
    "</jointo>\n" ..
    string.format("<groove target=\"top*|2ndtop*|contourtilted\" operator=\"vertical_y*|vertical_spacing|vertical_force\"> operatorskip=\"%s\"\n", rotStuds) ..
    string.format("<groove overtop=\"0.001\" overbot=\"0.001\" overside=\"0.001\" forcedepth=\"%.4f\" force90=\"1\"></groove>\n", gnGroDepth) ..
    "</groove>\n" ..
    "</operations>"
  else
    local i, skipOp, s, v, info
  
      -- Take only pieces less than 1 m from element bottom (try to skip door tops)
    skipOp=""
    for i=1,gnPlanks do
      ac_objectopen(string.format("#%d",i))
      v=ac_objectget("#af_elemdata")
      if math.abs(v.y1-v.y2)<0.001 and v.y1>1 then
        s=ac_objectget("iElemGroup")
        if string.match(s, "^bottom%a*") then
          info=af_request("plankinfo")
          if skipOp~="" then
            skipOp=skipOp .. ","
          end
          skipOp=skipOp .. info.ptr
        end
      end
      ac_objectclose()
    end

    if skipOp~="" then
      skipOp=string.format(" operatorskip=\"%s\"", skipOp) 
    end
    
      gxmlOperations=
    "<operations>\n" ..  
    string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" targetskip=\"%s\" operator=\"bottom*|2ndbottom*\"" .. skipOp ..">\n", rotStuds) ..
    string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\"></cut>\n", gnGroDepth) ..
    "</jointo>\n" ..
    string.format("<groove target=\"bottom*|2ndbottom*\" operator=\"vertical_y*|vertical_spacing|vertical_force\" operatorskip=\"%s\">\n", rotStuds) ..
    string.format("<groove overtop=\"0.001\" overbot=\"0.001\" overside=\"0.001\" forcedepth=\"%.4f\" force90=\"1\"></groove>\n", gnGroDepth) ..
    "</groove>\n" ..
    "</operations>"
  end
  
  af_request("elem_createplanks")
end


function Reset()
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  -- Remove operations
  RemoveGrooves(true)

  if gOptGroTop then
      gxmlOperations=
    "<operations>\n" ..  
    "<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"top*|2ndtop*|contourtilted\">\n" ..
    string.format("<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"%.4f\" endshape=\"angleddelfirst\"></cut>\n", gnGroDepth+0.0001) ..
    "</jointo>\n" ..
    "</operations>"
  else
      gxmlOperations=
    "<operations>\n" ..  
    "<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"bottom*|2ndbottom*\">\n" ..
    string.format("<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"%.4f\" endshape=\"angleddelfirst\"></cut>\n", gnGroDepth+0.0001)  ..
    "</jointo>\n" ..
    "</operations>"
  end

  af_request("elem_createplanks")
end


-- FOR OPTION DLG
-------------------------

]]>
        </script>

        <script id="markingslines">
          <![CDATA[
g_bottomline  =1
g_bottomid    =0
g_topside     =0      -- 0=default, 1-N=force it
g_botside     =0
g_topline     =1
g_topid       =0
g_posbot      =3
g_postop      =3
g_openpcs     =0
g_markopenings=0
g_markneig    =0
g_markjoints  =0
g_marksize    =0.015   -- We use meters and in xml it is centimeters


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local res, i, s, row, rows, mc, t, col, strOp
  
  af_request("elem_getpoly")
  
  res=-1
  if gnPlanks>0 then
    res=0
  end

  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    
    rows=ac_objectget("iMc",-1)
    for row=1,rows do
      mc=ac_objectget("iMc",row,1)
      if mc==303 then
        t=ac_objectget("iMc",row,11)    -- flags
        if (t % 2)==1 then
          ac_objectclose()
          res=1
          break
        end
      end
    end

    ac_objectclose()
  end

  return res
end


function Set(sSettings)
  local i, markid, sXml, bot, top, default, bot2, lang

  lang=af_request("aflang")
  if lang==nil then
    lang="eng"
  end
  gnPlankCount=0
  gtblCreate = {}
  
  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end  
  
  ClearMarkings()  

  local botforce=""

  bot=""
  if g_botside>=1 and g_botside<=6 then
    botforce=string.format("forceside=\"%d\"", g_botside)
    bot=bot .. botforce
  end
  if g_bottomline==1 then
    bot=bot .. "line=\"3\""
  else
    bot=bot .. "line=\"0\""
  end
  if g_bottomid==1 then
    bot=bot .. string.format(" id=\"2\" skipid=\"sideleft*|sideright*\" idline=\"%d\" markxpos=\"2\" markypos=\"1\" marksize=\"%0.6f\" marktextdir=\"0\"", g_posbot, g_marksize*100)
  end
  
  bot2=""
  if g_markopenings==1 then
    if lang=="nor" then
      bot2=bot2 .. string.format("<opening line=\"0\" windowtext=\"Vindu [width]x[height]\" doortext=\"Dør [width]x[height]\" marksize=\"%0.6f\" %s></opening>\n", g_marksize*100, botforce)
    elseif lang=="fin" then
      bot2=bot2 .. string.format("<opening line=\"0\" windowtext=\"Ikk [width]x[height]\" doortext=\"Ovi [width]x[height]\" marksize=\"%0.6f\" %s></opening>\n", g_marksize*100, botforce)
    elseif lang=="swe" then
      bot2=bot2 .. string.format("<opening line=\"0\" windowtext=\"Fönster [width]x[height]\" doortext=\"Dörr [width]x[height]\" marksize=\"%0.6f\" %s></opening>\n", g_marksize*100, botforce)
    else
      bot2=bot2 .. string.format("<opening line=\"0\" windowtext=\"Win [width]x[height]\" doortext=\"Door [width]x[height]\" marksize=\"%0.6f\" %s></opening>\n", g_marksize*100, botforce)
   end
  end
  if g_markneig==1 then
    bot2=bot2 .. string.format("<neighbour begtext=\"&lt;[id]\" endtext=\"[id]&gt;\" marksize=\"%0.6f\" marktextdir=\"1\" %s></neighbour>\n", g_marksize*100, botforce)
  end
 
  top=""
  if g_topside>=1 and g_topside<=6 then
    top=top .. string.format("forceside=\"%d\"", g_topside)
  end

  if g_topline==1 then
    top=top .. "line=\"3\""
  else
    top=top .. "line=\"0\""
  end
  if g_topid==1 then
    top=top .. string.format(" id=\"2\" skipid=\"sideleft*|sideright*\" idline=\"%d\" markxpos=\"2\" markypos=\"1\" marksize=\"%0.6f\" marktextdir=\"0\"", g_postop, g_marksize*100)
  end

  sXml="<markings delold=\"0\">"
  if bot~="" then
    sXml=string.format("%s\n<bottomwood>\n<stud %s/>\n%s</bottomwood>", sXml, bot, bot2)
  elseif bot2~="" then
    sXml=string.format("%s\n<bottomwood>\n%s</bottomwood>", sXml, bot2)
  end
  if top~="" then
    sXml=string.format("%s\n<topwood>\n<stud %s/>\n</topwood>", sXml, top)
  end
  
  if g_markjoints==1 then
    sXml=sXml .. "\n" .. string.format("<joint marksize=\"%0.6f\" marktextdir=\"1\" %s></joint>\n", g_marksize*100, botforce)
  end
  
  sXml=sXml .. "\n</markings>"

  if g_openpcs==1 then
    -- Just marking lines to opening pieces, need to make these first since elem_domarkings gives IDs to planks
    local xmlOp=""
    local domark
    
    domark=1
    if g_botside~=0 then
      domark=2
    end
    
    xmlOp=xmlOp ..
    "<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"vertical_x|contourtilted_opening\">\n" ..
    string.format("<cut jointgap=\"0\" extendmaxlen=\"0.005\" expandopfind=\"0.001\" conntype=\"hasx\" maxdisttoend=\"0.005\" dontcuttarget=\"1\" domark=\"%d\" markside=\"%d\" markauto=\"1\"></cut>\n", domark, g_botside) ..
    "</jointo>\n"

    -- Opening top&bottom to vertical_y
    xmlOp=xmlOp ..
    "<jointo target=\"vertical_x|contourtilted_opening|nogging|sideleft*|sideright*\" operator=\"vertical_y*|vertical_spacing|vertical_force\">\n" ..
    string.format("<cut jointgap=\"0\" extendmaxlen=\"0.005\" expandopfind=\"0.005\" conntype=\"hasx\" maxdisttoend=\"0.010\" dontcuttarget=\"1\" domark=\"%d\" markside=\"%d\" markauto=\"1\"></cut>\n", domark, g_botside) ..
    "</jointo>\n"
    
    gxmlOperations= "<operations>" ..  xmlOp .. "</operations>"
    af_request("elem_createplanks")
  end

  af_request("elem_domarkings", sXml)
end


function Reset()
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end
  
  ClearMarkings()
end
  
function ClearMarkings()
  local i, row, rows, mc, t, col

  -- Remove any marking which is maintained by ArchiFrame
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    
    rows=ac_objectget("iMc",-1)
    for row=1,rows do
      mc=ac_objectget("iMc",row,1)
      if mc==303 then
        t=ac_objectget("iMc",row,11)    -- flags
        if (t % 2)==1 then
          for col=1,16 do
            ac_objectset("iMc", 0, row, col)
          end
          ac_objectset("iMcStr", "", row)
        end
      end
    end

    ac_objectclose()
  end

  return 0
end


-------------------------
-- OPTIONS


-- Asks for the material to use
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
-- Returns: true=ok, false=canceled
function RunSettingsDlg(sSettings)
  local  tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat

  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type   =2
  tblSettings[1].prompt ="Lines bottom"
  tblSettings[1].key    ="bottomlines"
  tblSettings[1].defvalue  =1

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type   =2
  tblSettings[2].prompt ="Stud ID bottom"
  tblSettings[2].key    ="bottomstudids"
  tblSettings[2].defvalue  =0

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type   =2
  tblSettings[3].prompt ="Lines top"
  tblSettings[3].key    ="toplines"
  tblSettings[3].defvalue  =1

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type   =2
  tblSettings[4].prompt ="Stud ID top"
  tblSettings[4].key    ="topstudids"
  tblSettings[4].defvalue  =0

	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	="Stud ID bottom placement"
	tblSettings[5].key		="numplanks"
	tblSettings[5].valuelist="\"1:1 Left\",\"2:2 Right\",\"3:3 Calculate position not to be under any stud\",\"4:4 To center of the stud\""
	tblSettings[5].defvalue	=3

	tblSettings[6]			={}
	tblSettings[6].cfgonly	=0
	tblSettings[6].type		=1
	tblSettings[6].prompt	="Stud ID top placement"
	tblSettings[6].key		="numplanks"
	tblSettings[6].valuelist="\"1:1 Left\",\"2:2 Right\",\"3:3 Calculate position not to be under any stud\",\"4:4 To center of the stud\""
	tblSettings[6].defvalue	=3

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type   =2
  tblSettings[7].prompt ="Mark opening pieces"
  tblSettings[7].key    ="openplanks"
  tblSettings[7].defvalue  =0

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type   =2
  tblSettings[8].prompt ="Mark openings to bottom"
  tblSettings[8].key    ="openings"
  tblSettings[8].defvalue  =0

  tblSettings[9]      ={}
  tblSettings[9].cfgonly  =0
  tblSettings[9].type   =2
  tblSettings[9].prompt ="Mark neighbours to bottom"
  tblSettings[9].key    ="neig"
  tblSettings[9].defvalue  =0
  
	tblSettings[10]			={}
	tblSettings[10].cfgonly	=0
	tblSettings[10].type		=1
	tblSettings[10].prompt	="Force side top"
	tblSettings[10].key		="topside"
	tblSettings[10].valuelist="\"1:1 Automatic\",\"2:2 Top\",\"3:3 Front\",\"4:4 Bottom\",\"5:5 Back\""
	tblSettings[10].defvalue	=1
  
	tblSettings[11]			={}
	tblSettings[11].cfgonly	=0
	tblSettings[11].type		=1
	tblSettings[11].prompt	="Force side bottom, opening and connecting"
	tblSettings[11].key		="botside"
	tblSettings[11].valuelist="\"1:1 Automatic\",\"2:2 Top\",\"3:3 Front\",\"4:4 Bottom\",\"5:5 Back\""
	tblSettings[11].defvalue	=1

  tblSettings[12]      ={}
  tblSettings[12].cfgonly  =1
  tblSettings[12].type   =2
  tblSettings[12].prompt ="Mark connecting pieces"
  tblSettings[12].key    ="connbot"
  tblSettings[12].defvalue  =0

  tblSettings[13]      ={}
  tblSettings[13].cfgonly  =1
  tblSettings[13].type   =3
  tblSettings[13].prompt ="Mark text size"
  tblSettings[13].key    ="marksize"
  tblSettings[13].defvalue  =0.015

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      tblSettings[1].value=g_bottomline
      tblSettings[2].value=g_bottomid
      tblSettings[3].value=g_topline
      tblSettings[4].value=g_topid
      tblSettings[5].value=g_posbot
      tblSettings[6].value=g_postop
      tblSettings[7].value=g_openpcs
      tblSettings[8].value=g_markopenings
      tblSettings[9].value=g_markneig
      tblSettings[10].value=g_topside+1
      tblSettings[11].value=g_botside+1
      tblSettings[12].value=g_markjoints
      tblSettings[13].value=g_marksize
      
    else
      ac_environment( "tolog", string.format("RunSettingsDlg/parse settings failed: %s", tostring(err)) )
    end
  end

  gHelpAnchor="afdlgelemmarkings"
  bRes,sErr=ac_optiondlg("LDML", "Markings settings", tblSettings)
  if not bRes then
    return false
  end

  g_bottomline  =tblSettings[1].value
  g_bottomid    =tblSettings[2].value
  g_topline     =tblSettings[3].value
  g_topid       =tblSettings[4].value
  g_posbot      =tblSettings[5].value
  g_postop      =tblSettings[6].value
  g_openpcs     =tblSettings[7].value
  g_markopenings=tblSettings[8].value
  g_markneig    =tblSettings[9].value
  g_topside     =tblSettings[10].value-1
  g_botside     =tblSettings[11].value-1
  g_markjoints  =tblSettings[12].value
  g_marksize    =tblSettings[13].value
  
  return true
end



-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  local s
  
  g_bottomline  =tonumber(GetVal(sSettings, "bottomline"))
  g_bottomid    =tonumber(GetVal(sSettings, "bottomid"))
  g_topline     =tonumber(GetVal(sSettings, "topline"))
  g_topid       =tonumber(GetVal(sSettings, "topid"))

  g_posbot      =3
  g_postop      =3
  
  s=GetVal(sSettings, "posbot")
  if s then
    g_posbot=tonumber(s)
  end
  s=GetVal(sSettings, "postop")
  if s then
    g_postop=tonumber(s)
  end
  
  g_openpcs=0
  s=GetVal(sSettings, "openpcs")
  if s then
    g_openpcs=tonumber(s)
  end

  s=GetVal(sSettings, "opening")
  if s then
    g_markopenings=tonumber(s)
  end
  s=GetVal(sSettings, "neig")
  if s then
    g_markneig=tonumber(s)
  end
  
  s=GetVal(sSettings, "topside")
  if s then
    g_topside=tonumber(s)
  end
  s=GetVal(sSettings, "botside")
  if s then
    g_botside=tonumber(s)
  end
  
  s=GetVal(sSettings, "markjoints")
  if s then
    g_markjoints=tonumber(s)
  end
  
  s=GetVal(sSettings, "marksize")
  if s then
    g_marksize=tonumber(s)
  end
  
  -- Will cause error if bad syntax
  s = SettingsToStr()
end


function GetDefaults()
  g_bottomline  =1
  g_bottomid    =0
  g_topline     =1
  g_topid       =0
  g_posbot      =3
  g_postop      =3
  g_openpcs     =0
  g_markopenings=0
  g_markneig    =0
  g_topside     =0
  g_botside     =0
  g_markjoints  =0
  g_marksize    =0.015
  return true
end



-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=SettingsToStr()
    end
  end

  if RunSettingsDlg(sSettings)==false then
    return nil
  end

  sSettings=SettingsToStr()
  return sSettings
end

function SettingsToStr()
  return string.format("bottomline=%d\nbottomid=%d\ntopline=%d\ntopid=%d\nposbot=%d\npostop=%d\nopening=%d\nneig=%d\ntopside=%d\nbotside=%d\nmarkjoints=%d\nopenpcs=%d\nmarksize=%0.6f", g_bottomline, g_bottomid, g_topline, g_topid, g_posbot, g_postop, g_markopenings, g_markneig, g_topside, g_botside, g_markjoints, g_openpcs, g_marksize)
end
]]>
        </script>


        <script id="markingsgro">
          <![CDATA[
g_grodepth=0.005
g_groover=0.001     -- Previously used for each side, now for top&bottom
g_grooverSides=0.001  -- Used for sides
g_noggingsGap=0
gnDoTop=1
gnDoBot=1
gnDoOpening=1
gnDoFloor=0       -- 2/2022: Include floor names 0/1
gnDoStraightStudEnds=0


-- Dumps given variable into string
function DumpTblInt(o, nIndent)
  local s,k,v

  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end

    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end

    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end


function DoGroXml(isTop)
  local xmlOp, skipOpTop, tblVertx, nVertx, tblVerty, nVerty, tbl, skipOpVertx
  local i, ix, s, v, info, x, y, d, rotStuds

  -- Take only pieces less than 1 m from element bottom (try to skip door tops)
  -- Also make table of all vertical_x-planks (at opening top&bottom) and vertical_y not to make grooves for lintel support pieces
  rotStuds=""
  skipOpTop=""
  tblVertx={}
  nVertx=0
  tblVerty={}
  nVerty=0

--ac_environment("tolog", string.format("gnPlanks=%d", gnPlanks))
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    v=ac_objectget("#af_elemdata")
    s=ac_objectget("iElemGroup")
    guidElem=ac_objectget("#guid")

    if math.abs(v.y1-v.y2)<0.001 and v.y1>1 and string.match(s, "^bottom%a*") then
      info=af_request("plankinfo")
      if skipOpTop~="" then
        skipOpTop=skipOpTop .. ","
      end
      skipOpTop=skipOpTop .. info.ptr
    elseif s=="vertical_x" or s=="vertical_y" then
      tbl={}
      tbl.elemdata=v
      tbl.plankinfo=af_request("plankinfo")
        
--ac_environment("tolog", string.format("%s x1=%f x2=%f", s, tbl.elemdata.x1, tbl.elemdata.x2))
      if s=="vertical_x" then
        tbl.minx=0
        tbl.maxx=tbl.plankinfo.len
        nVertx=nVertx+1
        tblVertx[nVertx]=tbl
      else
        nVerty=nVerty+1
        tblVerty[nVerty]=tbl
      end
    end

    if string.match(s, "^vertical_%a*") and math.abs(v.rotangle)>1 and math.abs(v.rotangle-180)>1 then
      if rotStuds~="" then
        rotStuds=rotStuds .. ","
      end
      rotStuds=rotStuds .. v.ptr
    end
    ac_objectclose()
  end

  -- Find all vertical_y to skip for matching vertical_x (lintel supports). First adjust minx, maxx for each vertical_x
  local changed, changedNow, dummy

  skipOpVertx=""
  for ix=1,nVertx do
    -- Need to rescan if minx/maxx changed
    repeat
      changed=false
      for i=1,nVerty do
        x,y=ac_geo("linex", tblVertx[ix].elemdata.x1, tblVertx[ix].elemdata.y1, tblVertx[ix].elemdata.x2, tblVertx[ix].elemdata.y2, tblVerty[i].elemdata.x1, tblVerty[i].elemdata.y1, tblVerty[i].elemdata.x2, tblVerty[i].elemdata.y2)
        if x and y then
          -- Intersection must be at the end of vertical_y
          dummy,d=ac_geo("linedist", tblVerty[i].elemdata.x1, tblVerty[i].elemdata.y1, tblVerty[i].elemdata.x2, tblVerty[i].elemdata.y2, x, y)
--ac_environment("tolog", string.format("verty: x=%f y=%f d=%f", x, y, d))
          if math.abs(d-tblVerty[i].plankinfo.len-tblVertx[ix].plankinfo.width*0.5)<0.001 then
            -- vertical_y adjusted to the bottom of vertical_x, check if intersects with vertical_x
            dummy,d=ac_geo("linedist", tblVertx[ix].elemdata.x1, tblVertx[ix].elemdata.y1, tblVertx[ix].elemdata.x2, tblVertx[ix].elemdata.y2, x, y)
--ac_environment("tolog", string.format("vertx: d=%f", d))
            changedNow=false
            if d>tblVertx[ix].minx and d<tblVertx[ix].minx+tblVerty[i].plankinfo.width*0.5+0.010 then
              tblVertx[ix].minx=d+tblVerty[i].plankinfo.width*0.5
              changedNow=true
--ac_environment("tolog", string.format("minx=%f d=%f", tblVertx[ix].minx, d))
            elseif d<tblVertx[ix].maxx and d>tblVertx[ix].maxx-tblVerty[i].plankinfo.width*0.5-0.010 then
              tblVertx[ix].maxx=d-tblVerty[i].plankinfo.width*0.5
              changedNow=true
--ac_environment("tolog", string.format("maxx=%f d=%f", tblVertx[ix].maxx, d))
            end

            if changedNow then
              changed=true
              if skipOpVertx~="" then
                skipOpVertx=skipOpVertx .. ","
              end
              skipOpVertx=skipOpVertx .. tblVerty[i].plankinfo.ptr
            end

          end
        end
      end
    until not changed
  end
  
  -- Added 2/2022 to be able to make grooves to floors also
  local floorTarg=""
  local floorOps=""
  
  if gnDoFloor==1 then
    floorTarg="|contour_x"
    floorOps="|contour_y"
  end

  xmlOp=""
  if isTop then
    if gnDoTop==1 then
      local opTilted

      xmlOp=""
      opTilted = "|contourtilted"     -- Old way also extend to tilted parts

      if gnDoStraightStudEnds == 1 then
        -- Different handling for tilted parts only
        xmlOp = xmlOp .. string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force%s\" targetskip=\"%s\" operator=\"contourtilted\">\n", floorOps, rotStuds)
        xmlOp = xmlOp .. string.format("<cut jointgap=\"0.0\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"straightlong\" conntype=\"linex\" maxdisttoend=\"0.001\"></cut>\n")
        xmlOp = xmlOp .. "</jointo>\n"
        opTilted=""                   -- Tilted parts handled
      end

      -- Old way: Extend to all (but now contourtilted perhaps omitted and just straight parts handled)
      xmlOp = xmlOp .. string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force%s\" targetskip=\"%s\" operator=\"top*|2ndtop*%s%s\">\n", floorOps, rotStuds, opTilted, floorTarg)
      xmlOp = xmlOp .. string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.001\"></cut>\n", g_grodepth)
      xmlOp = xmlOp .. "</jointo>\n"
      
      -- Grooves straight
      xmlOp = xmlOp .. string.format("<groove target=\"top*|2ndtop*%s%s\" operator=\"vertical_y*|vertical_spacing|vertical_force%s\" operatorskip=\"%s\">\n", opTilted, floorTarg, floorOps, rotStuds)
      xmlOp = xmlOp .. string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"%.4f\" forcedepth=\"%.4f\" force90=\"1\"></groove>\n", g_groover, g_groover, g_grooverSides, g_grodepth) .. "</groove>\n"
      
      if gnDoStraightStudEnds == 1 then
        -- Different handling for tilted parts only
        xmlOp = xmlOp .. string.format("<groove target=\"contourtilted\" operator=\"vertical_y*|vertical_spacing|vertical_force%s\" operatorskip=\"%s\">\n", floorOps, rotStuds)
        xmlOp = xmlOp .. string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"0\"></groove>\n", g_groover, g_groover) .. "</groove>\n"
      end
    end
  else
    if gnDoBot==1 then
      if skipOpTop~="" then
        skipOpTop=string.format(" operatorskip=\"%s\"", skipOpTop) 
      end

      xmlOp=
      string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force%s\" targetskip=\"%s\" operator=\"bottom*|2ndbottom*%s\"" .. skipOpTop ..">\n", floorOps, rotStuds, floorTarg) ..
      string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\"></cut>\n", g_grodepth) ..
      "</jointo>\n" ..
      string.format("<groove target=\"bottom*|2ndbottom*%s\" operator=\"vertical_y*|vertical_spacing|vertical_force%s\" operatorskip=\"%s\">\n", floorTarg, floorOps, rotStuds) ..
      string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"%.4f\" forcedepth=\"%.4f\" force90=\"1\"></groove>\n", g_groover, g_groover, g_grooverSides, g_grodepth) ..
      "</groove>\n"
    end
  end

  if gnDoOpening==1 then
    -- Also studs to vertical_x -planks
    local opTilted
    
    s=""
    if skipOpVertx~="" then
      s=string.format(" targetskip=\"%s\"", skipOpVertx) 
      skipOpVertx=string.format(" operatorskip=\"%s\"", skipOpVertx) 
    
      -- Add rotated studs to skip items
      if rotStuds~="" then
        s=string.format("%s,%s", s, rotStuds)
        skipOpVertx=string.format("%s,%s", skipOpVertx, rotStuds)
      end
    end
    
    opTilted = "|contourtilted_opening"     -- Old way also extend to tilted parts
    if gnDoStraightStudEnds == 1 then
      opTilted = ""
    end

    -- Straight parts (and tilted if gnDoStraightStudEnds not 1)
    xmlOp=xmlOp ..
    "<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"vertical_x" .. opTilted .. "\"" .. s ..">\n" ..
    string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n", g_grodepth) ..
    "</jointo>\n" ..
    "<groove target=\"vertical_x" .. opTilted .. "\" operator=\"vertical_y*|vertical_spacing|vertical_force\"" .. skipOpVertx ..">\n" ..
    string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"%.4f\" forcedepth=\"%.4f\" force90=\"1\" conntype=\"linex\" maxdisttoendop=\"0.010\"></groove>\n", g_groover, g_groover, g_grooverSides, g_grodepth) ..
    "</groove>\n"
    
    if gnDoStraightStudEnds == 1 then
      -- Different handling for tilted parts only
      xmlOp = xmlOp .. string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" %s operator=\"contourtilted_opening\">\n", s)
      xmlOp = xmlOp .. string.format("<cut jointgap=\"0.0\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"straightlong\" conntype=\"linex\" maxdisttoend=\"0.001\"></cut>\n")
      xmlOp = xmlOp .. "</jointo>\n"
      
      -- Grooves
      xmlOp=xmlOp ..
      "<groove target=\"contourtilted_opening\" operator=\"vertical_y*|vertical_spacing|vertical_force\"" .. skipOpVertx ..">\n" ..
      string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"0\" conntype=\"linex\" maxdisttoendop=\"0.010\"></groove>\n", g_groover, g_groover) ..
      "</groove>\n"
    end
    

    -- Opening top&bottom to vertical_y
    xmlOp=xmlOp ..
    "<jointo target=\"vertical_x|contourtilted_opening\" operator=\"vertical_y*|vertical_spacing|vertical_force\">\n" ..
    string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n", g_grodepth) ..
    "</jointo>\n" ..
    "<jointo target=\"nogging\" operator=\"vertical_y*|vertical_spacing|vertical_force\">\n" ..
    string.format("<cut jointgap=\"-%.4f\" extendmaxlen=\"0.0\" expandopfind=\"0.001\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n", g_grodepth-g_noggingsGap) ..
    "</jointo>\n" ..
    "<groove target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"vertical_x|contourtilted_opening|nogging\">\n"

    xmlOp = xmlOp .. string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"%.4f\" forcedepth=\"%.4f\" force90=\"1\" conntype=\"linex\" mindisttoend=\"0.025\"></groove>\n", g_groover, g_groover, g_grooverSides, g_grodepth) ..
      "</groove>\n"

  end

  return xmlOp
end


function RemoveGrooves(isTop, bSave)
  local tblInfo, tblGroPlanks, nGroPlanks, bRes, bFoundGro, tblOps, k, v, klink, vlink, s

  -- To know which is top and which is bottom
  tblInfo=af_request("elem_getinfo")
  if isTop then
    -- Set vecy to point outside of top/bottom wood
    tblInfo.vecy.x=-tblInfo.vecy.x
    tblInfo.vecy.y=-tblInfo.vecy.y
    tblInfo.vecy.z=-tblInfo.vecy.z
  end
  
  -- Find top/bottom planks (having grooves)
  bFoundGro=false
  tblGroPlanks={}
  nGroPlanks=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if isTop then
      bRes=(string.match(s, "^top.*") or string.match(s, "^2ndtop.*") or string.match(s, "^contourtilted.*"))
    else
      bRes=(string.match(s, "^bottom.*") or string.match(s, "^2ndbottom.*"))
    end
    
    if not bRes then
      bRes=(s=="vertical_x")        -- Opening top/bottom
      if not bRes then
        bRes=string.match(s, "^nogging.*")
      end
    end

    if not bRes and gnDoFloor==1 then
      bRes=(s=="contour_x")        -- Floor top/bottom piece
    end

    tblOps=nil
    if bRes then
--ac_environment("tolog", string.format("s=%s", s))
      tblOps=af_request("op_get")
    end
    ac_objectclose()

    if tblOps~=nil and #tblOps>0 then
      -- Check if related planks are vertical*
      for k,v in pairs(tblOps) do
        if v.typenum==7 and #v.tbllinks>0 then
          for klink,vlink in pairs(v.tbllinks) do
            ac_objectopen(vlink.guid)
            s=ac_objectget("iElemGroup")
            if string.match(s, "^vertical.*") then
              bFoundGro=true
              if bSave then
                -- Delete male operation
                af_request("op_del", vlink.opid)
              else
                ac_objectclose()
                break
              end
            end
           ac_objectclose()
          end
        end
      end
    end   -- if

  end
  return bFoundGro
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local res
  
  af_request("elem_getpoly")
  
  res=-1
  if RemoveGrooves(true, false) then
    res=1
  elseif RemoveGrooves(true, false) then
    res=1
  elseif gnPlanks>0 then
    res=0
  end

  return res
end


function Set(sSettings)
  local res, errStr, strOp

  gnPlankCount=0
  gtblCreate = {}
  gxmlOperations=nil

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end

  res=false
  if sSettings~=nil then
    res=pcall(ParseSettings, sSettings)
  end

  if not res then
    GetDefaults()
  end

  strOp=""
  strOp=DoGroXml(true)

  strOp=strOp .. DoGroXml(false)
  
  if strOp~="" then
    gxmlOperations= "<operations>" ..  strOp .. "</operations>"
  end

  af_request("elem_createplanks")
end


function Reset()
  local i, s, row, rows, mc, t, col, strOp

  gnPlankCount=0
  gtblCreate = {}
  gxmlOperations=nil

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end
  
  RemoveGrooves(true, true)
  RemoveGrooves(false, true)

  -- 1/22: To support floor contour pieces
  local floorTarg=""
  local floorOps=""
  
  if gnDoFloor==1 then
    floorTarg="|contour_x"
    floorOps="|contour_y"
  end
  
  -- Will not remove stud trimmings to contourtilted_openings, should be contourtilted* but it would then cut studs into two pieces...
  strOp=
  string.format("<jointo target=\"vertical_y*|vertical_spacing|vertical_force%s\" operator=\"top*|2ndtop*|contourtilted*%s\">\n", floorOps, floorTarg) ..
  "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\" conntype=\"hasx\" maxdisttoend=\"0.050\"></cut>\n" ..
  "</jointo>\n"

  strOp=strOp ..
    "<jointo target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"bottom*|2ndbottom*\">\n" ..    -- Floor has contour_x at top and bottom
    "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\"></cut>\n" ..
    "</jointo>\n"

  strOp=strOp ..
    "<jointo target=\"vertical_spacing\" operator=\"vertical_x\">\n" ..
    "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\"></cut>\n" ..
    "</jointo>\n"

  -- If there is angled joint in top piece and connecting to opening horizontal piece
  strOp=strOp ..
    "<jointo target=\"vertical_y\" operator=\"vertical_x\">\n" ..
    "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n" ..
    "</jointo>\n"

  strOp=strOp ..
    "<jointo target=\"vertical_x|contourtilted_opening\" operator=\"vertical_y*|vertical_force\">\n" ..
    "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n" ..
    "</jointo>\n"

  strOp=strOp ..
    "<jointo target=\"nogging\" operator=\"vertical*\">\n" ..
    "<cut jointgap=\"0.000\" extendmaxlen=\"0.0\" expandopfind=\"0.0051\" endshape=\"angleddelfirst\" conntype=\"linex\" maxdisttoend=\"0.010\"></cut>\n" ..
    "</jointo>\n"

  if strOp~="" then
    gxmlOperations= "<operations>" ..  strOp .. "</operations>"
  end
  
  af_request("elem_createplanks")
  return 0
end


-------------------------
-- OPTIONS


-- Asks for the material to use
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
-- Returns: true=ok, false=canceled
function RunSettingsDlg(sSettings)
  local  tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat

  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =3
  tblSettings[1].prompt  ="Grooves depth"
  tblSettings[1].key    ="grodepth"
  tblSettings[1].defvalue  =0.005

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type    =3
  tblSettings[2].prompt  ="Grooves oversize top&bottom"
  tblSettings[2].key    ="gro_over"
  tblSettings[2].defvalue  =0.001

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  ="Grooves oversize sides"
  tblSettings[3].key    ="gro_oversides"
  tblSettings[3].defvalue  =0.001

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type    =2
  tblSettings[4].prompt  ="Grooves to top"
  tblSettings[4].key    ="gro_top"
  tblSettings[4].defvalue  =1

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type    =2
  tblSettings[5].prompt  ="Grooves to bottom"
  tblSettings[5].key    ="gro_bot"
  tblSettings[5].defvalue  =1

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type    =2
  tblSettings[6].prompt  ="Grooves to opening pieces"
  tblSettings[6].key    ="gro_opening"
  tblSettings[6].defvalue  =1

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type    =3
  tblSettings[7].prompt  ="Noggings gap"
  tblSettings[7].key    ="nogging_gap"
  tblSettings[7].defvalue  =0

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type    =2
  tblSettings[8].prompt  ="Grooves to floors also"
  tblSettings[8].key    ="gro_floor"
  tblSettings[8].defvalue  =0

  tblSettings[9] = {}
  tblSettings[9].cfgonly = 0
  tblSettings[9].type    = 2
  tblSettings[9].prompt  = "Straight stud ends when connecting to angled parts"
  tblSettings[9].key     = "straight_stud_ends"
  tblSettings[9].defvalue = 0


  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      tblSettings[1].value=g_grodepth
      tblSettings[2].value=g_groover
      tblSettings[3].value=g_grooverSides
      tblSettings[4].value=gnDoTop
      tblSettings[5].value=gnDoBot
      tblSettings[6].value=gnDoOpening
      tblSettings[7].value=g_noggingsGap
      tblSettings[8].value=gnDoFloor
      tblSettings[9].value=gnDoStraightStudEnds     -- PH: Must be to save per element
    else
      --ac_environment( "tolog", string.format("RunSettingsDlg/parse settings failed: %s", tostring(err)) )
    end
  end

  bRes,sErr=ac_optiondlg("LDMA", "Markings settings", tblSettings)
  if not bRes then
    return false
  end

  g_grodepth  =tblSettings[1].value
  g_groover   =tblSettings[2].value
  g_grooverSides=tblSettings[3].value
  gnDoTop     =tblSettings[4].value
  gnDoBot     =tblSettings[5].value
  gnDoOpening =tblSettings[6].value
  g_noggingsGap=tblSettings[7].value
  gnDoFloor   =tblSettings[8].value
  gnDoStraightStudEnds = tblSettings[9].value

  return true
end



-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height
function ParseSettings(sSettings)
  local s
  
  GetDefaults()
  g_grodepth=tonumber(GetVal(sSettings, "grodepth"))
  
  -- Settings added later
  s=GetVal(sSettings, "groover")
  if s then
    g_groover=tonumber(s)
  end

  s=GetVal(sSettings, "grooversides")
  if s then
    g_grooverSides=tonumber(s)
  end

  s=GetVal(sSettings, "grotop")
  if s then
    gnDoTop=tonumber(s)
  end
  
  s=GetVal(sSettings, "grobot")
  if s then
    gnDoBot=tonumber(s)
  end
  
  s=GetVal(sSettings, "groopening")
  if s then
    gnDoOpening=tonumber(s)
  end
  
  s=GetVal(sSettings, "noggap")
  if s then
    g_noggingsGap=tonumber(s)
  end
  
  s=GetVal(sSettings, "dofloor")
  if s then
    gnDoFloor=tonumber(s)
  end

  s = GetVal(sSettings, "straight_stud_ends")
  if s then
    gnDoStraightStudEnds=tonumber(s)
  end

  -- Will cause error if bad syntax
  s = string.format("%f %f %f %d %d %d %f %d", g_grodepth, g_groover, g_grooverSides, gnDoTop, gnDoBot, gnDoOpening, g_noggingsGap, gnDoStraightStudEnds)
end

function GetDefaults()
  g_grodepth=0.005
  g_groover=0.001
  g_grooverSides=0.001
  gnDoTop=1
  gnDoBot=1
  gnDoOpening=1
  g_noggingsGap=0
  gnDoFloor=0
  gnDoStraightStudEnds=0
  
  return true
end



-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("grodepth=%.4f", g_grodepth)
    end
  end

  if RunSettingsDlg(sSettings)==false then
    return nil
  end

  sSettings=string.format("grodepth=%f\ngroover=%.4f\ngrooversides=%.4f\ngrotop=%d\ngrobot=%d\ngroopening=%d\nnoggap=%f\ndofloor=%d\nstraight_stud_ends=%d\n", g_grodepth, g_groover, g_grooverSides, gnDoTop, gnDoBot, gnDoOpening, g_noggingsGap, gnDoFloor, gnDoStraightStudEnds)
  return sSettings
end
]]>
        </script>


        <!-- Norwegian opening -->
        <script id="openingsides">
          <![CDATA[
-- Lua script, see ArchiFrame manual

-- For planks to be created
gnPlankCount=0
gtblCreate = {}


gOptGroupName="vertical_y_openingside"


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Asks for the material to use
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
-- Returns three values: matid, thickness, height
function AskMat(sSettings)
	local	tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    
    
  tblMat=af_request("matlist")
  s=""
  strSep=""
    
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
  end

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end

	tblSettings={}
	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=1
	tblSettings[1].prompt	="Material"
	tblSettings[1].key		="balkmat"
	tblSettings[1].valuelist=s
	tblSettings[1].defvalue	=1

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=3
	tblSettings[2].prompt	="Thickness if not fixed"
	tblSettings[2].key		="thickness"
	tblSettings[2].defvalue	=0.050

	tblSettings[3]			={}
	tblSettings[3].cfgonly	=0
	tblSettings[3].type		=3
	tblSettings[3].prompt	="Height if not fixed"
	tblSettings[3].key		="height"
	tblSettings[3].defvalue	=0.100

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      for i=1,#tblSorted do
        if tblSorted[i].id==g_mat.id then
          tblSettings[1].value=i
          break
        end
      end
      tblSettings[2].value=g_thickness
      tblSettings[3].value=g_height
    else
      ac_environment( "tolog", string.format("AskMat/parse settings failed: %s", tostring(err)) )
    end
  end

	bRes,sErr=ac_optiondlg("LDOS", "Side planks material", tblSettings)
	if not bRes then
    return
  end
    
  mat=tblSorted[tblSettings[1].value]
  thickness=mat.thickness
  height=mat.height
  if thickness==0.0 then
    thickness=tblSettings[2].value
  end
  if height==0.0 then
    height=tblSettings[3].value
  end

  return mat, thickness, height
end


-- Scans edges table and returns table of edges for given holeIndex (1...N)
-- Returns: nil=no such opening, tbl=1-based table of edges
function GetOpening(holeIndex)
  local i,v
  local tblRes, nres
  
  nres=0
  tblRes={}
  for i,v in ipairs(gtblEdges) do
    -- Process only contour line
    if v.holeindex==holeIndex then
      nres=nres+1
      tblRes[nres]=v
    end
  end
  
  if nres==0 then
    return nil
  end

  return tblRes
end


-- Forget bottom joining for now
function DoJoinTopBotXml(plankNum)
  local s

  s=string.format("<jointo target=\"#%d\" operator=\"top*|2ndtop*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.100\" removepart=\"up\"></cut></jointo>", plankNum)
  return s
end


-- Adds top balk(s) below the upper with group names:
-- nMatThickness, nMatHeight If generic "block", "round" etc type. nil if defined by strMatId
function DoOpeningSides( strMatId, nMatThickness, nMatHeight )
  local nOpening, tblOpening, edge, vEdge, tblEdit, dx, tblSides, nSides, i, v
  local plank, strXmlOp
  local tblLimitOpenings


  gnPlankCount=0
  gtblCreate = {}
  tblLimitOpenings = nil   -- If non-nil, contains true value for every opening index to be handled, for example opening 1: [1]=true
  
  if gAdjustElems then
    -- From options tool palette, may limit openings with selection. Check if selected planks related to any openig
    local tblSel, guid, tblSelGuids

    tblSel=af_request("getselplanks")
    if tblSel then
    
      tblSelGuids={}
      for i,v in pairs(tblSel) do
        tblSelGuids[v]=true
      end

      nOpening=1
      while true do
        tblOpening=GetOpening(nOpening)
        if tblOpening==nil then
          break
        end
        
        for edge,vEdge in ipairs(tblOpening) do
          if vEdge.ptr then
            ac_objectopen(vEdge.ptr)
            guid=ac_objectget("#guid")
            ac_objectclose()
            if tblSelGuids[guid]~=nil then
              if tblLimitOpenings==nil then
                tblLimitOpenings={}
              end
          
              tblLimitOpenings[nOpening]=true
            end
          end
        end
        
        nOpening=nOpening+1
      end
    end
  end

  nOpening=1
  strXmlOp=""
  while true do
    tblOpening=GetOpening(nOpening)
    if tblOpening==nil then
      break
    end
    nOpening=nOpening+1

    if #tblOpening==4 and (tblLimitOpenings==nil or tblLimitOpenings[nOpening-1]) then 
      -- Find vertical pieces (openings are ccw as the main contour)
      nSides=0
      tblSides={}
      for edge,vEdge in ipairs(tblOpening) do
        if math.abs(vEdge.x2-vEdge.x1)<0.001 then
          -- Vertical, inside element is at the right hand side
          if vEdge.ptr then
            dx=nMatThickness
            if vEdge.y1>vEdge.y2 then
              dx=-dx
            end
            
            nSides=nSides+1
            tblSides[nSides]={}
            tblSides[nSides].edge=vEdge
            tblSides[nSides].dx=dx

            tblEdit={}
            tblEdit.guid=vEdge.ptr
          
  --ac_environment("tolog", dump(vEdge))

            ac_objectopen(tblEdit.guid)
            tblEdit.elemdata=ac_objectget("#af_elemdata")
            ac_objectclose()
          
            tblEdit.elemdata.x1=tblEdit.elemdata.x1+dx
            tblEdit.elemdata.x2=tblEdit.elemdata.x2+dx

            af_request("editplank", tblEdit)
            strXmlOp=strXmlOp .. DoJoinTopBotXml(tblEdit.elemdata.index)

            plank={}
            plank.guidsettings=tblEdit.guid
            plank.group=gOptGroupName
            plank.id=strMatId
            plank.thickness=nMatThickness
            plank.height=nMatHeight

            plank.x1=vEdge.x1+dx*0.5
            plank.y1=vEdge.y1
            plank.x2=plank.x1
            plank.y2=vEdge.y2
            --plank.extendtoelem=1
            gnPlankCount=gnPlankCount+1
            gtblCreate[gnPlankCount]=plank

          end
        end
      end   -- for edge,vEdge

      for edge,vEdge in ipairs(tblOpening) do
        if math.abs(vEdge.y2-vEdge.y1)<0.001 then
          -- Horizontal
          if vEdge.ptr then

            tblEdit={}
            tblEdit.guid=vEdge.ptr
          
            ac_objectopen(tblEdit.guid)
            tblEdit.elemdata=ac_objectget("#af_elemdata")
            ac_objectclose()
            
            for i,v in ipairs(tblSides) do
              if math.abs(v.edge.x1-tblEdit.elemdata.x1)<0.001 then
                tblEdit.elemdata.x1=tblEdit.elemdata.x1+v.dx
              elseif math.abs(v.edge.x1-tblEdit.elemdata.x2)<0.001 then
                tblEdit.elemdata.x2=tblEdit.elemdata.x2+v.dx
              end
            end

            af_request("editplank", tblEdit)
          end
        end
      end   -- for edge,vEdge
    end

  end
  
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end
  
end


-------------------------
-- FOR OPTION DLG


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height
function ParseSettings(sSettings)
  local s, mat, val
  
  --ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )

  mat=GetVal(sSettings, "mat")
  g_mat=af_request("singlemat", mat)
  g_thickness=g_mat.thickness
  g_height=g_mat.height
  if g_thickness==0.0 then
    g_thickness=tonumber(GetVal(sSettings, "thickness"))
  end
  if g_height==0.0 then
    g_height=tonumber(GetVal(sSettings, "height"))
  end

  -- Will cause error if bad syntax
  s = string.format("%s, thickness=%f, height=%f", g_mat.id, g_thickness, g_height)
end


-- Finds nice material
function GetDefaults()
  local mat, tblMat, i, secondWidth, tblInfo, s
  
  mat=af_request("elem_getstudmat")
  if mat==nil then
    return false
  end

  tblMat=af_request("singlemat", mat)
  if tblMat==nil then
    return false
  end

  g_thickness=0.022     -- 22 mm by default
  g_height=tblMat.height -- Studding height here
  
  g_mat=af_request("singlemat", "block")
  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("mat=%s\nthickness=%f\nheight=%f", g_mat.id, g_thickness, g_height)
    end
  end
  -- Ask material
  local mat, thickness, height, topOff, numPlanks
  mat, thickness, height = AskMat(sSettings)
  if mat==nil then
    return nil
  end

  s=string.format("mat=%s\nthickness=%f\nheight=%f", mat.id, thickness, height)
  return s
end


function Set(sSettings)
  local default, res, errStr, zoff, tblLastAdded, i, v, s, overL, overR, thickness
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end
  
  if g_mat.thickness>0 then
    g_thickness=g_mat.thickness
  end

  if g_mat.height>0 then
    g_height=g_mat.height
  end

  DoOpeningSides( g_mat.id, g_thickness, g_height )
  
  af_request("elem_createplanks")
end


function Reset()
  local i, elemDel, infoDel, elemNow, infoNow, nOpening, tblOpening, vEdgeOpening, edgeDir, y, y1, y2, e, v, x, tblEdit
  local strXmlOp

  gnPlankCount=0
  gtblCreate = {}

  res=false
  strXmlOp=""
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      elemDel=ac_objectget("#af_elemdata")
      infoDel=af_request("plankinfo")
      af_request("delplank")
      ac_objectclose()

      -- Find opening edge related to this piece
      y1=elemDel.y1
      y2=elemDel.y2
      if y1>y2 then
        y1,y2=y2,y1
      end

      nOpening=1
      while true do
        tblOpening=GetOpening(nOpening)
        if tblOpening==nil then
          break
        end
        nOpening=nOpening+1
        for e,v in ipairs(tblOpening) do
          y=(v.y1+v.y2)*0.5
          if math.abs(v.x1-v.x2)<0.001 and y1<y and y2>y then
            vEdgeOpening=nil
            if math.abs(v.x1-elemDel.x1-infoDel.width*0.5)<0.001 then
              -- On left side
              vEdgeOpening=v
              x=elemDel.x1-infoDel.width*0.5
              edgeDir=-1
            elseif math.abs(elemDel.x1-v.x2-infoDel.width*0.5)<0.001 then
              -- On right side
              vEdgeOpening=v
              edgeDir=1
              x=elemDel.x1+infoDel.width*0.5
            end

            if vEdgeOpening~=nil then
              -- Find stud next to plank to be deleted. x set to the edge of deleted plank next to stud. Also process opening top & bottom
              for e=1,gnPlanks do
                ac_objectopen(string.format("#%d",e))
                elemNow=ac_objectget("#af_elemdata")
                infoNow=af_request("plankinfo")
                ac_objectclose()
                
--ac_environment("tolog", string.format("x=%f elemNow=%s", x,dump(elemNow)))

                if elemNow.y1<y2 and elemNow.y2>y1 and math.abs(elemNow.x1-elemNow.x2)<0.001 and math.abs(elemNow.x1-edgeDir*infoNow.width*0.5-x)<0.001 then
                  -- Affected stud found, move
                  tblEdit={}
                  tblEdit.guid=infoNow.ptr
                  tblEdit.elemdata=elemNow
                  tblEdit.elemdata.x1=tblEdit.elemdata.x1-edgeDir*infoDel.width
                  tblEdit.elemdata.x2=tblEdit.elemdata.x1
                  af_request("editplank", tblEdit)
                  strXmlOp=strXmlOp .. DoJoinTopBotXml(tblEdit.elemdata.index)
                end
                
                if math.abs(elemNow.y2-elemNow.y1)<0.001 and (math.abs(elemNow.y1+infoNow.width*0.5-y1)<0.001 or math.abs(elemNow.y1-infoNow.width*0.5-y2)<0.001) then
                  -- Y-coordinate matches, check if left or right
                  if math.abs(x-elemNow.x1)<0.001 then
                    tblEdit={}
                    tblEdit.guid=infoNow.ptr
                    tblEdit.elemdata=elemNow
                    tblEdit.elemdata.x1=tblEdit.elemdata.x1-edgeDir*infoDel.width
                    af_request("editplank", tblEdit)
                  elseif math.abs(x-elemNow.x2)<0.001 then
                    tblEdit={}
                    tblEdit.guid=infoNow.ptr
                    tblEdit.elemdata=elemNow
                    tblEdit.elemdata.x2=tblEdit.elemdata.x2-edgeDir*infoDel.width
                    af_request("editplank", tblEdit)
                  end
                end
              end
            end
          end
        end
      end

      res=true
    end
    ac_objectclose()
  end
  
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
    af_request("elem_createplanks")   -- Will process operations
  end

  return res
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      if g_mat.thickness~=0 then
        baseName=string.format("%s %s", baseName, g_mat.id)
      else
        baseName=string.format("%s %sx%s", baseName, ac_environment("ntos", g_thickness, "length", "work"), ac_environment("ntos", g_height, "length", "work"))
      end
    end
  end
  return baseName
end

-- FOR OPTION DLG
-------------------------


]]>
        </script>

        <!-- Double studs for opening sides -->
        <script id="openingdouble">
          <![CDATA[
-- Lua script, see ArchiFrame manual

-- For planks to be created
gnPlankCount=0
gtblCreate = {}


gOptGroupName="vertical_y_openingdouble"


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Asks for the material to use
-- sSettings may be nil, otherwise width=x
-- Returns single val: minumum width
function SettingsDlg(sSettings)
	local	tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    

	tblSettings={}

	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=3
	tblSettings[1].prompt	="Minimum width to add double stud"
	tblSettings[1].key		="width"
	tblSettings[1].defvalue	=0.600

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=2
	tblSettings[2].prompt	="Mark added pieces not to have nailings"
	tblSettings[2].key		="nails"
	tblSettings[2].defvalue	=0

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      tblSettings[1].value=g_width
      tblSettings[2].value=g_nonails
    else
      ac_environment( "tolog", string.format("AskMat/parse settings failed: %s", tostring(err)) )
    end
  end

	bRes,sErr=ac_optiondlg("LDDS", "Double stud settings", tblSettings)
	if not bRes then
    return
  end
  
  g_width=tblSettings[1].value
  g_nonails=tblSettings[2].value
  return true  
end


-- Scans edges table and returns table of edges for given holeIndex (1...N)
-- Returns: nil=no such opening, tbl=1-based table of edges
function GetOpening(holeIndex)
  local i,v
  local tblRes, nres
  
  nres=0
  tblRes={}
  for i,v in ipairs(gtblEdges) do
    -- Process only contour line
    if v.holeindex==holeIndex then
      nres=nres+1
      tblRes[nres]=v
    end
  end
  
  if nres==0 then
    return nil
  end

  return tblRes
end


-- Forget bottom joining for now
function DoJoinTopBotXml(plankNum)
  local s

  s=string.format("<jointo target=\"#%d\" operator=\"top*|2ndtop*|bottom*|2ndbottom*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.100\"></cut></jointo>", plankNum)
  return s
end


function DoDoubleStud( strMatId, nMatThickness, nMatHeight )
  local nOpening, tblOpening, edge, vEdge, tblEdit, dx, tblSides, nSides, i, v, elemdata
  local plank, strXmlOp
  local tblLimitOpenings


  gnPlankCount=0
  gtblCreate = {}
  tblLimitOpenings = nil   -- If non-nil, contains true value for every opening index to be handled, for example opening 1: [1]=true
  
  if gAdjustElems then
    -- From options tool palette, may limit openings with selection. Check if selected planks related to any openig
    local tblSel, guid, tblSelGuids

    tblSel=af_request("getselplanks")
    if tblSel then
    
      tblSelGuids={}
      for i,v in pairs(tblSel) do
        tblSelGuids[v]=true
      end

      nOpening=1
      while true do
        tblOpening=GetOpening(nOpening)
        if tblOpening==nil then
          break
        end
        
        for edge,vEdge in ipairs(tblOpening) do
          if vEdge.ptr then
            ac_objectopen(vEdge.ptr)
            guid=ac_objectget("#guid")
            ac_objectclose()
            if tblSelGuids[guid]~=nil then
              if tblLimitOpenings==nil then
                tblLimitOpenings={}
              end
          
              tblLimitOpenings[nOpening]=true
            end
          end
        end
        
        nOpening=nOpening+1
      end
    end
  end
  
  nOpening=1
  strXmlOp=""
  while true do
    tblOpening=GetOpening(nOpening)
    if tblOpening==nil then
      break
    end
    nOpening=nOpening+1

    if #tblOpening==4 and (tblLimitOpenings==nil or tblLimitOpenings[nOpening-1]) then 
      -- Find vertical pieces (openings are ccw as the main contour)
      local x1, x2
      nSides=0
      tblSides={}
      
      
      x1=1E100
      x2=-1E100
      for edge,vEdge in ipairs(tblOpening) do
        if vEdge.x1<x1 then
          x1=vEdge.x1
        end
        if vEdge.x2<x1 then
          x1=vEdge.x2
        end
        if vEdge.x1>x2 then
          x2=vEdge.x1
        end
        if vEdge.x2>x2 then
          x2=vEdge.x2
        end
      end

      if x2-x1+0.0001>g_width then
        for edge,vEdge in ipairs(tblOpening) do
          if math.abs(vEdge.x2-vEdge.x1)<0.001 then
            -- Vertical, inside element is at the right hand side
            if vEdge.ptr then
              dx=nMatThickness
              if vEdge.y1>vEdge.y2 then
                dx=-dx
              end
            
              nSides=nSides+1
              tblSides[nSides]={}
              tblSides[nSides].edge=vEdge
              tblSides[nSides].dx=dx

              ac_objectopen(vEdge.ptr)
              elemdata=ac_objectget("#af_elemdata")
              ac_objectclose()
          
              strXmlOp=strXmlOp .. DoJoinTopBotXml(gnPlanks+gnPlankCount+1)

              plank={}
              plank.guidsettings=vEdge.ptr
              plank.copyops=1
              plank.group=gOptGroupName
              plank.id=strMatId
              plank.thickness=nMatThickness
              plank.height=nMatHeight

              plank.x1=elemdata.x1+dx
              plank.y1=elemdata.y1
              plank.x2=plank.x1
              plank.y2=elemdata.y2
              plank.extendtoelem=1
              plank.xmlsettings=string.format("<s><objparam name=\"iNailOffsetBehind\">%d</objparam></s>", g_nonails)
              
              gnPlankCount=gnPlankCount+1
              gtblCreate[gnPlankCount]=plank
  --ac_environment("tolog", string.format("UUS, dx=%f, %s", dx, dump(gtblCreate[gnPlankCount])))
            end
          end
        end   -- for edge,vEdge
      end
    end

  end
  
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end
  
end


-------------------------
-- FOR OPTION DLG


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height
function ParseSettings(sSettings)
  local s, mat, val
  
  --ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )
  g_width=tonumber(GetVal(sSettings, "width"))
  
  g_nonails=0
  s=GetVal(sSettings, "nonails")
  if s then
    g_nonails=tonumber(s)
  end

  -- Will cause error if bad syntax
  s = string.format("width=%f\nnonails=%d", g_width, g_nonails)
end


-- Finds nice material
function GetDefaults()
  g_width=0.600
  g_nonails=0
  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("width=%f\nnonails=%d", g_width, g_nonails)
    end
  end
  
  if not SettingsDlg(sSettings) then
    return nil
  end

  return string.format("width=%f\nnonails=%d", g_width, g_nonails)
end


function Set(sSettings)
  local default, res, errStr, matid, tblMat, thickness, height
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end

  matid=af_request("elem_getstudmat")
  if matid==nil then
    return
  end

  tblMat=af_request("singlemat", matid)
  if tblMat==nil then
    return
  end

  thickness=tblMat.thickness
  height=tblMat.height

  DoDoubleStud( matid, thickness, height )
  
  af_request("elem_createplanks")
end


function Reset()
  local i, elemDel, infoDel, elemNow, infoNow, nOpening, tblOpening, vEdgeOpening, edgeDir, y, y1, y2, e, v, x, tblEdit

  gnPlankCount=0
  gtblCreate = {}

  res=false
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      elemDel=ac_objectget("#af_elemdata")
      infoDel=af_request("plankinfo")
      af_request("delplank")
      ac_objectclose()
      res=true
    end
    ac_objectclose()
  end
  
  return res
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      baseName=string.format("%s >=%s", baseName, ac_environment("ntos", g_width, "length", "work"))
    end
  end
  return baseName
end

-- FOR OPTION DLG
-------------------------


]]>
        </script>


        <!-- Double studs for opening sides -->
        <script id="cornerdouble">
          <![CDATA[
-- Lua script, see ArchiFrame manual

-- For planks to be created
gnPlankCount=0
gtblCreate = {}


gOptGroupName="vertical_y_cornerdouble"


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Forget bottom joining for now
function DoJoinTopBotXml(plankNum)
  local s

  s=     string.format("<jointo target=\"#%d\" operator=\"top*|2ndtop*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.1\" removepart=\"up\"></cut></jointo>", plankNum)
  s=s .. string.format("<jointo target=\"#%d\" operator=\"bottom*|2ndbottom*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.1\" removepart=\"down\"></cut></jointo>", plankNum)
  return s
end


function DoDoubleStud( strMatId, nMatThickness, nMatHeight )
  local vEdge, dx, tblSides, nSides, i, v, elemdata, x1, x2, ptr1, ptr2
  local plank, strXmlOp
  local tblLimitOpenings


  gnPlankCount=0
  gtblCreate = {}
  tblLimitOpenings = nil   -- If non-nil, contains true value for every opening index to be handled, for example opening 1: [1]=true
  
  x1=1E100
  x2=-x1
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    plank=af_request("plankinfo")
    elemdata=ac_objectget("#af_elemdata")
    if math.abs(elemdata.x2-elemdata.x1)<0.001 then
      if elemdata.x1<x1 then
        x1=elemdata.x1
        plank1=plank
        plank1.elemdata=elemdata
      end
      if elemdata.x1>x2 then
        x2=elemdata.x1
        plank2=plank
        plank2.elemdata=elemdata
      end
    end
    ac_objectclose()
  end

  strXmlOp=""
  if plank1 then
    strXmlOp=strXmlOp .. DoJoinTopBotXml(gnPlanks+gnPlankCount+1)

    plank={}
    plank.guidsettings=plank1.ptr
    plank.copyops=1
    plank.group=gOptGroupName
    --plank.id=strMatId
    --plank.thickness=nMatThickness
    --plank.height=nMatHeight

    plank.x1=plank1.elemdata.x1+plank1.width
    plank.y1=plank1.elemdata.y1
    plank.x2=plank.x1
    plank.y2=plank1.elemdata.y2
    plank.extendtoelem=1
    gnPlankCount=gnPlankCount+1
    gtblCreate[gnPlankCount]=plank
  end

  if plank2 then
    strXmlOp=strXmlOp .. DoJoinTopBotXml(gnPlanks+gnPlankCount+1)

    plank={}
    plank.guidsettings=plank2.ptr
    plank.copyops=1
    plank.group=gOptGroupName
    --plank.id=strMatId
    --plank.thickness=nMatThickness
    --plank.height=nMatHeight

    plank.x1=plank2.elemdata.x1-plank2.width
    plank.y1=plank2.elemdata.y1
    plank.x2=plank.x1
    plank.y2=plank2.elemdata.y2
    plank.extendtoelem=1
    gnPlankCount=gnPlankCount+1
    gtblCreate[gnPlankCount]=plank
  end

  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end
  
end


-------------------------
-- FOR OPTION DLG


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height
function ParseSettings(sSettings)
  local s, mat, val
  
  --ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )

  g_width=tonumber(GetVal(sSettings, "width"))

  -- Will cause error if bad syntax
  s = string.format("width=%f", g_width)
end


-- Finds nice material
function GetDefaults()
  g_width=0.600
  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


function Set(sSettings)
  local default, res, errStr, matid, tblMat, thickness, height
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end

  matid=af_request("elem_getstudmat")
  if matid==nil then
    return
  end

  tblMat=af_request("singlemat", matid)
  if tblMat==nil then
    return
  end

  thickness=tblMat.thickness
  height=tblMat.height

  DoDoubleStud( matid, thickness, height )
  
  af_request("elem_createplanks")
end


function Reset()
  local i, elemDel, infoDel, elemNow, infoNow, nOpening, tblOpening, vEdgeOpening, edgeDir, y, y1, y2, e, v, x, tblEdit

  gnPlankCount=0
  gtblCreate = {}

  res=false
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      elemDel=ac_objectget("#af_elemdata")
      infoDel=af_request("plankinfo")
      af_request("delplank")
      ac_objectclose()
      res=true
    end
    ac_objectclose()
  end
  
  return res
end


-- FOR OPTION DLG
-------------------------

]]>
        </script>


        <script id="reinforceall">
          <![CDATA[
g_matid=nil           -- Element material as default "23x98"
g_issingle=false      -- Set to true if actually option Bottom balk in/out, will affect processing following also
g_topin=1
g_topout=1
g_botin=1
g_botout=1

g_topinname="reinforce_small_topin"
g_topoutname="reinforce_small_topout"
g_botinname="reinforce_small_bottomin"
g_botoutname="reinforce_small_bottomout"


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local b
  
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    ac_objectclose()
    
    b=false
    if g_issingle then
      if g_botin==1 and s==g_botinname then
        b=true
      end
      if g_botout==1 and s==g_botoutname then
        b=true
      end
    else
      b=string.match(s, "^reinforce_small.*")
    end

    if b then
      return 1
    end
  end
  return 0
end


function Set(sSettings)
  local res, errStr

  gxmlOperations=nil
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end

  res=false
  if sSettings~=nil then
    res=pcall(ParseSettings, sSettings)
  end

  if not res then
    GetDefaults()
  end
  
  local targNames=""
  local strXml = ""

  if g_topin==1 then
    strXml = strXml .. DoReinforce(true, "top_force", "2ndtop_force", "contourtilted", g_matid, false, g_topinname)
    if targNames~="" then
      targNames = targNames .. "|"
    end
    targNames = targNames .. g_topinname
  end
  if g_topout==1 then
    strXml = strXml .. DoReinforce(true, "top_force", "2ndtop_force", "contourtilted", g_matid, true, g_topoutname)
    if targNames~="" then
      targNames = targNames .. "|"
    end
    targNames = targNames .. g_topoutname
  end
  if g_botin==1 then
    strXml = strXml .. DoReinforce(false, "bottom_force", "2ndbottom_force", nil, g_matid, false, g_botinname)
    if targNames~="" then
      targNames = targNames .. "|"
    end
    targNames = targNames .. g_botinname
  end
  if g_botout==1 then
    strXml = strXml .. DoReinforce(false, "bottom_force", "2ndbottom_force", nil, g_matid, true, g_botoutname)
    if targNames~="" then
      targNames = targNames .. "|"
    end
    targNames = targNames .. g_botoutname
  end
  
  -- Added 4/2023: Auto cut to lintels
  if targNames~="" then
    strXml = string.format(
        "%s\n" ..
        "<jointo target=\"%s\" operator=\"lintel*\">\n" ..
        "    <cut extendmaxlen=\"0.0\" expandopfind\"0.0\" endshape=\"anglednoext\"></cut>\n" ..
        "</jointo>",
        strXml, targNames
      )
  end

  if strXml~="" then
    gxmlOperations = "<operations>\n" .. strXml .. "\n</operations>"
  end

  af_request("elem_createplanks")
end


function Reset()
  local i, s

  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return false
  end
  
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if g_issingle then
      if g_botin==1 and s==g_botinname then
        af_request("delplank")
      end
      if g_botout==1 and s==g_botoutname then
        af_request("delplank")
      end
    else
      if string.match(s, "^reinforce_small.*") then
        af_request("delplank")
      end
    end
    ac_objectclose()
  end
  return 0
end


-------------------------
-- OPTIONS


-- Asks for the material to use
-- sSettings may be nil, otherwise mat=xxx\nthickness=x\nheight=x\ntopoff=x
function AskMat(sSettings)
  local  tblSettings, bRes, sErr, s, n, strSep, tblSorted
  local tblMat, i, id, v, thickness, height, mat
    
    
  tblMat=af_request("matlist")
  s=""
  strSep=""
    
  -- Skip general materials
  tblSorted={}
  i=1
  for id,v in pairs(tblMat) do
    if v.thickness>0.001 then
  		tblSorted[i]=v
	  	i=i+1
	  end
  end

	table.sort(tblSorted, function (n1, n2)
    return n1.index < n2.index
	end)

  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end
  
  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =1
  tblSettings[1].prompt  ="Material"
  tblSettings[1].key    ="balkmat"
  tblSettings[1].valuelist=s
  tblSettings[1].defvalue  =1

    tblSettings[2]      ={}
    tblSettings[2].cfgonly  =0
  tblSettings[2].type		=3
  tblSettings[2].prompt	="Distance from stud end"
  tblSettings[2].key		="distend"
  tblSettings[2].defvalue	=g_reinforceDist

    tblSettings[3]      ={}
    tblSettings[3].cfgonly  =0
  tblSettings[3].type		=3
  tblSettings[3].prompt	="Oversize towards stud end"
  tblSettings[3].key		="overout"
  tblSettings[3].defvalue	=g_reinforceOverEnd
  
    tblSettings[4]      ={}
    tblSettings[4].cfgonly  =0
  tblSettings[4].type		=3
  tblSettings[4].prompt	="Oversize towards stud in"
  tblSettings[4].key		="overin"
  tblSettings[4].defvalue	=g_reinforceOverIn

    tblSettings[5]      ={}
    tblSettings[5].cfgonly  =0
  tblSettings[5].type		=3
  tblSettings[5].prompt	="Oversize sides"
  tblSettings[5].key		="overside"
  tblSettings[5].defvalue	=g_reinforceOverSide

  if g_issingle==false then
    tblSettings[6]      ={}
    tblSettings[6].cfgonly  =0
    tblSettings[6].type    =2
    tblSettings[6].prompt  ="Top back"
    tblSettings[6].key    ="topin"
    tblSettings[6].defvalue  =1

    tblSettings[7]      ={}
    tblSettings[7].cfgonly  =0
    tblSettings[7].type    =2
    tblSettings[7].prompt  ="Top front"
    tblSettings[7].key    ="topout"
    tblSettings[7].defvalue  =1
  
    tblSettings[8]      ={}
    tblSettings[8].cfgonly  =0
    tblSettings[8].type    =2
    tblSettings[8].prompt  ="Bottom back"
    tblSettings[8].key    ="botin"
    tblSettings[8].defvalue  =1

    tblSettings[9]      ={}
    tblSettings[9].cfgonly  =0
    tblSettings[9].type    =2
    tblSettings[9].prompt  ="Bottom front"
    tblSettings[9].key    ="botout"
    tblSettings[9].defvalue  =1
  end

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if res then
      -- Had saved settings
      for i=1,#tblSorted do
        if tblSorted[i].id==g_matid then
          tblSettings[1].value=i
          break
        end
      end
      
      tblSettings[2].value=g_reinforceDist
      tblSettings[3].value=g_reinforceOverEnd
      tblSettings[4].value=g_reinforceOverIn
      tblSettings[5].value=g_reinforceOverSide
      
      if g_issingle==false then
        tblSettings[6].value=g_topin
        tblSettings[7].value=g_topout
        tblSettings[8].value=g_botin
        tblSettings[9].value=g_botout
      end
    else
      ac_environment( "tolog", string.format("AskMat/parse settings failed: %s", tostring(err)) )
    end
  end

  bRes,sErr=ac_optiondlg("LDRA", "Reinforce ALL", tblSettings)
  if not bRes then
    return
  end
    
  -- New settings as globals
  g_reinforceDist=tblSettings[2].value
  g_reinforceOverEnd=tblSettings[3].value
  g_reinforceOverIn=tblSettings[4].value
  g_reinforceOverSide=tblSettings[5].value

  mat=tblSorted[tblSettings[1].value]
  if g_issingle==false then
    return mat.id, tblSettings[6].value, tblSettings[7].value, tblSettings[8].value, tblSettings[9].value
  end

  return mat.id   -- Just single value if bottom balk in/out
end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height and g_reinforceXxx
function ParseSettings(sSettings)
  local s, mat, val
  
  g_matid=GetVal(sSettings, "mat")
  if g_matid==nil then
    g_matid=""
  end
  if g_issingle==false then
    g_topin=tonumber(GetVal(sSettings, "topin"))
    g_topout=tonumber(GetVal(sSettings, "topout"))
    g_botin=tonumber(GetVal(sSettings, "botin"))
    g_botout=tonumber(GetVal(sSettings, "botout"))
  end

  -- These are new values - allow nil values
  val=GetVal(sSettings, "dist")
  if val then
    g_reinforceDist=tonumber(val)
  end

  val=GetVal(sSettings, "overend")
  if val then
    g_reinforceOverEnd=tonumber(val)
  end

  val=GetVal(sSettings, "overin")
  if val then
    g_reinforceOverIn=tonumber(val)
  end

  val=GetVal(sSettings, "overside")
  if val then
    g_reinforceOverSide=tonumber(val)
  end

  -- Will cause error if bad syntax
  s=string.format("mat=%s\ntopin=%d\ntopout=%d\nbotin=%d\nbotout=%d\ndist=%.6f\noverend=%.6f\noverin=%.6f\noverside=%.6f", g_matid, g_topin, g_topout, g_botin, g_botout, g_reinforceDist, g_reinforceOverEnd, g_reinforceOverIn, g_reinforceOverSide)
end


-- Finds nice material
function GetDefaults()
  g_matid=af_request("elem_getstudmat")
  if g_matid==nil then
    g_matid=""
  end
  if g_issingle==false then
    g_topin=1
    g_topout=1
    g_botin=1
    g_botout=1
  end

  g_reinforceOverEnd=0.010
  g_reinforceOverIn=0.002
  g_reinforceOverSide=0.001
  g_reinforceDist=0

  return true
end



-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    if GetDefaults() then
      sSettings=string.format("mat=%s\ntopin=%d\ntopout=%d\nbotin=%d\nbotout=%d\ndist=%.6f\noverend=%.6f\noverin=%.6f\noverside=%.6f", g_matid, g_topin, g_topout, g_botin, g_botout, g_reinforceDist, g_reinforceOverEnd, g_reinforceOverIn, g_reinforceOverSide)
    end
  end
  -- Ask material
  local mat, thickness, height, topOff, numPlanks
  if g_issingle==false then
    g_matid, g_topin, g_topout, g_botin, g_botout= AskMat(sSettings)
  else
    g_matid= AskMat(sSettings)
  end

  if g_matid==nil then
    return nil
  end

  s=string.format("mat=%s\ntopin=%d\ntopout=%d\nbotin=%d\nbotout=%d\ndist=%.6f\noverend=%.6f\noverin=%.6f\noverside=%.6f", g_matid, g_topin, g_topout, g_botin, g_botout, g_reinforceDist, g_reinforceOverEnd, g_reinforceOverIn, g_reinforceOverSide)
  return s
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res=pcall(ParseSettings, sSettings)
    if res then
      baseName=string.format("%s %s", baseName, g_matid)
      if g_issingle==false then
        if g_topin==1 then
          baseName=string.format("%s topin", baseName)
        end
        if g_topout==1 then
          baseName=string.format("%s topout", baseName)
        end
        if g_botin==1 then
          baseName=string.format("%s botin", baseName)
        end
        if g_botout==1 then
          baseName=string.format("%s botout", baseName)
        end
      end
    end
  end
  return baseName
end

]]>
        </script>
        

        <!-- Window lengthwise cut -->
        <script id="openingsbotcut">
          <![CDATA[
g_height=0.018
g_depth=0.038
g_win=1
g_door=1
g_topbot=1			-- 1=top, 3=bottom

function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Asks for the material to use
-- sSettings may be nil
-- Sets globals to given values
function SettingsDlg(sSettings)
	local	tblSettings, bRes, sErr, s, n
  local tblMat, i, id, v, thickness, height, mat
    
  tblSettings={}
	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=3
	tblSettings[1].prompt	="Height of the cut"
	tblSettings[1].key		="cutheight"
	tblSettings[1].defvalue	=0.025

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=3
	tblSettings[2].prompt	="Depth of the cut"
	tblSettings[2].key		="cutdepth"
	tblSettings[2].defvalue	=0.040

  tblSettings[3]			={}
  tblSettings[3].cfgonly	=0
  tblSettings[3].type		=2
  tblSettings[3].prompt	="Cut window bottom"
  tblSettings[3].key		="dowin"
  tblSettings[3].defvalue	=1

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=2
  tblSettings[4].prompt	="Cut door bottom"
  tblSettings[4].key		="dodoor"
  tblSettings[4].defvalue	=1
  
	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	="Target surface"
	tblSettings[5].key		="side"
	tblSettings[5].valuelist="\"1:Top\",\"3:Bottom\""
	tblSettings[5].defvalue	=3
  

  if sSettings~=nil and sSettings~="" then
    local res, err
    res,err=pcall(ParseSettings, sSettings)
    if not res then
      ac_environment( "tolog", string.format("SettingsDlg/parse settings failed: %s", tostring(err)) )
    end
  end

  -- Anyway put defaults if not settings
  tblSettings[1].value=g_height
  tblSettings[2].value=g_depth
  tblSettings[3].value=g_win
  tblSettings[4].value=g_door
  tblSettings[5].value=g_topbot

	bRes,sErr=ac_optiondlg("LDWC", "Angled cuts for doors and windows", tblSettings)
	if not bRes then
    return false
  end

  g_height=tblSettings[1].value
  g_depth=tblSettings[2].value
  g_win=tblSettings[3].value
  g_door=tblSettings[4].value
  g_topbot=tblSettings[5].value
  return true
end


-- Returns 1-based table having all items with fields:
-- ptr
-- openingtype 13 or 23 or for empty openings 113 or 123
function FindDoorWinBottoms()
	local	kPoly, vPoly, tblPoly, tblSettings, tblRes, nRes, nBegContour, v
	local x1, y1, x2, y2
  local isBot, tblVert, nVert, elemGroup
  local vert
	
	
	tblSettings={}
	tblSettings.calcopening=1
	tblPoly=af_request("getpoly", tblSettings, gGuidElem)

	tblRes={}
	nRes=0

  tblVert={}
  nVert=0
  
	nBegContour=1
	for kPoly, vPoly in ipairs(tblPoly.poly) do
		if vPoly.isbeghole then
			nBegContour=kPoly
		end
			
    -- Calc line here
			if vPoly.isendcontour then
				v=tblPoly.poly[nBegContour]
			else
				v=tblPoly.poly[kPoly+1]
			end
			x1=vPoly.x
			y1=vPoly.y
			x2=v.x
			y2=v.y

    isBot=(vPoly.openingtype==13 or vPoly.openingtype==113 or vPoly.openingtype==23 or vPoly.openingtype==123)
		if isBot or math.abs(y2-y1)<0.001 then
			-- Is door & win, find all related planks (also all vertical ones if not linked to any AC openings/copied element)
			-- Scan planks
			local i, elemData, plankInfo, dist, off, dist2, off2, lineLen
			
			for i=1,gnPlanks do
				
				ac_objectopen(string.format("#%d", i))
				elemData=ac_objectget("#af_elemdata")
        elemGroup=ac_objectget("iElemGroup")
				plankInfo=af_request("plankinfo")
				ac_objectclose()
				
				dist,off,lineLen=ac_geo("linedist", x1, y1, x2, y2, elemData.x1, elemData.y1)
				dist2,off2,lineLen=ac_geo("linedist", x1, y1, x2, y2, elemData.x2, elemData.y2)
				
				if math.abs(dist-dist2)<0.001 and off>-0.010 and off<lineLen+0.010 and off2>-0.010 and off2<lineLen+0.010 then
					-- Parallel and is inside the polygon edge, say max 30 mm from window line
					if math.abs(dist)-plankInfo.width*0.5<0.030 then
            if isBot then
						-- Found!
						nRes=nRes+1
						tblRes[nRes]={}
						tblRes[nRes].ptr=plankInfo.ptr
						tblRes[nRes].openingtype=vPoly.openingtype
            elseif string.match(elemGroup, "^vertical_x.*") then
              vert={}
              vert.x1=x1
              vert.x2=x2
              vert.y1=y1
              vert.y2=y2
              vert.ptr=plankInfo.ptr
              nVert=nVert+1
              tblVert[nVert]=vert
					end
				end
			end
		end
	end
	end
  
  if nRes==0 then
    -- Perhaps copied element and no links to original AC-openings. Check collected vertical planks and take only the lowest pieces
    local i1, i2, vert2
    
    for i1=1,nVert do
      vert=tblVert[i1]
      if vert.x2<vert.x1 then
        vert.x2,vert.y2,vert.x1,vert.y1=vert.x1,vert.y1,vert.x2,vert.y2
      end
      i2=i1+1
      while i2<=nVert do
        vert2=tblVert[i2]
        if vert2.x2<vert2.x1 then
          vert2.x2,vert2.y2,vert2.x1,vert2.y1=vert2.x1,vert2.y1,vert2.x2,vert2.y2
        end
        if math.abs(vert2.x1-vert.x1)<0.001 and math.abs(vert2.x2-vert.x2)<0.001 and vert2.y1<vert.y1 then
          break
        end
        i2=i2+1
      end
      if i2>nVert then
        nRes=nRes+1
				tblRes[nRes]={}
				tblRes[nRes].ptr=vert.ptr
				tblRes[nRes].openingtype=13   -- Say window bottom
      end
    end
  end
  
  return tblRes
end


-- Deletes all lengthwise cuts from opened plank
-- Returns: true=found, false=not found
function EditCutSingle(bDel, bAdd, openingtype)
  local i, count, mc, col, res, addIndex
  
  res=false
  count=ac_objectget("iMc",-1)
  addIndex=nil
  for i=1,count do
    mc=ac_objectget("iMc", i, 1)
	  if mc==305 then
		  res=true
		  if not addIndex then
			  addIndex=i
		  end
		  if bDel then
			  for col=1,16 do
				  ac_objectset("iMc", 0, i, col)
			  end
		  end
	  end
  end
  
  if bAdd and ((g_win==1 and (openingtype==13 or openingtype==113)) or (g_door==1 and (openingtype==23 or openingtype==123))) then
	  -- Add new one
	  local plankInfo, a
	
	  plankInfo=af_request("plankinfo")
	  if not addIndex then
		  addIndex=count
	  end

	  for col=1,16 do
		  ac_objectset("iMc", 0, addIndex, col)
	  end
	
	  -- double		dType;
	  -- double		dSideOneBased;	// 2
	  -- double		xStart;			// 3
	  -- double		dWidth;			// 4, 0=from xStart to the end
	  -- double		dDepthTop;		// 5, A from surface, neg=outside the plank
	  -- double		dYoffTop;		// 6, B from middle of the surface
	  -- double		dAngleY2Deg;	// 7, C angle at surface y2
	  -- double		dAngleY1Deg;	// 8, D angle at surface y1
	  -- double		dSideType;		// 9, 0=Just sawing, 1=use cutter for the sides
	
    a=57.295779513*math.atan2(g_height, g_depth)     -- 180/PI
	  ac_objectset("iMc", 305, addIndex, 1)
	  ac_objectset("iMc", 2, addIndex, 2)		-- Front surface
	  if g_topbot==1 then
		  ac_objectset("iMc", plankInfo.height*0.5-g_depth, addIndex, 6)
      ac_objectset("iMc", a, addIndex, 7)
	  else
		  ac_objectset("iMc", -plankInfo.height*0.5+g_depth, addIndex, 6)
      ac_objectset("iMc", a, addIndex, 8)
	  end
  end
  return res
end


-- Deletes all cuts from given planks
function EditCuts(tblRes, bDel, bAdd)
  local k,v,res
  
  res=false
  for k,v in ipairs(tblRes) do
	  ac_objectopen(v.ptr)
	  if EditCutSingle(bDel, bAdd, v.openingtype) then
		  res=true
	  end
	  ac_objectclose()
  end
  return res
end


-- Adds cuts
function DoCuts()
	local	tblRes
	
	-- Find all and remove
	tblRes=FindDoorWinBottoms()
	EditCuts(tblRes, true, true)
end


-------------------------
-- FOR OPTION DLG


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

	for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
		if k == keyName then
			return v
		end
	end
  return nil
end


-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  local s
  
--ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )
  g_height=tonumber(GetVal(sSettings, "height"))
  g_depth=tonumber(GetVal(sSettings, "depth"))
  g_win=tonumber(GetVal(sSettings, "win"))
  g_door=tonumber(GetVal(sSettings, "door"))
  g_topbot=tonumber(GetVal(sSettings, "side"))
  
  -- Will cause error if bad syntax
  s=string.format("height=%f\ndepth=%f\nwin=%d\ndoor=%d\nside=%d\n", g_height, g_depth, g_win, g_door, g_topbot)
end


-- Finds nice material
function GetDefaults()
	g_height=0.018
	g_depth=0.038
	g_win=1
	g_door=1
	g_topbot=1
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
	local tblRes

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
	tblRes=FindDoorWinBottoms()
	if EditCuts(tblRes, false, false) then
		return 1
	else
		return 0
	end
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if sSettings==nil or sSettings=="" then
    GetDefaults()
  end
  -- Ask material
  
  if not SettingsDlg(sSettings) then
    return nil
  end

  s=string.format("height=%f\ndepth=%f\nwin=%d\ndoor=%d\nside=%d\n", g_height, g_depth, g_win, g_door, g_topbot)
  return s
end


function Set(sSettings)
  local default, res, errStr, zoff, tblLastAdded, i, v, s, overL, overR, thickness
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end
  
  
  DoCuts()
end


function Reset()
	local	tblRes

	-- Find all and remove
	tblRes=FindDoorWinBottoms()
	EditCuts(tblRes, true, false)
	return true
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      if g_mat.thickness~=0 then
        baseName=string.format("%s %s", baseName, g_mat.id)
      else
        baseName=string.format("%s %sx%s", baseName, ac_environment("ntos", g_height, "length", "work"), ac_environment("ntos", g_depth, "length", "work"))
      end
    end
  end
  return baseName
end

-- FOR OPTION DLG
-------------------------


]]>
        </script>

        <script id="openingsupport">
          <![CDATA[
-- For planks to be created
gnPlankCount=0
gtblCreate = {}


gOptGroupName="vertical_y_openingsupport"


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


-- Finds nice material
function GetDefaults()
  local mat
  
  mat=af_request("elem_getstudmat")
  if mat==nil then
    return false
  end

  g_mat=af_request("singlemat", mat)
  return true
end


-- Scans edges table and returns table of edges for given holeIndex (1...N)
-- Returns: nil=no such opening, tbl=1-based table of edges
function GetOpening(holeIndex)
  local i,v
  local tblRes, nres
  
  nres=0
  tblRes={}
  for i,v in ipairs(gtblEdges) do
    -- Process only contour line
    if v.holeindex==holeIndex then
      nres=nres+1
      tblRes[nres]=v
    end
  end
  
  if nres==0 then
    return nil
  end

  return tblRes
end


function DoOpeningSupport( strMatId, nMatThickness, nMatHeight )
  local nOpening, tblOpening, edge, vEdge, dx, i, v
  local plank, strXmlOp
  local tblLimitOpenings


  gnPlankCount=0
  gtblCreate = {}
  tblLimitOpenings = nil   -- If non-nil, contains true value for every opening index to be handled, for example opening 1: [1]=true
  
  if gAdjustElems then
    -- From options tool palette, may limit openings with selection. Check if selected planks related to any openig
    local tblSel, guid, tblSelGuids

    tblSel=af_request("getselplanks")
    if tblSel then
    
      tblSelGuids={}
      for i,v in pairs(tblSel) do
        tblSelGuids[v]=true
      end

      nOpening=1
      while true do
        tblOpening=GetOpening(nOpening)
        if tblOpening==nil then
          break
        end
        
        for edge,vEdge in ipairs(tblOpening) do
          if vEdge.ptr then
            ac_objectopen(vEdge.ptr)
            guid=ac_objectget("#guid")
            ac_objectclose()
            if tblSelGuids[guid]~=nil then
              if tblLimitOpenings==nil then
                tblLimitOpenings={}
              end

              tblLimitOpenings[nOpening]=true
            end
          end
        end
        
        nOpening=nOpening+1
      end
    end
  end

  nOpening=1
  strXmlOp=""
  while true do
    tblOpening=GetOpening(nOpening)
    if tblOpening==nil then
      break
    end
    nOpening=nOpening+1

    if #tblOpening==4 and (tblLimitOpenings==nil or tblLimitOpenings[nOpening-1]) then 
      -- Find vertical pieces (openings are ccw as the main contour)
      for edge,vEdge in ipairs(tblOpening) do
        if math.abs(vEdge.x2-vEdge.x1)<0.001 and vEdge.ptr~=nil then
          -- Could use strMatId, nMatThickness, nMatHeight
          local elemdata, plankinfo, s, prevEdge, nextEdge, miny, maxy

          miny=vEdge.y1
          maxy=vEdge.y2
          dx=-1
          if vEdge.y1>vEdge.y2 then
            dx=1
            miny,maxy=maxy,miny
          end
          
          if edge>1 then
            prevEdge=tblOpening[edge-1]
          else
            prevEdge=tblOpening[#tblOpening]
          end

          if edge<#tblOpening then
            nextEdge=tblOpening[edge+1]
          else
            nextEdge=tblOpening[1]
          end

          ac_objectopen(vEdge.ptr)
          elemdata=ac_objectget("#af_elemdata")
          plankinfo=af_request("plankinfo")
          ac_objectclose()

          -- Above opening (this condition already should skip lintel cases)
          if elemdata.y2>maxy+0.001 then
            plank={}
            plank.guidsettings=vEdge.ptr
            plank.copyops=1
            plank.group=gOptGroupName
            plank.id=strMatId
            plank.thickness=nMatThickness
            plank.height=nMatHeight

            plank.x1=elemdata.x1+dx*plankinfo.width
            if vEdge.y1<vEdge.y2 then
              plank.y1=nextEdge.y1
            else
              plank.y1=prevEdge.y1
            end

            plank.x2=plank.x1
            plank.y2=elemdata.y2
            
            -- Create only if no intersection with a lintel type piece
            local hasx, scan
            
            hasx=false
            for scan=1,gnPlanks do
              ac_objectopen(string.format("#%d",scan))
              s=ac_objectget("iElemGroup")
              ac_objectclose()
              
              if s=="lintel" then
                local infolintel, x, y
                
                ac_objectopen(string.format("#%d",scan))
                infolintel=ac_objectget("#af_elemdata")
                ac_objectclose()

                x,y=ac_geo("linex", plank.x1, plank.y1, plank.x2, plank.x2, infolintel.x1, infolintel.y1, infolintel.x2, infolintel.y2)
                if x~=nil then
                  -- Check if inside the lines
                  if y>plank.y1 and y<plank.y2 and x>infolintel.x1 and x<infolintel.x2 then
                    hasx=true
                    break
                  end
                end
              end
            end
            
            if not hasx then
              gnPlankCount=gnPlankCount+1
              gtblCreate[gnPlankCount]=plank
          
              s=string.format("<jointo target=\"#%d\" operator=\"vertical_x*|top*|2ndtop*|contourtilted\" operatorskip=\"topbalk*\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.100\"></cut></jointo>", gnPlanks+gnPlankCount)
              strXmlOp=strXmlOp .. s
            end
          end

          -- Below opening
          if elemdata.y1<miny-0.001 then
            plank={}
            plank.guidsettings=vEdge.ptr
            plank.copyops=1
            plank.group=gOptGroupName
            plank.id=strMatId
            plank.thickness=nMatThickness
            plank.height=nMatHeight

            plank.x1=elemdata.x1+dx*plankinfo.width
            plank.y1=elemdata.y1
            plank.x2=plank.x1
            if vEdge.y1<vEdge.y2 then
              plank.y1=prevEdge.y2
            else
              plank.y1=nextEdge.y2
            end

            gnPlankCount=gnPlankCount+1
            gtblCreate[gnPlankCount]=plank
          
            s=string.format("<jointo target=\"#%d\" operator=\"vertical_x*|bottom*|2ndbottom*\" operatorskip=\"bottombalk*,balkbottom*\" ><cut jointgap=\"0.000\" endshape=\"angleddelfirst\" extendmaxlen=\"0.100\"></cut></jointo>", gnPlanks+gnPlankCount)
            strXmlOp=strXmlOp .. s
          end

        end
      end   -- for edge,vEdge
    end
  end
  
  if strXmlOp~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", strXmlOp)
  end

end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  local i

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      ac_objectclose()
      return 1
    end
    ac_objectclose()
  end
  return 0
end


function Set(sSettings)
  local default, res, errStr, zoff, tblLastAdded, i, v, s, overL, overR, thickness
  
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  GetDefaults()

  if g_mat.thickness>0 then
    g_thickness=g_mat.thickness
  end

  if g_mat.height>0 then
    g_height=g_mat.height
  end

  DoOpeningSupport( g_mat.id, g_thickness, g_height )
  
  af_request("elem_createplanks")
end


function Reset()
  local i, elemDel, infoDel, elemNow, infoNow, nOpening, tblOpening, vEdgeOpening, edgeDir, y, y1, y2, e, v, x
  local strXmlOp

  gnPlankCount=0
  gtblCreate = {}

  res=false
  strXmlOp=""
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^" .. gOptGroupName .. ".*") then
      elemDel=ac_objectget("#af_elemdata")
      infoDel=af_request("plankinfo")
      af_request("delplank")
      res=true
    end
    ac_objectclose()
  end

  return res
end
]]>
        </script>

        
        <script id="noggings">
          <![CDATA[
g_matid=nil             -- Material ID
g_thickness=nil         -- Only if block (matid thickness is 0)
g_height=nil
g_rotdeg=nil            -- In degrees
g_front=nil             -- To front or back side (0/1)
g_stagger=nil           -- Value >= 0
g_spacing=nil           -- Distance from bottom to center of the nogging (and then to next)
g_single=nil            -- Is it a single nogging (prev is distance from bottom) (0/1)
g_noggingsGap=nil


function GetDefaults()
    g_matid=af_request("elem_getstudmat")
    if g_matid==nil then
    g_matid="block"
    end
    g_thickness=0.050
    g_height=0.100
    g_rotdeg=0
    g_front=1
    g_stagger=0.0
    g_spacing=1.250
    g_single=1
    g_noggingsGap=0
end


-- Gives min&max distances of elemdata-plank in noggins direction
function FindMinMax(minx, miny, nogx, nogy, elemdata)
    local distmin,distmax, k, v, d, dummy
    
    distmin=1E10
    distmax=-1E10
    for k,v in ipairs(elemdata.poly) do
        dummy,d=ac_geo("linedist", minx, miny, minx+nogx, miny+nogy, v.x, v.y)
        if d<distmin then
            distmin=d
        end
        if d>distmax then
            distmax=d
        end
    end
    return distmin,distmax
end

function LinePolyX1(x1, y1, x2, y2, poly1)
  local t
  
  t={}
  t[1]=poly1
  return ac_geo("linepolyx", x1, y1, x2, y2, t)
end

-- studx, study Direction vector of the studs, noggings in 90 degree angle
function DoNoggings(studx, study)
  local tblPoly, t, minx, miny, currdist, maxdist, tblStuds, nstuds, i, dx, dy, planklen, nogx, nogy, infoElem, currThickness, currHeight, currMat
  local settingsGuid, settingsVert, info, staggerMul
  
  -- Get nogging material's size
  currThickness=g_thickness
  currHeight=g_height
  currMat=af_request("singlemat", g_matid)
  if currMat and currMat.thickness>0 then
      currThickness=currMat.thickness
      currHeight=currMat.height
  end
  
  -- Owner element's polygon
  t={}
  t.calcopening=1
  t.givelist=1
  tblPoly=af_request("getpoly", t, gGuidElem)
  infoElem=af_request("plankinfo", gGuidElem)

  -- First find the min stud pos
  if studx==0 and study==1 then
    minx=tblPoly.x1
    miny=tblPoly.y1
    maxdist=tblPoly.y2
    nogx=1              -- Noggins direction vector
    nogy=0
  else
    error("Unsupported noggings dir")
  end
  
  -- Find studs
  tblStuds={}           -- data=#af_elemdata table. Also fields distmin, distmax which are distances from starting point of the noggings
  nstuds=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    t=ac_objectget("#af_elemdata")
    info=af_request("plankinfo")
    ac_objectclose()
    
    dx=t.x2-t.x1
    dy=t.y2-t.y1
    planklen=math.sqrt(dx*dx+dy*dy)
    if planklen>0.001 then
        dx=dx/planklen
        dy=dy/planklen
        if math.abs(dx*studx + dy*study)>0.99 then
          t.distmin,t.distmax=FindMinMax(minx, miny, nogx, nogy, t)
          nstuds=nstuds+1
          tblStuds[nstuds]=t
          if not settingsGuid then
            settingsGuid=info.ptr
          end
        elseif not settingsGuid or not settingsVert then
          settingsVert=true
          settingsGuid=info.ptr
        end
    end
  end
  
  table.sort( tblStuds,  function(p1, p2)
                            return p1.distmin<p2.distmin
                          end )
  
  -- Place noggings
  currdist=0
  repeat
    local   tblLines, x1, y1, x2, y2, kline, vline, i1, i2, dummy, d

    currdist=currdist+g_spacing
    x1=minx+currdist*studx-100*nogx         -- 100 meters to left
    y1=miny+currdist*study-100*nogy
    x2=x1+200*nogx                          -- 200 meters to right
    y2=y1+200*nogy

    staggerMul=0
    tblLines=ac_geo("linepolyx", x1, y1, x2, y2, tblPoly.poly)       -- Get left & right & trim openings away
    if tblLines==nil then
      tblLines={}
    end

    for kline,vline in ipairs(tblLines) do
        i1=1
        while i1<nstuds do
          -- Nogging always between studs - find first one
          while i1<=nstuds do
              if LinePolyX1(vline.x1, vline.y1, vline.x2, vline.y2, tblStuds[i1].poly) then       -- Takes also vertical position into account
                  break
              end
              i1=i1+1
          end
        
          if i1<nstuds then
              -- Found first one intersecting, advance to next nogging direction coordinate and another intersecting stud
              local found=false

              i2=i1+1
              while i2<=nstuds do
                  -- If we went past the line, will go to nstuds
                  if tblStuds[i1].distmax<tblStuds[i2].distmin and LinePolyX1(vline.x1, vline.y1, vline.x2, vline.y2, tblStuds[i2].poly) then
                      found=true
                      break
                  end
                  i2=i2+1
              end
              if not found then
                  break
              end
            
              dx=tblStuds[i2].distmin-tblStuds[i1].distmax
              if dx>0.010 then
                  t={}
                  t.guidsettings=settingsGuid
                  t.group="nogging"
                  t.id=g_matid
                  if not currMat or currMat.thickness==0 then
                    t.thickness=g_thickness
                    t.height=g_height
                  end
                
                  -- Calc offset from the surface
                  local zheight=currHeight
                  
                  t.zoff=0
                  if math.abs(math.abs(g_rotdeg)-90)<0.1 or math.abs(math.abs(g_rotdeg)-270)<0.1 then
                      zheight=0
                      t.zoff=currThickness*0.5
                  end
                
                  if g_front==0 then
                      t.zoff=infoElem.width-zheight-t.zoff
                  end
                  t.rotangle=g_rotdeg

                  dx=nogy*g_stagger*staggerMul      -- To right
                  dy=-nogx*g_stagger*staggerMul
                  staggerMul=1-staggerMul

                  t.x1=minx + currdist*studx + tblStuds[i1].distmax*nogx+dx
                  t.y1=miny + currdist*study + tblStuds[i1].distmax*nogy+dy
                  t.x2=minx + currdist*studx + tblStuds[i2].distmin*nogx+dx
                  t.y2=miny + currdist*study + tblStuds[i2].distmin*nogy+dy
                  
                  local createPlank
                  
                  createPlank=true
                  if g_noggingsGap~=0 then
                    -- Gap between the nogging and the stud
                    local dx, dy, len
                    
                    dx=t.x2-t.x1
                    dy=t.y2-t.y1
                    len=math.sqrt(dx*dx+dy*dy)
                    if len>0.001 then
                      if len<2*g_noggingsGap+0.001 then
                        createPlank=false
                      else
                        dx=dx/len
                        dy=dy/len
                        t.x1=t.x1+g_noggingsGap*dx
                        t.y1=t.y1+g_noggingsGap*dy
                        t.x2=t.x2-g_noggingsGap*dx
                        t.y2=t.y2-g_noggingsGap*dy
                      end
                    end
                  end
                  
                  t.lineside=0        -- Center
                  
                  s="<root>\n"
                  s=s.."<objparam name=\"iElemModule\"></objparam>\n"
                  s=s.."</root>\n"
                  t.xmlsettings=s

                  s="<root><newelemprojside>\n"
                  s=s.."<objparam name=\"iIDPlace\">0</objparam>\n"
                  s=s.."<objparam name=\"iXoffID\">0</objparam>\n"
                  s=s.."</newelemprojside></root>\n"
                  t.xmlsettingsproj=s

--  ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f", t.x1, t.y1, t.x2, t.y2))
                
                  if createPlank then
                    gnPlankCount=gnPlankCount+1
                    gtblCreate[gnPlankCount]=t
                  end
              end
              i1=i2
          end
      end
    end

  until currdist>maxdist or g_single==1
end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


function SettingsToStr()
  return string.format("matid=%s\nthickness=%.8f\nheight=%.8f\nrot=%d\nfront=%d\nstagger=%.8f\nspacing=%.8f\nsingle=%d\nnoggap=%f\n", g_matid, g_thickness, g_height, g_rotdeg, g_front, g_stagger, g_spacing, g_single, g_noggingsGap)
end

-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  local s
  
--ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )
  g_matid=GetVal(sSettings, "matid")
  g_thickness=tonumber(GetVal(sSettings, "thickness"))
  g_height=tonumber(GetVal(sSettings, "height"))
  g_rotdeg=tonumber(GetVal(sSettings, "rot"))
  g_front=tonumber(GetVal(sSettings, "front"))
  g_stagger=tonumber(GetVal(sSettings, "stagger"))
  g_spacing=tonumber(GetVal(sSettings, "spacing"))
  g_single=tonumber(GetVal(sSettings, "single"))
  
  s=GetVal(sSettings, "noggap")
  if s then
    g_noggingsGap=tonumber(s)
  end
  
  -- Will cause error if bad syntax
  SettingsToStr()
end


-- sSettings may be nil
-- Sets globals to given values
function SettingsDlg(sSettings)
  local tblSettings, bRes, sErr, s, n, strSep, tblSorted, defMatId
  local tblMat, i, id, v, thickness, height, mat, hasSettings

  hasSettings=false
  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    local err

    hasSettings,err=pcall(ParseSettings, sSettings)
    if not hasSettings then
      GetDefaults()
    end
  end

  -- Build mat list
  tblMat=af_request("matlist")
  
  defMatId=af_request("elem_getstudmat")
  if defMatId==nil then
    defMatId=""
  end
  defMat=1
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
    if v.id==defMatId then
      defMat=v.index
    end
  end
 
  s=""
  strSep=""
  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end
    
  tblSettings={}
  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =1
  tblSettings[1].prompt  ="Material"
  tblSettings[1].key    ="balkmat"
  tblSettings[1].valuelist=s
  tblSettings[1].value  =defMat

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type    =3
  tblSettings[2].prompt  ="Thickness if not fixed"
  tblSettings[2].key    ="thickness"
  tblSettings[2].defvalue  =g_thickness

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  ="Height if not fixed"
  tblSettings[3].key    ="height"
  tblSettings[3].defvalue  =g_height

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type    =4
  tblSettings[4].prompt  ="Rotate nogging 0/90 degrees"
  tblSettings[4].key    ="rot"
  tblSettings[4].defvalue  =g_rotdeg

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type    =2
  tblSettings[5].prompt  ="Noggings to front side (or back)"
  tblSettings[5].key    ="front"
  tblSettings[5].defvalue  =g_front

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type    =3
  tblSettings[6].prompt  ="Staggering value, 0=no"
  tblSettings[6].key    ="stagger"
  tblSettings[6].defvalue  =g_stagger

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type    =3
  tblSettings[7].prompt  ="Spacing or distance from bottom"
  tblSettings[7].key    ="spacing"
  tblSettings[7].defvalue  =g_spacing

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type    =2
  tblSettings[8].prompt  ="Just single nogging line"
  tblSettings[8].key    ="single"
  tblSettings[8].defvalue  =g_single
  
  tblSettings[9]      ={}
  tblSettings[9].cfgonly  =0
  tblSettings[9].type    =3
  tblSettings[9].prompt  ="Noggings gap"
  tblSettings[9].key    ="nogging_gap"
  tblSettings[9].defvalue  =0

  -- Show current settings always (also from defaults)
  for i=1,#tblSorted do
    if tblSorted[i].id==g_matid then
      tblSettings[1].value=i
      break
    end
  end

  tblSettings[2].value    =g_thickness
  tblSettings[3].value    =g_height
  tblSettings[4].value    =g_rotdeg
  tblSettings[5].value    =g_front
  tblSettings[6].value    =g_stagger
  tblSettings[7].value    =g_spacing
  tblSettings[8].value    =g_single
  tblSettings[9].value    =g_noggingsGap
 
  bRes,sErr=ac_optiondlg("LDNO", "Noggings", tblSettings)
  if not bRes then
    return false
  end

  g_matid=tblSorted[tblSettings[1].value].id
  g_thickness=tblSettings[2].value
  g_height=tblSettings[3].value
  g_rotdeg=tblSettings[4].value
  g_front=tblSettings[5].value
  g_stagger=tblSettings[6].value
  g_spacing=tblSettings[7].value
  g_single=tblSettings[8].value
  g_noggingsGap=tblSettings[9].value

  return true
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  if gnPlanks==0 then
    return -1
  end

  local res,i,s

  res=0
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^nogging.*") then
      res=1
    end
    ac_objectclose()
    if res==1 then
      break
    end
  end
  return res
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if not SettingsDlg(sSettings) then
    return nil
  end

  return SettingsToStr()
end


function Set(sSettings)
  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end

  GetDefaults()
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end

  DoNoggings(0, 1)
  af_request("elem_createplanks")
end


function Reset()
  local res,i,s

  res=false
  af_request("elem_getpoly")
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^nogging.*") then
      s=af_request("delplank")
      res=true
    end
    ac_objectclose()
  end
  return res
end


function GetName(sSettings, baseName)
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      if g_mat.thickness~=0 then
        baseName=string.format("%s %s", baseName, g_matid)
      else
        baseName=string.format("%s %sx%s", baseName, ac_environment("ntos", g_thickness, "length", "work"), ac_environment("ntos", g_height, "length", "work"))
      end
    end
  end
  return baseName
end
]]>
        </script>

        
        <script id="elemsettings">
          <![CDATA[
-- To have settings that can be referred from own element types with experssion like "this.options.elemsettings.spacing"
-- All settings are saved as strings
gSpacing=0.6
gStacking=0.0


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return -1
end


function Set(sSettings)
end


function Reset()
end

-------------------------
-- OPTIONS


function SettingsDlg(sSettings)
  local  tblSettings, bRes, sErr


  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    pcall(ParseSettings, sSettings)
  end
  
  tblSettings={}
  tblSettings[1]			={}
  tblSettings[1].cfgonly	=0
  tblSettings[1].type		=3
  tblSettings[1].prompt	="Spacing:"
  tblSettings[1].key		="spacing"
  tblSettings[1].value	=gSpacing

  tblSettings[2]			={}
  tblSettings[2].cfgonly	=0
  tblSettings[2].type		=3
  tblSettings[2].prompt	="Stacking offset:"
  tblSettings[2].key		="stackingoffset"
  tblSettings[2].value	=gStacking

  gHelpAnchor="afdlgelemsettings"
  bRes,sErr=ac_optiondlg("LDES", "Element settings", tblSettings)
  gHelpAnchor=nil
  if not bRes then
    return false
  end

  gSpacing=tblSettings[1].value
  gStacking=tblSettings[2].value
  return true
end



-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Gets value from key=value\n string allowing setting to be missing (then defVal is returned)
function GetOptNum(data, keyName, defVal)
  local val
  
  val=GetVal(data, keyName)
  if not val then
    return defVal
  end
  return tonumber(val)
end


function SettingsToStr()
  return string.format("spacing=%0.5f\nstackingoffset=%0.5f", gSpacing, gStacking)
end


-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  gSpacing=tonumber(GetVal(sSettings, "spacing"))
  gStacking=GetOptNum(sSettings, "stackingoffset", 0)

  -- Will cause error if bad syntax
  SettingsToStr()
end


function GetDefaults()
  gSpacing=0.6
  gStacking=0.0
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if not SettingsDlg(sSettings) then
    return
  end

  sSettings=SettingsToStr()
  return sSettings
end
]]>
        </script>

        <script id="autocuttopbot">
          <![CDATA[
-- For planks to be created
gnPlankCount=0
gtblCreate = {}


gbHas2ndTop = false
gbHas2ndBottom = false

gtblTop=nil       -- Topmost pieces "top_force" | "bottom_force"
gtbl2ndTop=nil    -- 2nd topmost pieces "2ndtop_force" | "2ndbottom_force"

gdMaxLen=4.78    -- Without EPS, 0=use plank's set maximum length
gdMinLen=1.200
gdMinOverlap=1.200
gdMinDistStud=0   -- If nonzero, will be cut as long as possible but this far from a stud


NO_REINFORCEMENT = 1
DO_REINFORCEMENT = 2

gbCutTop = 1
gbCutBottom = 1
gbReinforcementCut = NO_REINFORCEMENT
gReinforcementMaterial = nil
gdReinforcementMinLength = 0.3


function dump(o)
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end

-- Dumps given variable into string
function DumpTblInt(o, nIndent)
  local s,k,v
  
  if type(o) == 'table' then
    s = '{\n'
    for i = 0, nIndent do
      s = s .. '\t'
    end
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v, nIndent + 1) .. ',\n'
      for i = 0, nIndent do
        s = s .. '\t'
      end
    end

    if string.len(s) > 1 then
      if string.sub(s, -1) == '\t' then
        s = string.sub(s, 1, -2)
      end
    end

    s=s .. '}'
  else
    s = ""
    for i = 0, nIndent do
      s = s .. '\t'
    end
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o, 0))
end


-- Find & delete reinforcements
function DeleteReinforcements()
  local s, n
  
  for i = 1, gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s = ac_objectget("iElemGroup")
    
    if string.match(s, "reinforce_topbot") then
      af_request("delplank")
    end
    
    ac_objectclose()
  end
end


function FindPreviousStud(tblStuds, tblForce, i, startPos, tx1, ty1, tx2, ty2, isBot)
  local x2, y2, dx2, dy2
  local k = i - 1

  local fx1 = tblForce.elemdata.bx1
  local fy1 = tblForce.elemdata.by1
  local fx2 = tblForce.elemdata.bx2
  local fy2 = tblForce.elemdata.by2

  local found = false
  while k > 1 do
    local tblStud = tblStuds[k]
    local bx1 = tblStud.elemdata.bx1
    local by1 = tblStud.elemdata.by1
    local bx2 = tblStud.elemdata.bx2
    local by2 = tblStud.elemdata.by2

    -- Check that we're near the current 'top_force'/'bottom_force'
    if TestBoxBox(bx1, by1 - 0.0005, bx2, by2 + 0.0005, fx1, fy1, fx2, fy2, 0.0005) then
      local dx1 = tblStuds[i].elemdata.bx1 - bx1
      local dy1 = tblStuds[i].elemdata.by1 - by1
      local dx2 = tblStuds[i].elemdata.bx2 - bx2
      local dy2 = tblStuds[i].elemdata.by2 - by2

      if math.abs(dx1) > 0.0005 or math.abs(dx2) > 0.0005 then
        found = true
        break
      end

    end

    k = k - 1
  end

  if not found then
    return nil, 0
  end

  x2, y2 = ac_geo("linex", tx1, ty1, tx2, ty2, tblStuds[k].elemdata.bx2, tblStuds[k].elemdata.y1 - 1, tblStuds[k].elemdata.bx2, tblStuds[k].elemdata.y2 + 1)
  if x2 then
    dx2, dy2 = ac_geo("linedist", tx1, ty1, tx2, ty2, x2, y2)
    dy2 = dy2 - startPos

    return tblStuds[k], dy2
  else
    return nil, 0
  end
end


-- Finds studs and returns a 1-based table of GUIDs
-- Sets also gloval target gtblTop, gtbl2ndTop
function FindStuds(isBot)
  local tblStuds, plank, i, s, tblDest, group1, group1ex, group2, rotAngleLimit  
  
  gbHas2ndTop=false
  gbHas2ndBottom=false

  tblStuds={}
  gtblTop={}
  gtbl2ndTop={}
  
  group1="^top_force%a*"
  group1ex="contourtilted"
  group2="^2ndtop_force%a*"
  if isBot then
    group1="^bottom_force%a*"
    group1ex=nil
    group2="^2ndbottom_force%a*"
  end

  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s=ac_objectget("iElemGroup")

    tblDest=nil
    rotAngleLimit=nil
    if string.match(s, group1) or (group1ex and s==group1ex) then
      tblDest=gtblTop
    elseif string.match(s, group2) then
      tblDest=gtbl2ndTop
    elseif string.match(s, "^vertical_%a*") then
      tblDest=tblStuds
      rotAngleLimit = true
    end
    
    if string.match(s, "2ndbottom_force") then
      gbHas2ndBottom = true
    end

    if string.match(s, "2ndtop_force") then
      gbHas2ndTop = true
    end

    if tblDest then
      plank={}
      plank.elemgroup=s
      plank.elemdata=ac_objectget("#af_elemdata")
      plank.plankinfo=af_request("plankinfo")
      if not rotAngleLimit or math.abs(plank.elemdata.rotangle) < 1 then
        if string.match(s, "^vertical_%a*") and math.abs(plank.elemdata.x2-plank.elemdata.x1)>0.001 then
          plank=nil
        end
        
        if plank and not plank.plankinfo.del then
          -- if string.match(s, "^vertical_%a*") then
            -- ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f", plank.elemdata.x1, plank.elemdata.y1, plank.elemdata.x2, plank.elemdata.y2))
          -- end
          
          tblDest[#tblDest+1]=plank
        end
      end
    end

    ac_objectclose()
  end

  table.sort( tblStuds, function (p1, p2)
    -- Don't sort the studs by group! Code wants to have them by their x-coordinates.
    
    -- if p1.elemgroup~=p2.elemgroup then
      -- return p1.elemgroup<p2.elemgroup
    -- end
    
    return p1.elemdata.x1 < p2.elemdata.x1
	end)

  table.sort( gtblTop, function (p1, p2)
    if p1.elemgroup~=p2.elemgroup then
      return p1.elemgroup<p2.elemgroup
    end
    return p1.elemdata.x1 < p2.elemdata.x1
	end)

  table.sort( gtbl2ndTop, function (p1, p2)
    if p1.elemgroup~=p2.elemgroup then
      return p1.elemgroup<p2.elemgroup
    end
    return p1.elemdata.x1 < p2.elemdata.x1
	end)

  return tblStuds,#tblStuds
end


-- Check whether reinforcement of length reinforcementMinLength fits between studs A and B
function ReinforcementFits(reinforcementMinLength, studA, studB)
  local studLeftA = math.min(studA.elemdata.bx1, studA.elemdata.bx2)
  local studRightB = math.max(studB.elemdata.bx1, studB.elemdata.bx2)
  return studLeftA - studRightB > reinforcementMinLength
end


-- Gives distance from tx1, ty1 for given stud, nil=not found
function GetStudPos(tx1, ty1, tx2, ty2, tblStuds, i1)
  local x,y

  x,y=ac_geo("linex", tx1, ty1, tx2, ty2, tblStuds[i1].elemdata.x1, tblStuds[i1].elemdata.y1-1, tblStuds[i1].elemdata.x2, tblStuds[i1].elemdata.y2+1)
  if x then
    y,x=ac_geo("linedist", tx1, ty1, tx2, ty2, x, y)
  end
  return x
end


-- Gives distance from tx1, ty1 for given x-coordinate, nil=not found
function GetXDist(tx1, ty1, tx2, ty2, xc)
  local x,y
  
  x,y=ac_geo("linex", tx1, ty1, tx2, ty2, xc, -1, xc, 1)
  if x then
    y,x=ac_geo("linedist", tx1, ty1, tx2, ty2, x, y)
  end
  return x
end


-- Calculates x,y on given line dy from begin.
-- Returns x,y
function CalcVecPt(tx1, ty1, tx2, ty2, dist)
  local   len, dx, dy
      
  dx=tx2-tx1
  dy=ty2-ty1
  len=math.sqrt(dx*dx + dy*dy)
  return tx1 + dx / len * dist, ty1 + dy / len * dist
end


function TestBoxBox(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2)
  if ax2 < bx1 or ax1 > bx2 then return false end
  if ay2 < by1 or ay1 > by2 then return false end
  return true
end


-- Splits single plank
-- tx1, ty2, tx2, ty2   Line for the plank to be split (lower edge for top, upper edge for bottom): Plank will be cut on stud and this intersection
-- tblSplit All cut places are saved here (sorted)
-- No return value
function DoRow(currPlank, bStartLong, tblStuds, nStuds, tblPrev, tblSplit, tx1, ty1, tx2, ty2, isBot)
  local startPos, len, i1, i2, bFound, x, y, xLen, dx, dy, currPtr, maxLen, cosAngle
  local dx2, dy2, x2, y2, k
  local studA, studB
  local hasDouble, currMatId
  
  local bFirst = true

  cosAngle = math.abs(currPlank.elemdata.x2 - currPlank.elemdata.x1) / currPlank.plankinfo.len
  currPtr = currPlank.plankinfo.ptr

  ac_objectopen(currPtr)

  maxLen = gdMaxLen
  if maxLen < 0.001 then
    -- Get from plank's iMaxLen parameter
    maxLen = ac_objectget("iMaxLen")
    
    if maxLen < 0.001 then
      maxLen = 5
    end
  end
  
  currMatId = ac_objectget("iMatId")    -- Not enough if it is a block
  ac_objectclose()
  

  -- Don't reinforce if we have Double Top / Double Bottom, but enable cutting of long planks.
  hasDouble = false
  if gbHas2ndBottom and isBot then
    hasDouble = true
  end

  if gbHas2ndTop and not isBot then
    hasDouble = true
  end

  startPos = 0
  len = currPlank.plankinfo.len

  -- ac_environment("tolog", string.format("starting: startPos=%f len=%f", startPos, len))

  while len - startPos > maxLen + 0.0005 do
    -- Need to split, find as long as possible splitting part
    bFound = false
    i1 = nStuds

    -- Handle reinforcement cut here. The case without reinforcement is handled below
    if gbReinforcementCut == DO_REINFORCEMENT and not hasDouble then
      while i1 >= 1 do
        -- Current stud & current force
        local tblStud = tblStuds[i1]
        local tblForce = gtblTop

        local ax1 = tblStud.elemdata.bx1
        local ay1 = tblStud.elemdata.by1
        local ax2 = tblStud.elemdata.bx2
        local ay2 = tblStud.elemdata.by2

        local bx1 = tblForce[1].elemdata.bx1
        local by1 = tblForce[1].elemdata.by1
        local bx2 = tblForce[1].elemdata.bx2
        local by2 = tblForce[1].elemdata.by2

        local eps = 0.005

        -- ac_environment("tolog", string.format("ax1=%f ay1=%f ax2=%f ay2=%f bx1=%f by1=%f bx2=%f by2=%f", ax1, ay1 - eps, ax2, ay2 + eps, bx1, by1, bx2, by2))

        local bIntersects = TestBoxBox(ax1, ay1 - eps, ax2, ay2 + eps, bx1, by1, bx2, by2)
        if bIntersects then
          -- select the leftmost stud x-coord for the rightmost stud
          local studX = math.min(tblStud.elemdata.bx1, tblStud.elemdata.bx2)

          -- ac_environment("tolog", string.format("ax1=%f ay1=%f ax2=%f ay2=%f bx1=%f by1=%f bx2=%f by2=%f", ax1, ay1 - eps, ax2, ay2 + eps, bx1, by1, bx2, by2))

          x, y = ac_geo("linex", tx1, ty1, tx2, ty2, studX, tblStud.elemdata.y1 - 1, studX, tblStud.elemdata.y2 + 1)
          if x then
            dx, dy = ac_geo("linedist", tx1, ty1, tx2, ty2, x, y)
            dy = dy - startPos

            -- distance calculation has to be done from CUT to the NEXT PROSPECTIVE CUT,
            studA = tblStud
            studB, dy2 = FindPreviousStud(tblStuds, tblForce[1], i1, startPos, tx1, ty1, tx2, ty2)
            if not studB then
              bFound = false
              break
            end

            local pos = dy + ( (dy2-dy) / 2 )

            if pos < maxLen and len - (pos + startPos) > gdMinLen - 0.001 then
              if dy > gdMinLen - 0.0009 then
                -- Check if allowed
                bFound = true
                for i2 = 1, #tblPrev do
                  if math.abs(x - tblPrev[i2]) < gdMinOverlap / cosAngle - 0.001 then
                    bFound = false
                    break
                  end
                end

                if not ReinforcementFits(gdReinforcementMinLength, studA, studB) then
                  bFound = false
                end
              end
            end

            -- else
            --   local b1
            --   local b2
            --   local bot
            --   if pos < maxLen + 0.001 then b1 = 1 else b1 = 0 end
            --   if len - (pos + startPos) > gdMinLen - 0.001 then b2 = 1 else b2 = 0 end
            --   if isBot then bot = 1 else bot = 0 end
            --   ac_environment("tolog", string.format("isBot=%d startPos=%f x=%f dy=%f dy2=%f pos=%f maxlen=%f len=%f len-(pos+startPos)=%f > %f b1=%d b2=%d", bot, startPos, x, dy, dy2, pos, maxLen, len, len-(pos+startPos),gdMinLen-0.001, b1, b2))
            -- end

            if bFound then
              break
            end
          end
        end -- bIntersects

        i1=i1-1
      end
    else
      -- No reinforcement
      if gdMinDistStud > 0 then
        -- Min distance from the middle of a stud, find the last stud after the plank and the first before the end
        -- Change to cut from middle: gdMinOverlap is in plank's dir
        local ipre, ipost
        
        ipre = nil
        ipost = nil
        while i1 >= 1 do
          dy = GetStudPos(tx1, ty1, tx2, ty2, tblStuds, i1)
          if dy then
            -- Has intersection
            if dy < startPos+maxLen then
              ipre = i1
              break
            end

            ipost = i1
          end

          i1 = i1 - 1
        end
        
        -- ac_environment("tolog", string.format("dy=%f ipre=%d ipost=%d", dy, ipre, ipost))
        
        bFound = true
        dy = startPos + maxLen      -- dy is the found length
        if len - dy < gdMinLen + 0.0005 then
          -- Apply min length
          dy = len - gdMinLen
        end
        
        -- ac_environment("tolog", string.format("dy=%f ipre=%d ipost=%d", dy, ipre, ipost))
        
        if ipre or ipost then
          -- Some studs found
          local x1, x2

          bFound = false
          while true do
            -- Calc possible cut area
            x1 = 0
            x2 = len
            if ipre then
              x1 = GetStudPos(tx1, ty1, tx2, ty2, tblStuds, ipre) + gdMinDistStud
            end
            if ipost then
              x2 = GetStudPos(tx1, ty1, tx2, ty2, tblStuds, ipost) - gdMinDistStud
            end
            
            -- ac_environment("tolog", string.format("x1: %f x2: %f tx1: %f ty1: %f tx2: %f ty2: %f", x1, x2, tx1, ty1, tx2, ty2))
            -- ac_environment("tolog", string.format("dy=%f ipre=%d ipost=%d x1=%f x2=%f", dy, ipre, ipost, x1, x2))

            if x1 - 0.0001 < x2 and x1 < dy then
              -- There is a possible cutting place, cut from max pos
              if x2 < dy then
                dy = x2
              end

              -- Apply overlap rule, tblPrev has x-coordinates of cuts
              local   dprev

              bFound = true
              for i2 = 1, #tblPrev do
                dprev = GetXDist(tx1, ty1, tx2, ty2, tblPrev[i2])
                if math.abs(dy - dprev) < gdMinOverlap then
                  -- There is a cut too close, back off
                  dprev = dprev - gdMinOverlap
  --ac_environment("tolog", string.format("Min overlap rule applied: dy=%f ipre=%d ipost=%d x1=%f x2=%f dprev=%f", dy, ipre, ipost, x1, x2, dprev))
                  if dprev > x1 then
                    dy = dprev
                  else
                    bFound = false
                  end
                  break
                end
              end
              
              if bFound then
                break
              end
            end
              
            if ipre then
              ipost = ipre
              ipre = ipre - 1
              if ipre == 0 then
                break
              end
            else
              break     -- Nothing to process any more, not found
            end
          end
        end

        -- Calc x that is saved for the overlapping rule
        x = CalcVecPt(tx1, ty1, tx2, ty2, dy)

        -- Relative to current plank
        dy = dy - startPos

      else
        -- Cut from middle of a stud
              
        -- Iterate over the studs and check the distance of the stud to our starting position,
        -- break when we're at an appropriate position
        while i1 >= 1 do

          x, y = ac_geo("linex", tx1, ty1, tx2, ty2, tblStuds[i1].elemdata.x1, tblStuds[i1].elemdata.y1 - 1, tblStuds[i1].elemdata.x2, tblStuds[i1].elemdata.y2 + 1)
          if x then
            dx, dy = ac_geo("linedist", tx1, ty1, tx2, ty2, x, y)   
            dy = dy - startPos
            if dy < maxLen + 0.001 and len - (dy + startPos) > gdMinLen - 0.001 then
              if dy < gdMinLen - 0.0009 then
                break
              end

              -- Check if allowed
              bFound = true
              for i2 = 1, #tblPrev do
                -- ac_environment("tolog", string.format("%f %f", x-tblPrev[i2], gdMinOverlap/cosAngle))
                if math.abs(x - tblPrev[i2]) < gdMinOverlap / cosAngle - 0.001 then
                  bFound = false
                  break
                end
              end
            end

            if bFound then
              break
            end
          end
        
          i1=i1-1
        end
      end
    --
    end

    if not bFound then
      ac_environment("tolog", "WARNING: Unable to automatically cut plank by rules (minimum length, minimum overlap), please check and cut manually.")
      break
    end
    
    -- Early out if we're not cutting these planks
    if gbCutBottom == 0 and isBot then
      break
    elseif gbCutTop == 0 and not isBot then
      break
    end

    local cut = dy
    if gbReinforcementCut == DO_REINFORCEMENT and not hasDouble then
      cut = dy + ( (dy2-dy) / 2 )
    end
    
    tblSplit[#tblSplit + 1] = cut

    ac_objectopen(currPtr)
    
    local tblPlane
    tblPlane = af_request("getbegendplane", "beg", 1)
            
    -- ac_environment("tolog", string.format("pd=%f cut=%f actual=%f dy=%f x=%f", tblPlane.pd, cut, tblPlane.pd + cut, dy, x))
    -- ac_environment("tolog", string.format("pa=%f pb=%f pc=%f pd=%f", tblPlane.pa, tblPlane.pb, tblPlane.pc, tblPlane.pd))  

    -- always from last cut
    tblPlane.pd = tblPlane.pd + cut
    
    currPtr = af_request("cutplank", tblPlane)
    
    ac_objectclose()

    if currPtr and gbReinforcementCut == DO_REINFORCEMENT and not hasDouble then
      local tblMat = af_request("singlemat", currPlank.plankinfo.typename)

      -- Calculate reinforcement plank position
      local materialHeight    = tblMat.height
      local materialThickness = tblMat.thickness
      local materialWidth     = currPlank.plankinfo.width
      local reinforceMat
      
      reinforceMat = gReinforcementMaterial
      if reinforceMat == nil then
        -- Use same as current
        reinforceMat = currMatId
      end
      
      local tblReinforcementMat = af_request("singlemat", reinforceMat)

      -- Assumes plank.rotangle == 0
      local zoff = (materialHeight / 2) - (tblReinforcementMat.height / 2)
      
      local yAdjust = tblReinforcementMat.thickness / 2.0
      if not isBot then
        yAdjust = -yAdjust
      end

      local studY
      if isBot then
        studY = math.max(gtblTop[1].elemdata.by1, gtblTop[1].elemdata.by2)
      else
        studY = math.min(gtblTop[1].elemdata.by1, gtblTop[1].elemdata.by2)
      end
      
      local y = studY + yAdjust

      -- ac_environment("tolog", string.format("a: x1=%f y1=%f x2=%f y2=%f", studA.elemdata.x1, studA.elemdata.y1, studA.elemdata.x2, studA.elemdata.y2))
      -- ac_environment("tolog", string.format("b: x1=%f y1=%f x2=%f y2=%f", studB.elemdata.x1, studB.elemdata.y1, studB.elemdata.x2, studB.elemdata.y2))

      -- Do the calculations 'from the left'
      local x1, x2

      -- change to min max
      if studA.elemdata.x1 < studB.elemdata.x2 then
        x1 = studA.elemdata.x1
        x2 = studB.elemdata.x1
        leftWidth = studA.plankinfo.width / 2
        rightWidth = studB.plankinfo.width / 2
      else
        x1 = studB.elemdata.x1
        x2 = studA.elemdata.x1
        leftWidth = studB.plankinfo.width / 2
        rightWidth = studA.plankinfo.width / 2
      end
      
      local plankX1 = x1 + leftWidth
      local plankY1 = y
      local plankX2 = x2 - rightWidth
      local plankY2 = y

      local plank = {}
      plank.guidsettings = currPlank.plankinfo.ptr
      plank.id = reinforceMat
      plank.xmlsettings = "<root>\n" .. "<objparam name=\"iElemModule\"></objparam>\n" .. "</root>\n"
      plank.group = "reinforce_topbot"
      plank.x1 = plankX1
      plank.x2 = plankX2
      plank.y1 = plankY1
      plank.y2 = plankY2
      plank.force = 2
      plank.rotangle = 0
      plank.zoff = zoff
      
      local reinforcementLen = plankX2 - plankX1
      if reinforcementLen+0.0001 >= gdReinforcementMinLength then
        gnPlankCount = gnPlankCount + 1
        gtblCreate[gnPlankCount] = plank
      end
      
      -- ac_environment("tolog", string.format("failed to create reinforcement: not enough space between studs: %f, %f", reinforcementLen, gdReinforcementMinLength))
    end
    
    if not currPtr then
      break
    end

    startPos = startPos + cut
    bStartLong = true
    bFirst = false
  end
end


function DoAutoCutTop(isBot)
  local tblStuds, nStuds, i1, i2, x1, y1, x2, y2, dx, dy, tblPlank

  gnPlankCount=0
  gtblCreate = {}
  
  tblStuds,nStuds=FindStuds(isBot)     -- Also finds target elements
  
  -- Discard any stud not close enough to lowest top piece
  local yDir=-1
  if isBot then
    yDir=1
  end

  local tblTargetRows = {}
  
  i2=0
  if isBot then
    if #gtblTop>0 then
      i2=i2+1
      tblTargetRows[i2]=gtblTop
    end
    if #gtbl2ndTop>0 then
      i2=i2+1
      tblTargetRows[i2]=gtbl2ndTop
    end
  else
    if #gtbl2ndTop>0 then
      i2=i2+1
      tblTargetRows[i2]=gtbl2ndTop
    end
    if #gtblTop>0 then
      i2=i2+1
      tblTargetRows[i2]=gtblTop
    end
  end

  local i3, tblPrev, tblSplit

  local bStartLong = true
  tblPrev={}
  for i1=1,i2 do
    tblSplit = {}
    for i3=1,#tblTargetRows[i1] do
      tblPlank=tblTargetRows[i1][i3]

      x1=tblPlank.elemdata.x1
      y1=tblPlank.elemdata.y1
      x2=tblPlank.elemdata.x2
      y2=tblPlank.elemdata.y2
      dx=(x2-x1) / tblPlank.plankinfo.len * tblPlank.plankinfo.width * 0.5
      dy=(y2-y1) / tblPlank.plankinfo.len * tblPlank.plankinfo.width * 0.5
        
      if x1>x2 then
        yDir=-yDir
      end

      dx,dy=-dy*yDir, dx*yDir     -- For bottom piece: Left from line
      x1=x1+dx
      y1=y1+dy
      x2=x2+dx
      y2=y2+dy
      
      -- ac_environment("tolog", string.format("i1=%d i3=%d bStartLong=%s nStuds=%d x1=%f y1=%f x2=%f y2=%f isBot=%s", i1, i3, tostring(bStartLong), nStuds, x1, y1, x2, y2, tostring(isBot)))
         -- 5 , 6
         -- tblPrev, tblSplit
      DoRow(tblTargetRows[i1][i3], bStartLong, tblStuds, nStuds, tblPrev, tblSplit, x1, y1, x2, y2, isBot)
    end
    tblPrev = tblSplit
    bStartLong = not bStartLong
  end
  
  if #gtblCreate > 0 then
    af_request("elem_createplanks")
  end
  
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return ResetInt(true)
end


function Set(sSettings)
  local default, res, errStr

  gnPlankCount=0
  gtblCreate = {}

  af_request("elem_getpoly")
  if gnPlanks==0 then
    return
  end
  
  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end
  
  if default then
    -- Default settings
    GetDefaults()
  end

  if gbCutTop == 1 then
    DoAutoCutTop(false)
  end
  
  if gbCutBottom == 1 then
    DoAutoCutTop(true)
  end

end


-- justCheck  true=do not connect, just check if there are split pieces
-- Returns: true=changes, false=no split ones
function DoJoin(tblPlanks, justCheck)
  local i, firstInd, res, x1, y1, x2, y2, hasX, dist1, len1, dist2, len2, dx, dy

  -- Join all connecting ones to the first piece
  firstInd=1
  res=false
  for i=2,#tblPlanks do
    x1=tblPlanks[firstInd].elemdata.x1
    y1=tblPlanks[firstInd].elemdata.y1
    x2=tblPlanks[firstInd].elemdata.x2
    y2=tblPlanks[firstInd].elemdata.y2

    hasX=ac_geo("linex", x1, y1, x2, y2, tblPlanks[i].elemdata.x1, tblPlanks[i].elemdata.y1, tblPlanks[i].elemdata.x2, tblPlanks[i].elemdata.y2)
    dist1,len1 = ac_geo("linedist", x1, y1, x2, y2, tblPlanks[i].elemdata.x1, tblPlanks[i].elemdata.y1)
    dist2,len2 = ac_geo("linedist", x1, y1, x2, y2, tblPlanks[i].elemdata.x2, tblPlanks[i].elemdata.y2)

    if len2<len1 then
      len1=len2
      dist1=dist2
    end
    
    dx=x2-x1
    dy=y2-y1
    len2=math.sqrt(dx*dx+dy*dy)
--ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f len1=%f dist1=%f len2=%f", x1, y1, x2, y2, len1, dist1, len2))
    if not hasX and math.abs(dist1)<0.001 and math.abs(dist2)<0.001 and len1>-0.001 and len1<len2+0.001 then
      res=true
      if justCheck then
        break
      end
      af_request("joinplanks", tblPlanks[firstInd].plankinfo.ptr, tblPlanks[i].plankinfo.ptr)
      
      ac_objectopen(tblPlanks[firstInd].plankinfo.ptr)
      tblPlanks[firstInd].elemdata=ac_objectget("#af_elemdata")     -- Refresh
      ac_objectclose()
    else
      firstInd=i
    end
  end
  return res
end


function Reset()
  return ResetInt(false)
end


function ResetInt(justCheck)
  local res, i
  
  gnPlankCount=0
  gtblCreate = {}

  res=0
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  
  -- Top
  FindStuds(false)
  if #gtblTop>1 then
    if DoJoin(gtblTop, justCheck) then
      res=1
    end
  end
  if #gtbl2ndTop>1 then
    if DoJoin(gtbl2ndTop, justCheck) then
      res=1
    end
  end

  -- Bottom
  FindStuds(true)
  if #gtblTop>1 then
    if DoJoin(gtblTop, justCheck) then
      res=1
    end
  end
  if #gtbl2ndTop>1 then
    if DoJoin(gtbl2ndTop, justCheck) then
      res=1
    end
  end
  
  -- Remove found reinforcements
  DeleteReinforcements()

  return res
end


-------------------------
-- OPTIONS


-- Gets AF's default material list and sorts it. Returns the sorted table and string of the the material IDs suitable for dialogs.
function GetSortedMaterials()
  local tblMaterials, tblSortedMaterials
  local strMaterials
  local s = ""
  local strSep = ""
  local i, id, v

  tblMaterials = af_request("matlist")
  
  local n = 0
  tblSortedMaterials = {}
  
  -- We'll remove those materials that don't have height & thickness defined
  for id, v in pairs(tblMaterials) do
    if v.height ~= 0 and v.thickness ~= 0 then
      n = n + 1
      tblSortedMaterials[n] = v
    end
  end
  
  table.sort(tblSortedMaterials, function(m1, m2)
    return m1.index < m2.index
  end)
  
  -- Since we removed bunch of materials from the list, the indices are 'off by diff', adjust them here
  local diff = tblSortedMaterials[#tblSortedMaterials].index - #tblSortedMaterials
  for i = 1, #tblSortedMaterials do 
    tblSortedMaterials[i].index = tblSortedMaterials[i].index - diff
  end

  for i, v in ipairs(tblSortedMaterials) do
    s = string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep = ","
  end

  return tblSortedMaterials, s
end


function SettingsDlg(sSettings)
  local  tblSettings, bRes, sErr, i
  
  local tblSortedMaterials, strMaterials = GetSortedMaterials()
  
  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    pcall(ParseSettings, sSettings)
  end

  local defaultMaterial
  if gReinforcementMaterial ~= nil then 
    for id, v in pairs(tblSortedMaterials) do
      if v.id == gReinforcementMaterial then
        defaultMaterial = v.index
        break
      end
    end
  else

    local tblStudMat = af_request("elem_getstudmat")
    if tblStudMat then
      if tblStudMat.height == 0 or tblStudMat.thickness == 0 then
        for id, v in pairs(tblSortedMaterials) do
          if v.height ~= 0 and v.thickness ~= 0 then
            defaultMaterial = v.index
            break
          end
        end
      else
        defaultMaterial = tblStudMat.index
      end
    else
      -- In element layer options - no element now
      defaultMaterial=1
    end
  end

  i = 1

  tblSettings={}
  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	="Max length (0=use plank's maximum length):"
  tblSettings[i].key		="maxlen"
  tblSettings[i].value	=gdMaxLen
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	="Min length:"
  tblSettings[i].key		="minlen"
  tblSettings[i].value  =gdMinLen
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	="Min overlap:"
  tblSettings[i].key		="minoverlap"
  tblSettings[i].value  =gdMinOverlap
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	="Min distance from stud (0=cut from center):"
  tblSettings[i].key		="minstud"
  tblSettings[i].value  =gdMinDistStud
  i = i + 1

  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type     = 2
  tblSettings[i].prompt   = "Cut top:"
  tblSettings[i].key      = "cut_top"
  tblSettings[i].value    = gbCutTop

  i = i + 1

  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type     = 2
  tblSettings[i].prompt   = "Cut bottom:"
  tblSettings[i].key      = "cut_bottom"
  tblSettings[i].value    = gbCutBottom

  i = i + 1

  local strNoYes = "\"1:No\",\"2:Yes\""
  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type     = 1
  tblSettings[i].prompt   = "Reinforcement to the cut:"
  tblSettings[i].key      = "reinforcement_cut"
  tblSettings[i].valuelist = strNoYes
  tblSettings[i].value = gbReinforcementCut
  i = i + 1

  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type     = 1
  tblSettings[i].prompt   = "Reinforcement material ID:"
  tblSettings[i].key      = "reinforcement_material"
  tblSettings[i].valuelist = strMaterials
  tblSettings[i].value    = defaultMaterial
  i = i + 1

  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type		  = 3
  tblSettings[i].prompt   = "Reinforcement minimum length:"
  tblSettings[i].key		  = "reinforcement_min_length"
  tblSettings[i].value    = gdReinforcementMinLength
  i = i + 1

  bRes,sErr=ac_optiondlg("LDAC", "Automatic cutting", tblSettings)
  if not bRes then
    return false
  end
  
  gdMaxLen=tblSettings[1].value
  gdMinLen=tblSettings[2].value
  gdMinOverlap=tblSettings[3].value
  gdMinDistStud=tblSettings[4].value
  gbCutTop = tblSettings[5].value
  gbCutBottom = tblSettings[6].value
  gbReinforcementCut = tblSettings[7].value
  
  local mat = nil
  for id, v in pairs(tblSortedMaterials) do
    if id == tblSettings[8].value then
      mat = v.id
    end
  end
  
  gReinforcementMaterial = mat
  gdReinforcementMinLength = tblSettings[9].value
  
  return true
end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets all configuration globals.
function ParseSettings(sSettings)
  local val
  
  gdMaxLen=tonumber(GetVal(sSettings, "maxlen"))
  gdMinLen=tonumber(GetVal(sSettings, "minlen"))
  gdMinOverlap=tonumber(GetVal(sSettings, "minoverlap"))
  
  val=GetVal(sSettings, "minstud")
  if val then
    gdMinDistStud=tonumber(val)
  end
    
  gbCutTop =  tonumber(GetVal(sSettings, "cut_top"))
  gbCutBottom = tonumber(GetVal(sSettings, "cut_bottom"))
  gbReinforcementCut = tonumber(GetVal(sSettings, "reinforcement_cut"))
  gReinforcementMaterial = GetVal(sSettings, "reinforcement_material")
  if gReinforcementMaterial~=nil and gReinforcementMaterial=="" then
    gReinforcementMaterial=nil
  end
    
  gdReinforcementMinLength = tonumber(GetVal(sSettings, "reinforcement_min_length"))

  -- ac_environment("tolog", string.format("%s %s", "gbCutTop", tostring(gbCutTop)))
  -- ac_environment("tolog", string.format("%s %s", "gbCutBottom", tostring(gbCutBottom)))
  -- ac_environment("tolog", string.format("%s %s", "gbReinforcementCut", tostring(gbReinforcementCut)))
  -- ac_environment("tolog", string.format("%s %s", "gReinforcementMaterial", tostring(gReinforcementMaterial)))
  -- ac_environment("tolog", string.format("%s %s", "gdReinforcementMinLength", tostring(gdReinforcementMinLength)))  
  
  -- Will cause error if bad syntax
  DoSettingsStr()  
  return true
end


function GetDefaults()
  gdMaxLen=4.78    -- Without EPS, 0=use plank's set maximum length
  gdMinLen=1.200
  gdMinOverlap=1.200
  gdMinDistStud=0
  gbCutTop = 1
  gbCutBottom = 1
  gbReinforcementCut = 1
  gReinforcementMaterial = nil
  gdReinforcementMinLength = 0.3
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if not SettingsDlg(sSettings) then
    return
  end

  return DoSettingsStr()
end


function DoSettingsStr()
  local reinforce = gReinforcementMaterial
  local sSettings
  
  if reinforce==nil then
    reinforce=""
  end
  
  sSettings = string.format("maxlen=%0.6f\nminlen=%0.6f\nminoverlap=%0.6f\nminstud=%0.6f\n", gdMaxLen, gdMinLen, gdMinOverlap, gdMinDistStud )
  sSettings = sSettings .. string.format("cut_top=%d\ncut_bottom=%d\nreinforcement_cut=%d\nreinforcement_material=%s\nreinforcement_min_length=%0.6f",
    gbCutTop, gbCutBottom, gbReinforcementCut, reinforce, gdReinforcementMinLength)
  return sSettings
end
]]>
        </script>



        <script id="autocutstud">
          <![CDATA[
gdMaxLen=0          -- Without EPS, 0=use plank's set maximum length
gdMinLen=1.200
gdMinOverlap=1.200
gOverlapRuleDist=1.2


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return ResetInt(true)
end


function Set(sSettings)
  local default, res, errStr, t

  default=true
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if res then
      default=false
    end
  end

  if default then
    -- Default settings
    GetDefaults()
  end 

  t={}
  t.elemguid=gGuidElem
  t.maxlen=gdMaxLen
  t.minlen=gdMinLen
  t.minoverlap=gdMinOverlap
  t.overlapruledist=gOverlapRuleDist
  
  af_request("autocut", t)
end


-- justCheck  true=do not connect, just check if there are split pieces
-- Returns: true=changes, false=no split ones
function DoJoin(tblPlanks, justCheck)
  local i, firstInd, res, x1, y1, x2, y2, hasX, dist1, len1, dist2, len2, dx, dy

  -- Join all connecting ones to the first piece
  firstInd=1
  res=false
  for i=2,#tblPlanks do
    x1=tblPlanks[firstInd].elemdata.x1
    y1=tblPlanks[firstInd].elemdata.y1
    x2=tblPlanks[firstInd].elemdata.x2
    y2=tblPlanks[firstInd].elemdata.y2

    hasX=ac_geo("linex", x1, y1, x2, y2, tblPlanks[i].elemdata.x1, tblPlanks[i].elemdata.y1, tblPlanks[i].elemdata.x2, tblPlanks[i].elemdata.y2)
    dist1,len1 = ac_geo("linedist", x1, y1, x2, y2, tblPlanks[i].elemdata.x1, tblPlanks[i].elemdata.y1)
    dist2,len2 = ac_geo("linedist", x1, y1, x2, y2, tblPlanks[i].elemdata.x2, tblPlanks[i].elemdata.y2)

    if len2<len1 then
      len1=len2
      dist1=dist2
    end
    
    dx=x2-x1
    dy=y2-y1
    len2=math.sqrt(dx*dx+dy*dy)
--ac_environment("tolog", string.format("x1=%f y1=%f x2=%f y2=%f len1=%f dist1=%f len2=%f", x1, y1, x2, y2, len1, dist1, len2))
    if not hasX and math.abs(dist1)<0.001 and math.abs(dist2)<0.001 and len1>-0.001 and len1<len2+0.001 then
      res=true
      if justCheck then
        break
      end
      af_request("joinplanks", tblPlanks[firstInd].plankinfo.ptr, tblPlanks[i].plankinfo.ptr)
      
      ac_objectopen(tblPlanks[firstInd].plankinfo.ptr)
      tblPlanks[firstInd].elemdata=ac_objectget("#af_elemdata")     -- Refresh
      ac_objectclose()
    else
      firstInd=i
    end
  end
  return res
end


function Reset()
  return ResetInt(false)
end


function ResetInt(justCheck)
  local i, i2, tblPlanks, elemdata, t, t2, info, res
  local cos1=0.99984769515639123915701155881391
  
  res=0
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  
  -- Check if there are parallel planks having the same end points
  tblPlanks={}
  res=0
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
    elemdata=ac_objectget("#af_elemdata")
    info=af_request("plankinfo")
    ac_objectclose()
    
    t={}
    t.guid=info.ptr
    t.elemdata=elemdata
    t.dx=t.elemdata.x2-t.elemdata.x1
    t.dy=t.elemdata.y2-t.elemdata.y1
    t.len=math.sqrt(t.dx * t.dx + t.dy * t.dy)
    if t.len>0.0001 then
      t.dx=t.dx / t.len
      t.dy=t.dy / t.len
    end
    t.conn={}
    tblPlanks[i]=t
    
    -- Check if any connection
    i2=1
    while i2<i do
      t2=tblPlanks[i2]
      if math.abs(t.dx * t2.dx + t.dy * t2.dy)>cos1 and math.abs(t.elemdata.z1 - t2.elemdata.z1)<0.001 then

        -- Parallel and same z-offset, check end points
        if (math.abs(t2.elemdata.x1 - t.elemdata.x1)<0.001 and math.abs(t2.elemdata.y1 - t.elemdata.y1)<0.001) or (math.abs(t2.elemdata.x1 - t.elemdata.x2)<0.001 and math.abs(t2.elemdata.y1 - t.elemdata.y2)<0.001) then
          -- Connected to beg of current
          res=1
          if justCheck then
            break
          end
          
          t2.conn[#t2.conn + 1]=i
          t.conn[#t.conn + 1]=i2
        end
        if (math.abs(t2.elemdata.x2 - t.elemdata.x1)<0.001 and math.abs(t2.elemdata.y2 - t.elemdata.y1)<0.001) or (math.abs(t2.elemdata.x2 - t.elemdata.x2)<0.001 and math.abs(t2.elemdata.y2 - t.elemdata.y2)<0.001) then
          -- Connected to end of current
          res=1
          if justCheck then
            break
          end
          
          t2.conn[#t2.conn+1]=i
          t.conn[#t.conn + 1]=i2
        end
      end
      i2=i2+1
    end
  end
  
  if justCheck then
    return res
  end

  if res>0 then
    -- Connect recursively
    t={}      -- Reuse as table if handled ones
    for i=1,gnPlanks do
      if not t[i] then
        DoConn(tblPlanks, i, t)
      end
    end
  end

  return res
end


function DoConn(tblPlanks, currind, tblHandled)
  local i, index, tblPlank
  
  tblPlank=tblPlanks[currind]
  if #tblPlank.conn==0 then
    return
  end
  
  i=1
  while true do
    index=tblPlank.conn[i]
    if not index then
      break
    end
      
    if not tblHandled[index] then
      tblHandled[index]=1
      DoConn(tblPlanks, index, tblHandled)
      af_request("joinplanks", tblPlank.guid, tblPlanks[index].guid)
    end

    i=i+1
  end
end


-------------------------
-- OPTIONS


function SettingsDlg(sSettings)
  local  tblSettings, bRes, sErr


  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    pcall(ParseSettings, sSettings)
  end
  
  tblSettings={}
  tblSettings[1]			={}
  tblSettings[1].cfgonly	=0
  tblSettings[1].type		=3
  tblSettings[1].prompt	="Max length (0=use plank's maximum length):"
  tblSettings[1].key		="maxlen"
  tblSettings[1].value	=gdMaxLen

  tblSettings[2]			={}
  tblSettings[2].cfgonly	=0
  tblSettings[2].type		=3
  tblSettings[2].prompt	="Min length:"
  tblSettings[2].key		="minlen"
  tblSettings[2].value  =gdMinLen

  tblSettings[3]			={}
  tblSettings[3].cfgonly	=0
  tblSettings[3].type		=3
  tblSettings[3].prompt	="Min overlap:"
  tblSettings[3].key		="minoverlap"
  tblSettings[3].value  =gdMinOverlap

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=3
  tblSettings[4].prompt	="Min overlap rule applied max dist:"
  tblSettings[4].key		="minoverlaprule"
  tblSettings[4].value  =gOverlapRuleDist

  bRes,sErr=ac_optiondlg("LDAS", "Automatic stud cutting", tblSettings)
  if not bRes then
    return false
  end

  gdMaxLen=tblSettings[1].value
  gdMinLen=tblSettings[2].value
  gdMinOverlap=tblSettings[3].value
  gOverlapRuleDist=tblSettings[4].value
  return true
end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    if k == keyName then
      return v
    end
  end
  return nil
end


-- Called with pcall(), sets globals: g_mat, g_thickness, g_height
function ParseSettings(sSettings)
  local s
  
  gdMaxLen=tonumber(GetVal(sSettings, "maxlen"))
  gdMinLen=tonumber(GetVal(sSettings, "minlen"))
  gdMinOverlap=tonumber(GetVal(sSettings, "minoverlap"))
  gOverlapRuleDist=tonumber(GetVal(sSettings, "overlapruledist"))

  -- Will cause error if bad syntax
  s = string.format("maxlen=%0.5f\nminlen=%0.5f\nminoverlap=%0.5f\noverlapruledist=%0.5f", gdMaxLen, gdMinLen, gdMinOverlap, gOverlapRuleDist )
end


-- Finds nice material
function GetDefaults()
  gdMaxLen=0
  gdMinLen=1.200
  gdMinOverlap=1.200
  gOverlapRuleDist=1.2
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if not SettingsDlg(sSettings) then
    return
  end

  sSettings=string.format("maxlen=%0.5f\nminlen=%0.5f\nminoverlap=%0.5f\noverlapruledist=%0.5f", gdMaxLen, gdMinLen, gdMinOverlap, gOverlapRuleDist)
  return sSettings
end
]]>
        </script>


        <script id="floorsideplanks">
          <![CDATA[
-- Adds side pieces to selected planks using current grid

-- Frame interface to add new planks to the related element
gnPlankCount=0
gtblCreate = {}


g_matid=nil             -- Material ID
g_thickness=nil         -- Only if block (matid thickness is 0)
g_height=nil
g_side=-1               -- -1=to left from selection


-- Returns cos angle of the vectors if normalized
function CalcDot3D( x1, y1, z1, x2, y2, z2 )
	return x1 * x2 + y1 * y2 + z1 * z2;
end


-- Returns cos angle of the vectors if normalized
function CalcDot( x1, y1, x2, y2 )
	return x1 * x2 + y1 * y2
end


-- Converts given global coordinates to element's coordinates
-- Returns x,y,z
function GlobalToSide(side, x, y, z)
  local x2, y2, z2

  x=x-side.origc.x
  y=y-side.origc.y
  z=z-side.origc.z
  
  x2=CalcDot3D(side.vecx.x, side.vecx.y, side.vecx.z, x, y, z)
  y2=CalcDot3D(side.vecy.x, side.vecy.y, side.vecy.z, x, y, z)
  z2=CalcDot3D(side.vecz.x, side.vecz.y, side.vecz.z, x, y, z)
  
  return x2, y2, z2
end


-- Returns nil if zero length vector
function ToUnit(dx,dy)
  local len

  len=math.sqrt(dx*dx + dy*dy)
  if len<0.001 then
    return
  end
  return dx/len, dy/len, len
end


-- Duunaa tason yhtälön ax+bx+cx+dx=0 tason normaalista ja yhdestä pisteestä x1,y1,z1
-- Huom-- plane constant eri etumerkillä kuin wykobissa
-- in:
--	tnx, tny, tnz	Vektori tason normaalista, lasketaan täällä yksikkövektoriksi
--	x1,y1,z1		Piste tasolla
-- out:
--	ta, tb, tc, td	Tason yhtälö (ta,tb,tc=tnx,tny,tnz normalisoituna)
function MakePlaneNormal(tnx, tny, tnz, x1, y1, z1)
	--   template<typename T>
	--   inline plane<T,3> make_plane(const T& x1, const T& y1, const T& z1,
	--								const T& x2, const T& y2, const T& z2,
	--								const T& x3, const T& y3, const T& z3)
	--   {
	--	  plane<T,3> plane_;
	--	  vector3d<T> v1 = makevector(x2 - x1, y2 - y1, z2 - z1);
	--	  vector3d<T> v2 = makevector(x3 - x1, y3 - y1, z3 - z1);
	--	  plane_.normal   = normalize(v1 * v2);
	--	  plane_.constant = dot_product(plane_.normal,makevector(x1,y1,z1));
	--	  return plane_;
	--   }
	local mul, ta, tb, tc, td

	-- Tässä hypätään suoraan vakion laskentaan
	mul=1/math.sqrt(tnx*tnx+tny*tny+tnz*tnz)
	ta=tnx*mul
	tb=tny*mul
	tc=tnz*mul
	td=-(ta*x1+tb*y1+tc*z1)
	return ta, tb, tc, td
end


-- ### Suoran ja tason leikkauspiste
-- in: 
--	ta,tb,tc,td		Tason yhtälö, a-c=kohtisuora ja d on vakio
--   x1, y1, z1		Suora
--   x2, y2, z2		Suora
-- out:
--	hasX			Oliko leikkausta
--	x, y, z			Piste
--   dist			Etäisyys pisteestä x1,y1,z1 suoran suuntaisesti (suhteessa suoran pituuteen 0...1!)
function LinePlaneX(ta, tb, tc, td, x1, y1, z1, x2, y2, z2 )
	-- Tuollainen koodi "käännetty" wykobi-kirjastosta
	--   template<typename T>
	--   inline point3d<T> intersection_point(const line<T,3>&  line,
	--										const plane<T,3>& plane)
	--   {
	--	  vector3d<T> linevec = line[1] - line[0];
	--	  T denom = dot_product(linevec,plane.normal);
	--	  point3d<T> ipoint = degenerate_point3d<T>();
	--	  if (not_equal(denom,T(0.0)))
	--	  {
	--		 T t = -distance(line[0],plane) / denom;
	--		 ipoint = line[0] + t * (line[1] - line[0]);
	--	  }
	--	  return ipoint;
	--   }
	local x, y, z, dist, denom


	dist=0

	x=x2-x1
	y=y2-y1
	z=z2-z1

	denom=x*ta + y*tb + z*tc		-- Pistetulo suora ja tason normaali
	if math.abs(denom)<1E-5 then
		-- Tason suuntainen suora
		return false
	end

	-- Pisteen etäisyys tasolta
	-- (plane.normal.x * point.x + plane.normal.y * point.y + plane.normal.z * point.z ) - plane.constant;

	dist=-(ta*x1 + tb*y1 + tc*z1 + td)/denom		-- Huom-- td eri etumerkillä kuin wykobissa (kun siellä oli puki)
	x=x1 + x*dist
	y=y1 + y*dist
	z=z1 + z*dist
	return true, x, y, z, dist
	-- To return correct dist: return true, x, y, z, dist*math.abs(denom)
end


function DumpVec(info, vec)
  ac_environment("tolog", string.format("%s: x=%f y=%f z=%f", info, vec.x, vec.y, vec.z))
end

-- Calculates grid to give plank side
-- side   give infoelem.tblSides[2]
-- Retruns grid table as "gridnext" gives it but converted to infoelem, nil=vertical element - cannot do.
-- Adds table members vecx and vecy which are the local grid direction vectors with length of grid and (x,y as unit vector,len which is original length). Member angle is global and not converted.
function GridToLocal(side)
  local dummy, grid, pa, pb, pc, pd, has, x1, y1, z1, x2, y2, z2, dx, dy
  
  -- Get grid info and calculate plank positions here ourselves, first decide the direction of the new planks to dx, dy. Convert grid to local coords.
  dummy,dummy,dummy,grid=ac_environment ("gridnext", 0, 0, 1, 0)

  pa,pb,pc,pd = MakePlaneNormal(side.vecz.x, side.vecz.y, side.vecz.z, side.origc.x, side.origc.y, side.origc.z)
--ac_environment("tolog", string.format("Grid origin 3D: pa=%f, pb=%f, pc=%f, pd=%f, x=%f y=%f z=%f", pa, pb, pc, pd, side.origc.x, side.origc.y, side.origc.z))
--DumpVec("side.vecx", side.vecx)
--DumpVec("side.vecy", side.vecy)
--DumpVec("side.vecz", side.vecz)

  -- orig on dest plane
  dx=math.cos(grid.angle) * grid.mainx    -- X-axis
  dy=math.sin(grid.angle) * grid.mainx
  has,x1,y1,z1 = LinePlaneX(pa, pb, pc, pd, grid.x, grid.y, grid.z, grid.x, grid.y, grid.z+1)
  if not has then
    return nil
  end
--ac_environment("tolog", string.format("Grid origin 3D: x=%f y=%f z=%f", x1, y1, z1))
  x1,y1,z1=GlobalToSide(side, x1, y1, z1)
--ac_environment("tolog", string.format("Grid origin local: x=%f y=%f z=%f", x1, y1, z1))
  
  -- x-vector
--ac_environment("tolog", string.format("dx=%f dy=%f grid.angle=%f", dx, dy, grid.angle))
  has,x2,y2,z2 = LinePlaneX(pa, pb, pc, pd, grid.x+dx, grid.y+dy, grid.z, grid.x+dx, grid.y+dy, grid.z+1)
  x2,y2=GlobalToSide(side, x2, y2, z2)
  grid.vecx={}
  grid.vecx.x=x2-x1
  grid.vecx.y=y2-y1
  grid.vecx.len=math.sqrt(grid.vecx.x*grid.vecx.x + grid.vecx.y*grid.vecx.y)
  if grid.vecx.len>0.001 then
    grid.vecx.x=grid.vecx.x / grid.vecx.len
    grid.vecx.y=grid.vecx.y / grid.vecx.len
  end

  -- y-vector to left from x
  dx=math.cos(grid.angle) * grid.mainy    -- Y-axis
  dy=math.sin(grid.angle) * grid.mainy
  has,x2,y2,z2 = LinePlaneX(pa, pb, pc, pd, grid.x-dy, grid.y+dx, grid.z, grid.x-dy, grid.y+dx, grid.z+1)
  x2,y2=GlobalToSide(side, x2, y2, z2)
  grid.vecy={}
  grid.vecy.x=x2-x1
  grid.vecy.y=y2-y1
  grid.vecy.len=math.sqrt(grid.vecy.x*grid.vecy.x + grid.vecy.y*grid.vecy.y)
  if grid.vecy.len>0.001 then
    grid.vecy.x=grid.vecy.x / grid.vecy.len
    grid.vecy.y=grid.vecy.y / grid.vecy.len
  end
  
  grid.x=x1
  grid.y=y1

--ac_environment("tolog", string.format("Grid orig x=%f y=%f, grid.xvecx=%f grid.xvecy=%f grid.yvecx=%f grid.yvecy=%f", grid.x, grid.y, grid.vecx.x, grid.vecx.y, grid.vecy.x, grid.vecy.y))

  return grid
end



function GetDefaults()
    g_matid="block"
    g_thickness=0.050
    g_height=0.100
end


-- Gets value from key=value\n string
function GetVal(data, keyName)
  local k,v

  for k, v in string.gmatch(data, "([^ \r\n]+)=([^\r\n]+)") do
    --ac_environment("tolog", string.format("#%s=%s\n", k, v))
    if k == keyName then
      return v
    end
  end
  return nil
end


function SettingsToStr()
  return string.format("matid=%s\nthickness=%.8f\nheight=%.8f\nside=%.8f", g_matid, g_thickness, g_height, g_side)
end

-- Called with pcall(), sets globals
function ParseSettings(sSettings)
  local s
  
--ac_environment("tolog", string.format("sSettings=%s\n", sSettings) )
  g_matid=GetVal(sSettings, "matid")
  g_thickness=tonumber(GetVal(sSettings, "thickness"))
  g_height=tonumber(GetVal(sSettings, "height"))
  g_side=tonumber(GetVal(sSettings, "side"))

  -- Will cause error if bad syntax
  SettingsToStr()
end


-- sSettings may be nil
-- Sets globals to given values
-- Returns: true=OK clicked, false=canceled
function SettingsDlg(sSettings)
  local tblSettings, bRes, sErr, s, n, strSep, tblSorted, defMat, defMatId
  local tblMat, i, id, v, thickness, height, mat, hasSettings

  hasSettings=false
  GetDefaults()
  if sSettings~=nil and sSettings~="" then
    local err

    hasSettings,err=pcall(ParseSettings, sSettings)
    if not hasSettings then
      GetDefaults()
    end
  end

  -- Build mat list
  tblMat=af_request("matlist")
  
  defMatId=af_request("elem_getstudmat")
  if defMatId==nil then
    defMatId=""
  end
  defMat=1
  tblSorted={}
  for id,v in pairs(tblMat) do
    tblSorted[v.index]=v
    if v.id==defMatId then
      defMat=v.index
    end
  end
 
  s=""
  strSep=""
  for i,v in ipairs(tblSorted) do
    s=string.format("%s%s\"%s:%s (%s)\"", s, strSep, i, v.name, v.id)
    strSep=","
  end
    
  tblSettings={}
  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =1
  tblSettings[1].prompt  ="Material"
  tblSettings[1].key    ="balkmat"
  tblSettings[1].valuelist=s
  tblSettings[1].defvalue  =defMat    -- defvalue instead of value

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type    =3
  tblSettings[2].prompt  ="Thickness (if not fixed)"
  tblSettings[2].key    ="thickness"
  tblSettings[2].defvalue  =g_thickness

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  ="Height (if not fixed)"
  tblSettings[3].key    ="height"
  tblSettings[3].defvalue  =g_height

  tblSettings[4]      ={}
  tblSettings[4].cfgonly =0
  tblSettings[4].type    =1
  tblSettings[4].prompt  ="Position of new pieces relative to the selection"
  tblSettings[4].key    ="side"
  tblSettings[4].valuelist="\"1:To left\",\"2: To right\""
  tblSettings[4].defvalue  =1

  if false then
    -- no way to save settings currently. Just use what ac_optiondlg preserves
    -- Show current setting
    for i=1,#tblSorted do
      if tblSorted[i].id==g_matid then
        tblSettings[1].value=i
        break
      end
    end
    tblSettings[2].value    =g_thickness
    tblSettings[3].value    =g_height
  end

  bRes,sErr=ac_optiondlg("LDSP", "Floor side pieces", tblSettings)
  if not bRes then
    return false
  end

  g_matid=tblSorted[tblSettings[1].value].id
  g_thickness=tblSettings[2].value
  g_height=tblSettings[3].value

  g_side=-1
  if tblSettings[4].value==2 then
    g_side=1
  end

  return true
end


-- Gets the grid vector that is more in direction with dx, dy
-- Returns new copied unit vector and adds new member dir which is 1 if same dir as grid and -1 if opposite
function GetGridVec(grid, dx, dy)
  local x1, y1, x2, y2, cosx, coxy, vecnew

  x1,y1=ToUnit(grid.vecx.x, grid.vecx.y)
  x2,y2=ToUnit(grid.vecy.x, grid.vecy.y)
  cosx=CalcDot(dx, dy, x1, y1)
  cosy=CalcDot(dx, dy, x2, y2)

  vecnew={}
  vecnew.x=x1      -- Default axis for new planks
  vecnew.y=y1
  vecnew.len=grid.vecx.len
  if math.abs(cosx)<math.abs(cosy) then
    vecnew.x=x2    -- Y was better
    vecnew.y=y2
    vecnew.len=grid.vecy.len
    cosx=cosy
  end
  vecnew.dir=1
  if cosx<0 then
    -- Different dir
    vecnew.x=-vecnew.x
    vecnew.y=-vecnew.y
    vecnew.dir=-1
  end
  
  return vecnew
end


function GetSgn(d)
  if d<0 then
    return -1
  end
  return 1
end


-- Cuts plank to existing planks to avoid skipping plank because there is already one
-- tblnew contains x1,y1,x2,y2
function CutToExisting(tblnew)
  local i, v, x, y, dummy, dist, len
  
  if not gtblOld then
    -- Build lines table
    gtblOld={}
    for i=1,gnPlanks do
      ac_objectopen(string.format("#%d", i))
      gtblOld[i]=ac_objectget("#af_elemdata")
      ac_objectclose()
    end
  end
  
  -- Scan lines table
  i=1
  while true do
    v=gtblOld[i]
    if not v then
      break
    end
    i=i+1
    
    x,y = ac_geo("linex", tblnew.x1, tblnew.y1, tblnew.x2, tblnew.y2, v.x1, v.y1, v.x2, v.y2)
    if x then
      -- Intersection, 
      dummy,dist,len=ac_geo("linedist", v.x1, v.y1, v.x2, v.y2, x, y)
      if dist>-0.001 and dist<len+0.001 then
        -- check if in tblnew
        dummy,dist,len=ac_geo("linedist", tblnew.x1, tblnew.y1, tblnew.x2, tblnew.y2, x, y)
        if dist>0.001 and dist<len then
          -- In both lines, make new shorter
          tblnew.x2=x
          tblnew.y2=y
--ac_environment("tolog", string.format("tblnew.x1=%f, tblnew.y1=%f, tblnew.x2=%f, tblnew.y2=%f, v.x1=%f, v.y1=%f, v.x2=%f, v.y2=%f", tblnew.x1, tblnew.y1, tblnew.x2, tblnew.y2, v.x1, v.y1, v.x2, v.y2))
        end
      end
    end
  end
end


-- infoelem Plank info for the element
function DoPlank(infoelem, guid)
  local info, elemdata, dx, dy, d1, len, x, y, grid, vecnew, vecgrid, x1, y1, x2, y2, mm, dummy, cosa, t, t2, offgrid
  
  ac_objectopen(guid)
  info=af_request("plankinfo")
  elemdata=ac_objectget("#af_elemdata")
  ac_objectclose()

  dx,dy,len=ToUnit(elemdata.x2 - elemdata.x1, elemdata.y2 - elemdata.y1)
  if not dx then
    return
  end

  -- Get grid info and calculate plank positions here ourselves, first decide the direction of the new planks to dx, dy. Convert grid to local coords.
  grid=GridToLocal(infoelem.tblSides[2])
  if not grid then
    return
  end
  
  -- Calc plank dir first 90deg to left/right from current plank and direction of the best grid in plank's dir
  vecnew=GetGridVec(grid, g_side * dy, -g_side * dx)
  vecgrid=GetGridVec(grid, dx, dy)
--ac_environment("tolog", string.format("vecnew: x=%f y=%f len=%f vecgrid: x=%f y=%f len=%f", vecnew.x, vecnew.y, vecnew.len,  vecgrid.x, vecgrid.y, vecgrid.len))

  -- Move starting point 1 mm before current starting point
  mm=0.001
  x=elemdata.x1 - mm*dx
  y=elemdata.y1 - mm*dy
  
  cosa=CalcDot(dx, dy, vecgrid.x, vecgrid.y)    -- cos angle between these two vectors, this is always positive since vecrid is selected to be in plank's dir

--ac_environment("tolog", string.format("math.fmod(-2.2, 1)=%f, math.fmod(2.2, 1)=%f", math.fmod(-2.2, 1), math.fmod(2.2, 1)))

  -- Then process in grid's direction until we are outside the line
  while true do
    -- Advance to the next grid line, calc distance from current pos x,y to the grid origin in vecgrid dir
    x1=x - grid.x
    y1=y - grid.y

    offgrid=CalcDot(vecgrid.x, vecgrid.y, x1, y1) * vecgrid.dir     -- Keep sign of original grid direction
    d1=math.abs(offgrid)
--ac_environment("tolog", string.format("1: d1=%f offgrid=%f vecgrid.dir=%f", d1, offgrid, vecgrid.dir))
    d1=math.fmod(d1, vecgrid.len)
    if GetSgn(vecgrid.dir)*GetSgn(offgrid)>0 then
      d1=vecgrid.len-d1
    end
--ac_environment("tolog", string.format("2: d1=%f, cosa=%f len=%f dx=%f dy=%f vecgrid.len=%f x=%f y=%f", d1, cosa, len, dx, dy, vecgrid.len, x, y))
    
    -- Convert distance to the plank's line
    d1=d1/cosa
    x=x + dx*d1
    y=y + dy*d1

    dummy,d1=ac_geo("linedist", elemdata.x1, elemdata.y1, elemdata.x2, elemdata.y2, x, y)
    if d1>len+mm then
      break
    end

    t={}
    t.guidsettings=info.ptr
    t.group="sideleft_spacing"
    if g_side>0 then
      t.group="sideright_spacing"
    end
      
    t.x1=x
    t.y1=y
    t.x2=x + 2 * vecnew.x     -- Make it 2 meters long (will be trimmed to the first collision)
    t.y2=y + 2 * vecnew.y
    CutToExisting(t)

    t.id=g_matid
    t2=af_request("singlemat", t.id)
    if not t2 then
      ac_environment("tolog", string.format("ERROR, MATERIAL %s IS MISSING", t.id))
      return
    end
    
    t.thickness=g_thickness
    t.height=g_height
    if t2.thickness>0 then
      t.thickness=t2.thickness
      t.height=t2.height
    end
      
    t.rotAngle=0
    t.zoff=0
    --t.force=3

    --t.xmlsettings="<s>" ..  xmlSettings .. "</s>"

    gnPlankCount=gnPlankCount+1
    gtblCreate[gnPlankCount] = t

    -- To half of next grid
    x=x + dx * vecgrid.len * 0.5 / cosa
    y=y + dy * vecgrid.len * 0.5 / cosa
    
    -- Add xml-operations to be run after new planks are initialized
    gxmlOperations=gxmlOperations .. string.format("<jointo target=\"#%d\" operator=\"*\">\n" ..
                "    <cut jointgap=\"0.000\" extendmaxlen=\"0.000\" removepart=\"between\"></cut>\n" ..
                "</jointo>\n", gnPlanks+gnPlankCount)
  end
end


-- infoelem Plank info for the element
function AddPlanksToSel(infoelem)
  local tblSel, i, v

  tblSel=af_request("getselplanks")
  if not tblSel then
    ac_msgbox("Please select the target planks first.")
    return
  end
  
  for i,v in pairs(tblSel) do
    DoPlank(infoelem, v)
  end
end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return -1			-- This is set only
end


-- Called when user clicks the button
function Set(sSettings)
  local tblPolys, k, v
  local infoPlank, infoElem
  
  gnPlankCount=0
  gtblCreate = {}
  gtblOld=nil
  
  -- First get the owning element from the first plank
  ac_objectopen("#1")
  infoPlank=af_request("plankinfo")
  ac_objectclose()
  
  if not infoPlank.ownerelemguid then
    error("No owner element - cannot proceed.")   -- Should never happen
  end
  
  infoElem=af_request("plankinfo", infoPlank.ownerelemguid)
  if not infoElem then
    error("plankinfo")   -- Should never happen
  end

  infoElem.vecz,infoElem.vecy=infoElem.vecy,infoElem.vecz   -- swap
--ac_environment("tolog", string.format("ELEM begc=%f %f %f vecx=%f %f %f vecy=%f %f %f vecz=%f %f %f", infoElem.begc.x, infoElem.begc.y, infoElem.begc.z, infoElem.vecx.x, infoElem.vecx.y, infoElem.vecx.z, infoElem.vecy.x, infoElem.vecy.y, infoElem.vecy.z, infoElem.vecz.x, infoElem.vecz.y, infoElem.vecz.z))

  if math.abs(infoElem.vecz.z)<0.001 then
    ac_environment("ERROR: Vertical elements not supported")
    return
  end

  -- For button we don't have settings that ArchiFrame manages - just the ones for ac_optiondlg
  GetDefaults()
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end
  
  if not SettingsDlg(sSettings) then
    return
  end

  gxmlOperations=""
  AddPlanksToSel(infoElem)
  
  if gxmlOperations~="" then
    gxmlOperations=string.format("<operations>\n%s</operations>", gxmlOperations)
  end
  
  af_request("elem_createplanks")   -- Create gtblCreate-planks
end


-- Used only for checkbox option, unused
function Reset()
	return false
end
]]>
        </script>


        <!-- DIM SCRIPTS BEG -->
        <script id="dim_wallsect">
          <![CDATA[
-- Returns cos angle of the vectors if normalized
function CalcDot3D( x1, y1, z1, x2, y2, z2 )
	return x1 * x2 + y1 * y2 + z1 * z2;
end

function GetLang()
  local lang
  
  lang=af_request("aflang")
  if lang==nil then
    lang="eng"
  end
  return lang
end

function IsCoreBottom(elemgroup)
  return string.match(elemgroup, "^bottom_force.*") or string.match(elemgroup, "^2ndbottom_force.*")
end

function IsCoreTop(elemgroup)
  return string.match(elemgroup, "^top_force.*") or string.match(elemgroup, "^2ndtop_force.*")
end

function GetNameForTypetag(typetag)
  local lang=GetLang()
  local name=typetag

  if lang=="fin" then
    if string.match(typetag, "^finish_int.*") then
      name="VERH"
    elseif string.match(typetag, "^intstud.*") then
      name="KOOL"
    elseif string.match(typetag, "^boarding_int.*") then
      name="LEVY"
    elseif string.match(typetag, "^core.*") then
      name="RUNKO"
    elseif string.match(typetag, "^boarding_ext.*") then
      name="LEVY"
    elseif string.match(typetag, "^extstud.*") then
      name="KOOL"
    elseif string.match(typetag, "^finish_ext.*") then
      name="VERH"
    end
  elseif lang=="nor" then    
    if string.match(typetag, "^finish_int.*") then
      name="PANEL"
    elseif string.match(typetag, "^intstud.*") then
      name="PÅFORING"
    elseif string.match(typetag, "^boarding_int.*") then
      name="PLATE"
    elseif string.match(typetag, "^core.*") then
      name="KJERNE"
    elseif string.match(typetag, "^boarding_ext.*") then
      name="PLATE"
    elseif string.match(typetag, "^extstud.*") then
      name="LEKT"
    elseif string.match(typetag, "^finish_ext.*") then
      name="KLEDING"
    end
  else
    if string.match(typetag, "^finish_int.*") then
      name="PANEL"
    elseif string.match(typetag, "^intstud.*") then
      name="STUD"
    elseif string.match(typetag, "^boarding_int.*") then
      name="BOARD"
    elseif string.match(typetag, "^core.*") then
      name="CORE"
    elseif string.match(typetag, "^boarding_ext.*") then
      name="BOARD"
    elseif string.match(typetag, "^extstud.*") then
      name="STUD"
    elseif string.match(typetag, "^finish_ext.*") then
      name="CLADD"
    end
  end

  return name
end


-- Gives plank's y-coord in camera y-axis
function GetCamY1(tblCam,info)
  local x,y,z
  
  x=info.begc.x-tblCam.begc.x
  y=info.begc.y-tblCam.begc.y
  z=info.begc.z-tblCam.begc.z
  return CalcDot3D(x, y, z, tblCam.vecy.x, tblCam.vecy.y, tblCam.vecy.z)
end


-- Picks all horizontal pieces from layer typetag (core/intstud/intstud2 etc)
-- Returns:
-- 1. table of dim points
-- 2. true/false if there was any other planks than core
function FindHorPieces(typetag)
  local i, s, n, z, info, a
  local tblRes, tbl, elemdata, tblVertx, nvertx, hasValidDimPts, isCoreOnly
  local tblCoreOthers, ncoreothers
  local tblCoreBot, tblCoreTop, incDim
  local tblCam=af_request("dim_camera")     -- Use camera to judge if piece is horizontal or not


  isCoreOnly=(typetag=="core")
  hasValidDimPts=isCoreOnly
  tblRes={}
  n=0
  tblVertx={}       -- Collect vertical_x to be able to guess which one is lower and which upper
  nvertx=0
  tblCoreOthers={}  -- Add these to nvertx if we have nothing (probably floor structure etc)
  ncoreothers=0
  for i=1,gnPlanks do
    tbl=nil
    ac_objectopen(string.format("#%d",i))
    info=af_request("plankinfo")
    incDim=ac_objectget("iIncludeDim")
    if not incDim then
      incDim=1
    end
    
    a=CalcDot3D(tblCam.vecz.x, tblCam.vecz.y, tblCam.vecz.z, info.vecx.x, info.vecx.y, info.vecx.z)
    if info.type==1 and math.abs(a)>0.999 and incDim~=0 then
      elemdata=ac_objectget("#af_elemdata")
      s=ac_objectget("iElemGroup")
      if elemdata and s then
        if elemdata.typetag=="core" then
          if IsCoreBottom(s) then
            tbl={}
            tbl.index=i
            tbl.anchorfirst=1
            tbl.anchormid=0
            tbl.anchorlast=0
            tbl.elemgroup=s           -- Need to know if it is bottom_force or 2ndbottom_force
            if isCoreOnly then
              tbl.anchorlast=1
            else
              -- Pick just lowest part (in camera y-dir)
              tbl.info=info

              if gSect2ndBottom then
                -- Lindal 8/2023, skip bottom_force
                if not tblCoreBot or (s==tblCoreBot.elemgroup and GetCamY1(tblCam,info)<GetCamY1(tblCam,tblCoreBot.info)) or (tblCoreBot.elemgroup=="bottom_force" and s~="bottom_force") then
                  tblCoreBot=tbl
                end
              elseif not tblCoreBot or GetCamY1(tblCam,info)<GetCamY1(tblCam,tblCoreBot.info) then
                tblCoreBot=tbl
              end
              tbl=nil
            end
          elseif IsCoreTop(s) then
            tbl={}
            tbl.index=i
            tbl.anchormid=0
            tbl.anchorlast=1
            if isCoreOnly then
              tbl.anchorfirst=1
            else
              -- Pick just lowest part (in camera y-dir)
              tbl.info=info
              if not tblCoreTop or GetCamY1(tblCam,info)>GetCamY1(tblCam,tblCoreTop.info) then
                tblCoreTop=tbl
              end
              tbl=nil
            end
          elseif string.match(s, "^vertical_x.*") then
            -- Just save horizontal opening pieces
            local t
            
            t={}
            t.index=i
            t.elemdata=elemdata
            nvertx=nvertx+1
            tblVertx[nvertx]=t
          else
            -- It is in camera's watching direction, perhaps a top balk
            local t
            
            t={}
            t.index=i
            t.elemdata=elemdata
            ncoreothers=ncoreothers+1
            tblCoreOthers[ncoreothers]=t
          end
        elseif not isCoreOnly and elemdata.typetag==typetag then
          -- Add all bottoms of vertical pieces
          tbl={}
          tbl.index=i
          tbl.anchorfirst=1
          tbl.anchormid=0
          tbl.anchorlast=0
          hasValidDimPts=true
        end
      end
      if tbl then
        n=n+1
        tblRes[n]=tbl
      end
    end
    ac_objectclose()
  end
  
  if tblCoreBot then
    n=n+1
    tblRes[n]=tblCoreBot
  end

  if tblCoreTop then
    n=n+1
    tblRes[n]=tblCoreTop
  end
  
  if (not tblCoreBot or not tblCoreTop) and nvertx==0 and ncoreothers>0 then
    for i=1,ncoreothers do
      nvertx=nvertx+1
      tblVertx[nvertx]=tblCoreOthers[i]
    end
  end

  if nvertx>0 then
    -- Sort horizontal window/door pieces, highest first
	  table.sort(tblVertx, function (n1, n2)
      return n1.elemdata.y1 > n2.elemdata.y1
	  end)
    
    i=1
    while i<=nvertx do
      if nvertx-i>=1 then
        -- Assume first is win top and second window bottom
        tbl={}
        tbl.index=tblVertx[i].index
        tbl.anchorfirst=1
        tbl.anchormid=0
        tbl.anchorlast=0
        if isCoreOnly then
          tbl.anchorlast=1
        end
        n=n+1
        tblRes[n]=tbl

        tbl={}
        tbl.index=tblVertx[i+1].index
        tbl.anchorfirst=0
        if isCoreOnly then
          tbl.anchorfirst=1
        end
        tbl.anchormid=0
        tbl.anchorlast=1
        n=n+1
        tblRes[n]=tbl
        i=i+2
      else
        -- Assume door top
        tbl={}
        tbl.index=tblVertx[i].index
        tbl.anchorfirst=1
        tbl.anchormid=0
        if isCoreOnly then
          tbl.anchorlast=1
        end
        n=n+1
        tblRes[n]=tbl
        i=i+1
      end
    end
  end
  
  return tblRes, hasValidDimPts
end


function MakeTextXml(content, textid)
  local s
  
  s=   "<text content=\"" .. content .. "\" textid=\"" .. textid .. "\" anchor=\"6\" marg=\"0.2\">\n"
  s=s.."  <elemparam name=\"pen\">1</elemparam>\n"
  s=s.."  <elemparam name=\"fontname\">arial</elemparam>\n"
  s=s.."  <elemparam name=\"fontsize\">1.5</elemparam>\n"
  s=s.."  <elemparam name=\"fontstyle\"></elemparam>\n"
  s=s.."  <layer></layer>\n"
  s=s.."</text>\n"
  return s
end


-- Makes dim line for horizontal pieces
-- dMargin is number: 0.2/0.15
-- Returns new ndims
function AddHorPieces(tblDims, ndims, typetag, dimSide, dMargin, dimdir)
  local t, s, name, hasStud

  name=GetNameForTypetag(typetag)
  s=string.format("<dimline side=\"%s\" margin=\"%0.2f\" %s %s>\n", dimSide, dMargin, dimdir, gDimExtraAttr)
  s=s..MakeTextXml(name, string.format("projid*20+%d", ndims))
  s=s..gDimExtraSettings
  s=s.."</dimline>"
  t={}
  t.xmldim=s
  t.dimpoints,hasStud=FindHorPieces(typetag)
  if hasStud then
    ndims=ndims+1
    tblDims[ndims]=t
  end
  return ndims
end


function AddSectionTblVert(tblSect,tblRes,n)
  local i,v,t
  
  for i,v in ipairs(tblSect) do
    t={}
    t.x=v.bottom_minx
    t.y=v.bottom_miny
    n=n+1
    tblRes[n]=t
    
    t={}
    t.x=v.top_minx
    t.y=v.top_miny
    n=n+1
    tblRes[n]=t
  end
  return n
end


function SortDimSectVert(tbl)
	  table.sort(tbl, function (n1, n2)
      return n1.bottom_miny < n2.bottom_miny
	  end)
end


-- Finds dimension points for layer size and offsets to core
function FindLayerSizeAndOff(tblCore, tblDims, ndims, sCurrLayer, sXmlDimLine, sDimText, dimdir)
  local tblCurr
  local nmain, tblMain, t, s, tblExtra, nextra
  
  t={}
  if gSect2ndBottom then
    t.skipbottom=1
  end

  tblCurr=af_request("dim_section", sCurrLayer, t)
  SortDimSectVert(tblCurr)
  if #tblCurr==0 then
    -- No such layer now
    return ndims
  end

  -- Add points from curr layer and create additional offset dim points if needed
  local icore, icurr, vcore, vcurr, vfound
  
  -- This is the main dim line for this layer, only coords
  tblMain={}
  nmain=0
  
  -- Additional dim lines after the main on same x-coord
  tblExtra={}
  nextra=0
  
  -- Find closest core points for each current layer's segments
  for icurr,vcurr in ipairs(tblCurr) do
    -- Find overlapping core segment
    vfound=nil
    for icore,vcore in ipairs(tblCore) do
      if vcore.top_miny>vcurr.bottom_miny and vcore.bottom_miny<vcurr.top_miny then
        -- Found overlap, take it
        vfound=vcore
        break
      end
    end

    -- Always add current layer min&max (ok if not sorted now)
    t={}
    t.x=vcurr.bottom_minx
    t.y=vcurr.bottom_miny
    nmain=nmain+1
    tblMain[nmain]=t

    t={}
    t.x=vcurr.top_minx
    t.y=vcurr.top_miny
    nmain=nmain+1
    tblMain[nmain]=t

    if vfound==nil then
      -- No related core segment, anything below?
      
      -- Anything above?
    else
      if vfound.bottom_miny<vcurr.bottom_miny then
        -- Core min below curr layer min, add to main dim line
        t={}
        t.x=vfound.bottom_minx
        t.y=vfound.bottom_miny
        nmain=nmain+1
        tblMain[nmain]=t
      else
        -- Core bottom above curr bottom, add extra line
        local t2
        
        t2={}
        t={}
        t.x=vcurr.bottom_minx
        t.y=vcurr.bottom_miny
        t2[1]=t
        
        t={}
        t.x=vfound.bottom_minx
        t.y=vfound.bottom_miny
        t2[2]=t
       
        nextra=nextra+1
        tblExtra[nextra]=t2
      end
      
      if vfound.top_miny+0.0004>vcurr.top_miny then
        -- Core max above curr layer max, add to main dim line
        t={}
        t.x=vfound.top_minx
        t.y=vfound.top_miny
        nmain=nmain+1
        tblMain[nmain]=t
      else
        -- Core top below curr top, add extra line
        local t2
        
        t2={}
        t={}
        t.x=vfound.top_minx
        t.y=vfound.top_miny
        t2[1]=t
        
        t={}
        t.x=vcurr.top_minx
        t.y=vcurr.top_miny
        t2[2]=t
       
        nextra=nextra+1
        tblExtra[nextra]=t2
      end
    end
  
  end

  s=sXmlDimLine .. "\n"
  s=s..MakeTextXml(sDimText, string.format("projid*20+%d", ndims))
  s=s..gDimExtraSettings
  s=s.."</dimline>"
  t={}
  t.xmldim=s
  t.dimpoints=tblMain

  ndims=ndims+1
  tblDims[ndims]=t
  
  -- Add all extra dim lines to the same x-coordinate (just first one having margin)
  local smarg, s1, s2, dummy
  
  smarg="0.1"
  for icurr,vcurr in ipairs(tblExtra) do
    -- sXmlDimLine is something like "<dimline side=\"left\" margin=\"0.3\" elemvecy=\"1\">", we want to set first margin to 0.25 and rest to 0
    dummy,dummy,s1,s2=string.find(sXmlDimLine, "(.*) margin=\".-\"(.*)")
    s=string.format("%s margin=\"%s\"%s", s1, smarg, s2)
--ac_environment("tolog", string.format("s1=%s s2=%s s=%s #vcurr=%d", s1, s2, s, #vcurr))
    
    smarg="0"
    s=s .. "</dimline>"
    t={}
    t.xmldim=s
    t.dimpoints=vcurr

    ndims=ndims+1
    tblDims[ndims]=t
  end
  return ndims
end


-- Returns two values: x1, x2
function FindX(tblSection)
  local i, v, x1, x2
  
  v=tblSection[1]
  x1=v.left_minx
  x2=v.right_minx
  i=2
  while true do
    v=tblSection[i]
    if v==nil then
      break
    end
    if x1>v.left_minx then
      x1=v.left_minx
    end
    if x2<v.right_minx then
      x2=v.right_minx
    end
    i=i+1
  end
  return x1,x2
end


-- Scans all planks and makes table of layers
-- Returns multiple values (nil if core not found):
-- 1st: 1-based table of layers sorted by camera x-coordinate. Each item has fields:
--   typetag    core/intstud etc.
--   elem.q     elem_quantities for the layer
-- 2nd: index to core layer
-- 3rd: elemvecy="1" etc (whatever axis matches camera's y)
function FindElemLayers(tblCam)
  local i
  local tbl
  local typetag, info
  local tblLayers                       -- key=element layer typetag, data: elem is the owner element ; parts beg and end each having fields: index, elemdata
  
  tblLayers={}
  for i=1,gnPlanks do
    ac_objectopen(string.format("#!%d",i))    -- Open related master plank
    info=af_request("plankinfo")
    typetag=nil
    tbl=ac_objectget("#af_elemdata")   -- To get typetag also
    if tbl then
      typetag=tbl.typetag
    end
    ac_objectclose()
    
    if typetag then
      tbl=tblLayers[typetag]
      if tbl==nil then
        -- Construct info for this layer
        tbl={}
        tbl.elem={}
        tbl.elem.q=af_request("elem_quantities", info.ownerelemguid, 0)
        tblLayers[typetag]=tbl
      end
    end
  end
  
  tblCore=tblLayers["core"]
  if tblCore==nil then
    return nil
  end

  -- Collect all layers and sort by distance from core layer to put dim lines in order
  local tblLayersSort, k, v, x, y, z
  
  tblLayersSort={}
  i=0
  for k,v in pairs(tblLayers) do
    i=i+1
    tblLayersSort[i]=v
    tblLayersSort[i].typetag=k

    x=v.elem.q.geo.orig.x - tblCore.elem.q.geo.orig.x
    y=v.elem.q.geo.orig.y - tblCore.elem.q.geo.orig.y
    z=v.elem.q.geo.orig.z - tblCore.elem.q.geo.orig.z
    tblLayersSort[i].dist=CalcDot3D(tblCam.vecx.x, tblCam.vecx.y, tblCam.vecx.z, x, y, z)
--ac_environment("tolog", string.format("%s, dist=%f", k, tblLayersSort[i].dist))
  end

  table.sort(tblLayersSort, function (n1, n2)
    return n1.dist<n2.dist
  end)

  -- Find core (always found)
  local coreInd
  
  for i,v in ipairs(tblLayersSort) do
    if v.typetag=="core" then
      coreInd=i
      break
    end
  end
  
  local sdim
  
  sdim="elemvecy=\"1\""
  if math.abs(CalcDot3D(tblCore.elem.q.geo.vecx.x, tblCore.elem.q.geo.vecx.y, tblCore.elem.q.geo.vecx.z, tblCam.vecy.x, tblCam.vecy.y, tblCam.vecy.z))>0.999 then
    sdim="elemvecx=\"1\""
  elseif math.abs(CalcDot3D(tblCore.elem.q.geo.vecz.x, tblCore.elem.q.geo.vecz.y, tblCore.elem.q.geo.vecz.z, tblCam.vecy.x, tblCam.vecy.y, tblCam.vecy.z))>0.999 then
    sdim="elemvecz=\"1\""
  end
  
  return tblLayersSort, coreInd, sdim
end


function DoSectDimLayer(vlayer, side, marg, tblDims, ndims, tblCore, dimdir)
  local name, s

  s=vlayer.elem.q.tblelems[1].templateid
  name=GetNameForTypetag(vlayer.typetag)
  if vlayer.typetag=="core" or not s or string.match(s, "airstrips_hor") or string.match(s, "^framinghor.*") or string.match(s, "^framing_hor.*") or string.match(s, "^horpanel.*") then
    ndims=AddHorPieces(tblDims, ndims, vlayer.typetag, side, marg, dimdir)
  else
    ndims=FindLayerSizeAndOff(tblCore, tblDims, ndims, vlayer.typetag, string.format("<dimline side=\"%s\" margin=\"%0.2f\" %s %s>", side, marg, dimdir, gDimExtraAttr), name)
  end
    
  return ndims
end


-- Creates all dim lines for section
-- spaceL,R if given, tells how much space is needed to left/right hand side of the dim line, default L=0.2, r=0.1
-- spaceDims How much to leave between dim lines
-- specClad If given, special dimension lines for cladding:
--          1=Lindal rules: at core the anchor is at the bottom of second bottom plate (if two), not implemented: and if horizontal cladding put dimension to the first plank above that
-- gSect2ndBottom Global set to true to skip bottom_force if there is 2ndbottom_force
function SectDimLines(strExtraSettings, strExtraAttr, spaceL, spaceR, spaceDims, specClad)
  local tblDims, ndims, name, tblCore
  local tblLayers, coreInd, nLayers, nleft, i, marg, v, dimdir
  local tblCam=af_request("dim_camera")
  
  if not spaceL then
    spaceL=0.2
    spaceR=0.1
    spaceDims=0.15
  end
  
  gDimExtraSettings=""
  if strExtraSettings then
    gDimExtraSettings=strExtraSettings
  end
  gDimExtraAttr=""
  if strExtraAttr then
    gDimExtraAttr=strExtraAttr
  end
  
  gSpecClad=0
  if specClad then
    gSpecClad=specClad
  end

  -- Get table of all layers in our composite
  tblLayers,coreInd,dimdir=FindElemLayers(tblCam)
  nLayers=#tblLayers

  -- Get core section
  t={}
  if gSect2ndBottom then
    t.skipbottom=1
  end
  
  tblCore=af_request("dim_section", "core", t)
  SortDimSectVert(tblCore)

  -- Add dim lines 
  ndims=0
  tblDims={}

  nleft=coreInd-1
  if nLayers-coreInd>nleft then
    nleft=coreInd     -- Core dim to the left side
  end

  marg=spaceR
  i=nleft
  while i>0 do
    ndims=DoSectDimLayer(tblLayers[i], "left", marg, tblDims, ndims, tblCore, dimdir)
    i=i-1
    marg=spaceDims
  end

  marg=spaceL
  i=nleft+1
  while i<=nLayers do
    ndims=DoSectDimLayer(tblLayers[i], "right", marg, tblDims, ndims, tblCore, dimdir)
    i=i+1
    marg=spaceDims
  end
  
  -- Max height
  local t={}
  if gSect2ndBottom then
    t.skipbottom=1
  end

  local tblSect=af_request("dim_section", "*", t)
  local botx,boty, topx,topy
  
  for i,v in ipairs(tblSect) do
    if not boty or v.bottom_maxy<boty then
      botx=v.bottom_maxx
      boty=v.bottom_maxy
    end
      
    if not topy or v.top_maxy>topy then
      topx=v.top_maxx
      topy=v.top_maxy
    end
  end

  if botx then
    s=string.format("<dimline side=\"right\" margin=\"%0.2f\" %s %s>\n", marg, dimdir, gDimExtraAttr)
    s=s..gDimExtraSettings
    s=s.."</dimline>"
    t={}
    t.xmldim=s
    t.dimpoints={}
    
    v={}
    v.x=botx
    v.y=boty
    t.dimpoints[1]=v
--ac_environment("tolog", string.format("1: v.x=%s v.y=%s", tostring(v.x), tostring(v.y)))
    v={}
    v.x=topx
    v.y=topy
    t.dimpoints[2]=v
--ac_environment("tolog", string.format("2: v.x=%s v.y=%s", tostring(v.x), tostring(v.y)))

    ndims=ndims+1
    tblDims[ndims]=t
  end

  return tblDims
end


-- Dim lines cumulative (Scandicc uses)
function SectDimLinesCum()
  --return SectDimLines("<dimlinesettings><elemparam name=\"dimensiontype\">cumulative</elemparam><elemparam name=\"markertype\">5</elemparam></dimlinesettings>", " textrot=\"0.001\"", 0.1, 0.4, 0.4)
  return SectDimLines("<dimlinesettings><elemparam name=\"dimensiontype\">cumulative</elemparam><elemparam name=\"markertype\">5</elemparam></dimlinesettings>", nil, 0.35, 0.1, 0.15)
end

]]>
        </script>
        <!-- DIM SCRIPTS END-->
      </scripts>
    </settings>

    <elemtypes>
      <elemtype class="wall" id="WALL 100 C/C 600" idstamp="50x100">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
            <objparam name="iShowElemType">0</objparam>
          </newelem>

          <newelemplank>
            <objparam name="iShowID3D">0</objparam>
          </newelemplank>

          <newelemprojside>
          </newelemprojside>
        </settings>

        <layers>
          <layer name="Core" visible="1" thickness="0.100" type="core" anchorname1="Core out" anchorname2="Core in">

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->

            <!-- bottom wood -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="50x100" zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="50x100" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="0.6" spacingtolerance="0.01">
              <material id="50x100" zoff="0" rotangle="0"></material>
            </planks>
            
            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="50x100" zoff="0" rotangle="0"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to tilted openings -->
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- groove operator is the piece that makes the groove, target is here the the piece that gets the groove -->
              <groove target="vertical_y*|vertical_spacing|vertical_force" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove>
              <!--markingto target="vertical*" operator="bottom*" type="lines_sides" text=""></markingto>-->
            </operations>

          </layer>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>


      <elemtype class="wall" id="WALL 173 K600" idstamp="42x173">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
            <elemparam name="pen">1</elemparam>
          </newelem>

          <newelemplank>
          </newelemplank>

          <newelemprojside>
          </newelemprojside>
        </settings>

        <!-- Could set some options on here as default, settings may be given in side <option>settings</option> and format depends on the option -->
        <!--options>
          <option id="openingsides">
            <![CDATA[
mat=block
thickness=0.050
height=0.173
]]>
          </option>
        </options-->

        <layers>
          <layer name="Core" visible="1" thickness="0.173" type="core" anchorname1="Core out" anchorname2="Core in">

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->

            <!-- bottom wood -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="42x173" zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="42x173" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="0.6" spacingtolerance="0.01">
              <material id="42x173" zoff="0" rotangle="0"></material>
              <force_nope>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="0.141" extend="1"></parallel>
                <parallel x2off="-0.141" extend="1"></parallel>
              </force_nope>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="42x173" zoff="0" rotangle="0"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to tilted openings -->
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_y*|vertical_spacing|vertical_force" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- groove operator is the piece that makes the groove, target is here the the piece that gets the groove -->
              <groove target="vertical_y*|vertical_spacing|vertical_force" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove>
              <!--markingto target="vertical*" operator="bottom*" type="lines_sides" text=""></markingto>-->
            </operations>

          </layer>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>


      <elemtype class="wall" id="WALL 42x42 HOR" idstamp="42x42">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
          </newelem>

          <newelemplank>
          </newelemplank>

          <newelemprojside>
          </newelemprojside>
        </settings>

        <layers>
          <layer name="Core" visible="1" thickness="0.042" type="core" anchorname1="Out" anchorname2="In">

            <!-- Top/bottom -->
            <planks group="bottom" axis="y" skipaxis="1">
              <material id="42x42" zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="y" skipaxis="1">
              <material id="42x42" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->
            <planks group="vertical" axis="x" opening_parallel="1" opening_normal="1" spacing="0.6" spacingtolerance="0.01">
              <material id="42x42" zoff="0" rotangle="0"></material>
              <force_unused>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="0.141" extend="1"></parallel>
                <parallel x2off="-0.141" extend="1"></parallel>
              </force_unused>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="0">
              <material id="42x42" zoff="0" rotangle="0"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_y|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to tilted openings -->
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- groove operator is the piece that makes the groove, target is here the the piece that gets the groove -->
              <groove target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove>
              <!--markingto target="vertical*" operator="bottom*" type="lines_sides" text=""></markingto>-->
            </operations>

          </layer>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>


      <elemtype class="wall" id="WALL 42x42 VERT" idstamp="42x42">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
            <objparam name="iShowElemType">0</objparam>
          </newelem>

          <newelemplank>
            <objparam name="iShowID3D">0</objparam>
          </newelemplank>

          <newelemprojside>
          </newelemprojside>
        </settings>

        <layers>
          <layer name="Core" visible="1" thickness="0.042" type="core" anchorname1="Core out" anchorname2="Core in">

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->

            <!-- bottom wood -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="42x42" zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="42x42" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="0.6" spacingtolerance="0.01">
              <material id="42x42" zoff="0" rotangle="0"></material>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="42x42" zoff="0" rotangle="0"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to tilted openings -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- groove operator is the piece that makes the groove, target is here the the piece that gets the groove -->
              <groove target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove>
              <!--markingto target="vertical*" operator="bottom*" type="lines_sides" text=""></markingto>-->
            </operations>

          </layer>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>

      
      <!-- MULTILAYER BEG -->

      <!-- Used only as part of other elements -->
      <elemtype class="wall" id="GYPSUM 9" idstamp="BOARD 9" tolist="0" density="1.1">
        <!-- Default settings for this element type -->
        <layers>
          <boarding thickness="0.009" type="core" anchorname1="Out" anchorname2="In">
            <board id="GYP 1200x2600x9" name="GYP 1200x2600x9" name_fin="Kipsi 1200x2600x9" width="1.2" height="2.6"></board>
            <!-- cost is slightly higher than area 0.6*2.6=1.56 -->
            <board id="GYP 600x2600x9" name="GYP 600x2600x9" name_fin="Kipsi 600x2600x9" width="0.6" height="2.6" cost="1.8"></board>
		  </boarding>
        </layers>
      </elemtype>

      <!-- Used only as part of other elements -->
      <elemtype class="wall" id="GYPSUM 13" idstamp="BOARD 13" tolist="0" density="1.1">
        <!-- Default settings for this element type -->
        <layers>
          <boarding thickness="0.013" type="core" anchorname1="Out" anchorname2="In">
            <board id="GYP 1200x2600x13" name="GYP 1200x2600x13" name_fin="Kipsi 1200x2600x13" width="1.2" height="2.6"></board>
            <!-- cost is slightly higher than area 0.6*2.6=1.56 -->
            <board id="GYP 600x2600x13" name="GYP 600x2600x13" name_fin="Kipsi 600x2600x13" width="0.6" height="2.6" cost="1.8"></board>
          </boarding>
        </layers>
      </elemtype>

      <!-- Multilayer element -->
      <elemtype class="wall" id="WALL 173+42 VERT" idstamp="173+42">
        <settings>
          <masterelem>
            <objparam name="iShowElemType">1</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <layers>
          <!-- spacepre=empty space before the layer (for unmodeled parts of the structure) -->
          <boarding ref="GYPSUM 9" anchorname1="Windshield ext" anchorname1_fin="Tuulensuoja ulko" type="boarding_ext" studs="core" spacepre="0">
          </boarding>
          <layer ref="WALL 173 K600" anchorname1="Core ext" anchorname2="Core int" anchorname1_fin="Runko ulko" anchorname2_fin="Runko sisä" type="core">
          </layer>
          <layer ref="WALL 42x42 VERT" anchorname2="Inner studding int" anchorname2_fin="Sisäkoolaus sisä" studs="core" type="intstud">
          </layer>
          <boarding ref="GYPSUM 13" anchorname2="Boarding int" anchorname2_fin="Levytys sisä" type="boarding_int" studs="intstud" spacepre="0">
          </boarding>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="boarding_ext" exclude="intstud,extstud">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1" boardpanels="boarding_int,boarding_ext">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <projection type="back" layoutmargins="2,0.5,0,1" boardpanels="boarding_int" exclude="core,extstud">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

      </elemtype>



      <!-- Full panel wall -->
      <elemtype class="wall" id="PANEL_HOR_OUTIN" idstamp="PANEL_HOR_OUTIN" tolist="0" density="0.5">
        <!-- Default settings for this element type -->
        <settings>
          <newelemboard>
            <layer>AF Panel</layer>
          </newelemboard>
          <newelemboardprojside>
            <objparam name="iFill">0</objparam>
          </newelemboardprojside>
        </settings>
        <layers>
          <boarding thickness="0.023" type="core" anchorname2="Paneling ext">
            <board panelingref="PANEL_HOR_OUTIN" width="9999" height="9999" >
            </board>
          </boarding>
        </layers>
      </elemtype>

      <!-- External studding -->
      <elemtype class="wall" id="STUDDING20" tolist="0" density="0">
        <layers>
          <layer name="Core" visible="1" thickness="0.020" type="core" anchorname1="Core out" anchorname2="Core in">
            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="0" spacing="0.6" spacingtolerance="0.01">
              <material id="20x70" zoff="mat_thickness*0.5" rotangle="90"></material>
            </planks>
          </layer>
        </layers>
      </elemtype>


      <elemtype class="wall" id="WALL 173+42 PANEL OUTIN" idstamp="173+42">
        <settings>
          <masterelem>
            <objparam name="iShowElemType">1</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Default element weights for this type -->
        <elemweight>
          <bools calc="0" door="1" win="1"></bools>
          <floats framingkg="400" boardingkg="1150" insulationkg="35" doorm2kg="10" doorframekg="4" winm2kg="15" winframekg="4"></floats>
        </elemweight>

        <layers>
          <boarding ref="PANEL_HOR_OUTIN" anchorname1="Exterior finishing ext" anchorname1_fin="Panelointi ulko" type="finish_ext" studs="extstud" spacepre="0">
          </boarding>
          <layer ref="STUDDING20" anchorname1="Exterior studding ext" anchorname1_fin="Ulkokoolaus ulko" studs="core" type="extstud">
          </layer>
          <boarding ref="GYPSUM 9" anchorname1="Windshield ext" anchorname1_fin="Tuulensuoja ulko" type="boarding_ext" studs="core" spacepre="0">
          </boarding>
          <layer ref="WALL 173 K600" anchorname1="Core ext" anchorname2="Core int" anchorname1_fin="Runko ulko" anchorname2_fin="Runko sisä" type="core">
          </layer>
          <layer ref="WALL 42x42 VERT" anchorname2="Inner studding int" anchorname2_fin="Sisäkoolaus sisä" studs="core" type="intstud">
          </layer>
          <!--layer ref="WALL 42x42 HOR" anchorname2="Inner studding int" anchorname2_fin="Sisäkoolaus sisä" studs="core" type="intstud">
          </layer-->
          <boarding ref="GYPSUM 13" anchorname2="Boarding int" anchorname2_fin="Levytys sisä" type="boarding_int" studs="intstud" spacepre="0">
          </boarding>
        </layers>

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="finish_ext,boarding_ext" exclude="intstud,extstud">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="1" text="(weight) KG" units="kg">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,1" boardpanels="boarding_int,boarding_ext,finish_ext">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <projection type="back" layoutmargins="2,0.5,0,1" boardpanels="boarding_int" exclude="core,extstud">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtype>

      <!-- MULTILAYER END -->
      

      <elemtype class="floor" id="FLOOR 300 C/C 300 BORDER" idstamp="300">

        <layers>
          <layer name="Core" visible="1" thickness="0.300" type="core" anchorname1="Top" anchorname2="Bottom">

            <planks group="contour" axis="y" extend="0">
              <material id="block" zoff="0" rotangle="0" thickness="0.025" height="0.300"></material>
            </planks>

            <planks group="contour" axis="x" extend="0">
              <material id="block" zoff="0" rotangle="0" thickness="0.025" height="0.300"></material>
            </planks>

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->
            <planks group="vertical" axis="y" skipaxis="1" opening_parallel="1" opening_normal="1" spacing="0.3" spacingtolerance="0.05">
              <material id="I 300" zoff="0" rotangle="0"></material>
              <force>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="0.500" extend="1" handleto1="-0.500">
                  <planks1 group="sideleft" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>

                <parallel x2off="-0.500" extend="1" handleto1="0.500">
                  <planks1 group="sideright" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>
              </force>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="block" zoff="0" rotangle="0" thickness="0.025" height="0.300"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>

          </layer>
          <!--layer name="Insulation" visible="0" thickness="0.050"></layer-->
          <!--layer name="Vertical studding in" visible="0" thickness="0.022" anchorname1="Vertical studding in"></layer-->
          <!--layer name="Plasterboard" visible="0" thickness="0.013" anchorname2="Plasterboard in"></layer-->
        </layers>

        <!-- No projections at all (no dim lines etc), change tag name projections_nope to projections to have projections. ALSO THE END TAG -->
        <projections_nope>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,2,2,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection>
            </group>
          </group>
        </projections_nope>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>


      <elemtype class="floor" id="FLOOR 300 C/C 300" idstamp="300">
        <layers>
          <layer name="Core" visible="1" thickness="0.300" type="core" anchorname1="Top" anchorname2="Bottom">

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->
            <planks group="vertical" axis="y" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="0.3" spacingtolerance="0.05">
              <material id="I 300" zoff="0" rotangle="0"></material>
              <force_nope>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="0.500" extend="1" handleto1="-0.500">
                  <planks1 group="sideleft" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>

                <parallel x2off="-0.500" extend="1" handleto1="0.500">
                  <planks1 group="sideright" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>
              </force_nope>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="0" opening_unused="1">
              <material id="block" zoff="0" rotangle="0" thickness="0.025" height="0.300"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>

          </layer>
          <!--layer name="Insulation" visible="0" thickness="0.050"></layer-->
          <!--layer name="Vertical studding in" visible="0" thickness="0.022" anchorname1="Vertical studding in"></layer-->
          <!--layer name="Plasterboard" visible="0" thickness="0.013" anchorname2="Plasterboard in"></layer-->
        </layers>

        <!-- No projections at all (no dim lines etc), change tag name projections_nope to projections to have projections. ALSO THE END TAG -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="bottom" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>

      <elemtype class="floor" id="FLOOR 300 C/C 600 FRAME" idstamp="300">
        <layers>
          <layer name="Core" visible="1" thickness="0.300" type="core" anchorname1="Top" anchorname2="Bottom">

            <!-- Group name will have suffixes: _y=vertical planks, _x=horizontal planks -->
            <!-- Group names can be used for example to make grooves for balks and groups may be referred using wild cards: vertical* -->

            <!-- bottom wood -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="I 300" zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="I 300" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="0.6" spacingtolerance="0.05">
              <material id="I 300" zoff="0" rotangle="0"></material>
              <force_nope>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="0.500" extend="1" handleto1="-0.500">
                  <planks1 group="sideleft" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>

                <parallel x2off="-0.500" extend="1" handleto1="0.500">
                  <planks1 group="sideright" axis="x" spacing="0.3" spacingtolerance="0.05">
                    <material id="I 300" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>
              </force_nope>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="0" opening_unused="1">
              <material id="block" zoff="0" rotangle="0" thickness="0.025" height="0.300"></material>
            </planks>

            <script ref="setcolours"></script>

            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>

          </layer>
          <!--layer name="Insulation" visible="0" thickness="0.050"></layer-->
          <!--layer name="Vertical studding in" visible="0" thickness="0.022" anchorname1="Vertical studding in"></layer-->
          <!--layer name="Plasterboard" visible="0" thickness="0.013" anchorname2="Plasterboard in"></layer-->
        </layers>

        <!-- No projections at all (no dim lines etc), change tag name projections_nope to projections to have projections. ALSO THE END TAG -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <!-- cutlist attribute elemid="0"/"1", includes element id in the cut list (1) or not (0) -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection>
              <projection type="bottom" layoutmargins="2,0.5,0,1">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,2,0,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>


      <elemtype class="roof" id="GABLE EAVES 173 K600 LEFT" idstamp="42x173">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
            <elemparam name="pen">1</elemparam>
          </newelem>

          <newelemplank>
            <elemparam name="pen">1</elemparam>
          </newelemplank>
        </settings>

        <layers>

          <layer name="Core" visible="1" thickness="0.173" type="core" anchorname1="Core top" anchorname2="Core bottom">

            <planks group="purlins" axis="x" opening_parallel="1" opening_normal="1" spacing="0.9" spacingtolerance="0.01">
              <material id="block" thickness="0.042" height="0.173" zoff="0" rotangle="0"></material>
            </planks>

            <!-- Eaves side wood -->
            <planks group="eaves" axis="y" skipaxis="1">
              <material id="block" thickness="0.042" height="0.173" zoff="0" rotangle="0"></material>
              <force>
                <parallel x1off="mat_thickness*0.5"></parallel>
              </force>
            </planks>


            <!-- Transportation support -->
            <planks group="xxx" axis="y" skipaxis="1">
              <material id="block" thickness="0.020" height="0.070" zoff="-mat_thickness*0.5" rotangle="90"></material>
              <force>
                <parallel x2off="-0.070"></parallel>
              </force>
            </planks>

            <operations>
              <jointo target="purlins*" operator="eaves*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>

        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,2,2,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection>

              <!-- No top projection -->
              <!--projection type="top" layoutmargins="2,2,2,2">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>

        <!--markings ref="mark_default">
        </markings-->
      </elemtype>

      <elemtype class="roof" id="GABLE EAVES 173 K600 RIGHT" idstamp="42x173">
        <!-- Default settings for this element type -->
        <settings>
          <newelem>
            <elemparam name="pen">1</elemparam>
          </newelem>

          <newelemplank>
            <elemparam name="pen">1</elemparam>
          </newelemplank>
        </settings>

        <layers>

          <layer name="Core" visible="1" thickness="0.173" type="core" anchorname1="Core top" anchorname2="Core bottom">

            <planks group="purlins" axis="x" opening_parallel="1" opening_normal="1" spacing="0.9" spacingtolerance="0.01">
              <material id="block" thickness="0.042" height="0.173" zoff="0" rotangle="0"></material>
            </planks>

            <!-- Eaves side wood -->
            <planks group="eaves" axis="y" skipaxis="1">
              <material id="block" thickness="0.042" height="0.173"  zoff="0" rotangle="0"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5"></parallel>
              </force>
            </planks>


            <!-- Transportation support -->
            <planks group="xxx" axis="y" skipaxis="1">
              <material id="block" thickness="0.020" height="0.070" zoff="-mat_thickness*0.5" rotangle="90"></material>
              <force>
                <parallel x1off="0.000"></parallel>
              </force>
            </planks>

            <operations>
              <jointo target="purlins*" operator="eaves*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>

        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <!-- Only planks belonging to the element are included in cutlist -->
              <!-- layoutalign: -1=left/bottom, 0=center, 1=right/top -->
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,2,2,2">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
              </projection>

              <!-- No top projection -->
              <!-- projection type="top" layoutmargins="2,2,2,2">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection -->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtype>
    </elemtypes>


    <!-- ELEMENT TEMPLATES -->
    <elemtemplates>
      <elemtemplate class="boarding" templateid="boarding" templatename="Boarding" templatename_fin="Levytys" id="[id]">
        <settings>
          <newelemboard>
            <layer>[layer;type=layer;default=AF Board]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
            <objparam name="iShowDiaLine">[boarddialine;default=1]</objparam>
            <objparam name="iShowID2D">[Show ID in floor plan]</objparam>
            <objparam name="iShowID3D">[Show ID in 3D]</objparam>
            <objparam name="iPenId">[idpen]</objparam>
            <objparam name="iFill">[board_fill_2d]</objparam>
            <objparam name="iFillFrom3D">[board_fill_pen_from_3dmat;type=real;default=0]</objparam>
          </newelemboard>
          <newelemboardprojside>
            <objparam name="iShowID2D">[Show ID in front projection]</objparam>
          </newelemboardprojside>
        </settings>
        <layers>
          <boarding thickness="[thickness;type=length]" overlap="[boardoverlap;default=1]" boardingtype="[boardingtype;default=1]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]">
            <board id="[boardid]" width="[boardwidth;type=length]" height="[boardheight;type=length]"></board>

            <!-- For customized board IDs -->
            <renumscript ref="[renum_script_board;prompt=Board id assign script;default=]"></renumscript>
		  </boarding>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      <elemtemplate class="boarding" templateid="paneling" templatename="Paneling" templatename_fin="Verhoilu" id="[id]">
        <settings>
          <newelemboard>
            <layer>[layer;type=layer;default=AF Panel]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
            <objparam name="iFill">0</objparam>
            <objparam name="iPanelRot">[panelrot;type=angle;default=0]</objparam>
            <objparam name="iPanelAnchor">[panelanchor;type=real;default=1]</objparam>
            <objparam name="iPanelX">[panel_offset_X;type=length;default=0]</objparam>
            <objparam name="iPanelY">[panel_offset_Y;type=length;default=0]</objparam>
          </newelemboard>
        </settings>
        <layers>
          <boarding thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]">
            <board panelingref="[panelref;type=panelid;default=PANEL_HOR_INOUT]" width="9999" height="9999" >
            </board>

            <!-- For customized board IDs -->
            <renumscript ref="[renum_script_board;prompt=Board id assign script;default=]"></renumscript>
		  </boarding>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      <elemtemplate class="layer" templateid="airstrips_vert" templatename="Air space strips vertical" templatename_fin="Tuuletusrako pysty" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <planks group="vertical" axis="y" opening_parallel="[opening_parallel;default=1]" opening_normal="[opening_normal;default=0]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>
            <operations>
              <jointo target="vertical_spacing" operator="vertical_x">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      <elemtemplate class="layer" templateid="airstrips_hor" templatename="Air space strips horizontal" templatename_fin="Tuuletusrako vaaka" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left -->
            <planks group="top" axis="y" skipaxis="1" create="[create_left;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Right -->
            <planks group="bottom" axis="y" skipaxis="1" create="[create_right;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-mat_height*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="x" opening_parallel="[opening_parallel;default=1]" opening_normal="[opening_normal;default=1]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]" skipcorners="[skipcorners;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
            </planks>

            <operations>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_y|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="airstrips_hor_gable_10" templatename="Air space strips horizontal with angled parts" templatename_fin="Tuuletusrako vaaka vinoilla osilla" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]" opening_square="[opening_square;type=length;default=0.2]">
            <!-- Left side vertical -->
            <planks group="top" axis="y" skipaxis="1" create="[create_left;default=0]">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff_left;default=mat_thickness*0.5]" rotangle="[rotangle_left;type=real;default=90]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="bottom" axis="y" skipaxis="1" create="[create_right;default=0]">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff_right;default=mat_thickness*0.5]" rotangle="[rotangle_right;type=real;default=90]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <!-- Bottom -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="x" opening_parallel="[opening_parallel;default=3]" opening_normal="[opening_normal;default=0]" stackingoffset="[stackingoffset;type=length;default=-0.624]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=6]" skipcorners="[skipcorners;default=1]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused_angled" contour_unused="1" opening_unused="1" joinends_contour="[joinends_contour;default=0]" joinends_opening="[joinends_opening;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_y|contourtilted">
                <cut conntype="hasx" maxdisttoend="0.100" jointgap="0.000" extendmaxlen="0.1"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.080" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Needed if contourtilted is not connected -->
              <jointo target="contourtilted" operator="contourtilted">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0" endshape="straightshort"></cut>
              </jointo>

            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      <elemtemplate class="layer" templateid="framing1" templatename="Framing" templatename_fin="Runko" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left side vertical -->
            <planks group="vertical" axis="y" skipaxis="1">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff_left;default=0]" rotangle="[rotangle_left;type=real;default=0]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_thickness*0.5]"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="vertical" axis="y" skipaxis="1">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff_right;default=0]" rotangle="[rotangle_right;type=real;default=0]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_thickness*0.5]"></parallel>
              </force>
            </planks>

            <!-- bottom wood, assume rotangles 0/90 -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff_bot;default=@zoff]" rotangle="[rotangle_bot;type=real;default=@rotangle]">
                <objparam name="iCnc">[cnc_bottom;default=1;type=real]</objparam>
                <layer>[layer_bottom_plate;]</layer>
              </material>
              <force>
                <parallel x2off="-mat_thickness*0.5*abs(cos([rotangle_bot]*pi/180))-mat_height*0.5*abs(sin([rotangle_bot]*pi/180))"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff_top;default=@zoff]" rotangle="[rotangle_top;type=real;default=@rotangle]">
                <objparam name="iCnc">[cnc_top;default=1;type=real]</objparam>
                <layer>[layer_top_plate;]</layer>
              </material>
              <force>
                <parallel x1off="mat_thickness*0.5*abs(cos([rotangle_top]*pi/180))+mat_height*0.5*abs(sin([rotangle_top]*pi/180))"></parallel>
              </force>
            </planks>

            <!-- Spacing must be latest possible to get custom corners work the best -->
            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]" zstagger="[zstagger;type=real;default=0]" gablehipsplit="[gablehipsplit;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]" duplicate_zoff="[duplicate_zoff;type=length;default=0]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="[matid_tilted;default=@matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
            </planks>

            <script ref="setcolours" currpre="1">
gFillPen="[studs_fillpen;prompt=Studs fill pen, empty=default, -=none;default=]"
            </script>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- To join tilted side to horizontal top begin or end having horizontal top straight -->
              <jointo target="contourtilted" operator="top_force">
                <cut conntype="hasx" absangle="60" jointgap="0.000" extendmaxlen="0.0" skipopface="15" removepart="keeplonger"></cut>
              </jointo>

              <!--groove target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove-->
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      
      <elemtemplate class="layer" templateid="framingmetal" templatename="Framing metal" templatename_fin="Runko metalli" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- bottom wood -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff_bot;default=@zoff]" rotangle="[rotangle_bot;type=real;default=@rotangle]"></material>
              <force>
                <parallel x2off="-mat_thickness*0.5*abs(cos([rotangle_bot]*pi/180))-mat_height*0.5*abs(sin([rotangle_bot]*pi/180))"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff_top;default=@zoff]" rotangle="[rotangle_top;type=real;default=@rotangle]"></material>
              <force>
                <parallel x1off="mat_thickness*0.5*abs(cos([rotangle_top]*pi/180))+mat_height*0.5*abs(sin([rotangle_top]*pi/180))"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]" duplicate_zoff="[duplicate_zoff;type=length;default=0]"></material>
              <opening_bot>
                <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff_top;default=@zoff]" rotangle="[rotangle_top;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid_bot;type=matid]" zoff="[zoff_bot;default=@zoff]" rotangle="[rotangle_bot;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
            </planks>

            <script ref="setcolours" currpre="1">
              gFillPen="[studs_fillpen;prompt=Studs fill pen, empty=default, -=none;default=]"
            </script>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="-[extend_inside;type=length;default=0]" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="-[extend_inside;type=length;default=0]" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="-[extend_inside;type=length;default=0]" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>
      
      
      <elemtemplate class="layer" templateid="framinghor1" templatename="Framing horizontal" templatename_fin="Runko vaaka" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left side vertical -->
            <planks group="top" axis="y" skipaxis="1" create="[create_left;default=1]">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff_left;default=mat_thickness*0.5]" rotangle="[rotangle_left;type=real;default=90]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="bottom" axis="y" skipaxis="1" create="[create_right;default=1]">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff_right;default=mat_thickness*0.5]" rotangle="[rotangle_right;type=real;default=90]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>


            <!-- Bottom -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_height*0.5;prompt=Offset to center:]"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="x" opening_parallel="[opening_parallel;default=1]" opening_normal="[opening_normal;default=1]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[create_other;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|vertical_y|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="framing_horlong" templatename="Framing horizontal long" templatename_fin="Runko vaaka pitkä" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left side vertical -->
            <planks group="top" axis="y" skipaxis="1" create="[create_left;default=1]">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="bottom" axis="y" skipaxis="1" create="[create_right;default=1]">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Bottom -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="mat_height*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="x" opening_parallel="[opening_parallel;default=1]" opening_normal="[opening_normal;default=1]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="bottom*|top*|contourtilted" operator="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_y">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="framing_horlong2" templatename="Framing horizontal long opening sides cut" templatename_fin="Runko vaaka pitkä aukkojen sivut pätkinä" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left side vertical -->
            <planks group="top" axis="y" skipaxis="1" create="[create_left;default=1]">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="bottom" axis="y" skipaxis="1" create="[create_right;default=1]">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Bottom -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x2off="-mat_height*0.5"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="vertical" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <force>
                <parallel x1off="mat_height*0.5"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="x" opening_parallel="[opening_parallel;default=1]" opening_normal="[opening_normal;default=1]" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="bottom*|top*|contourtilted|vertical_y" operator="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_y">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
              <jointo target="vertical_x|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
            </operations>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="framing_ibeam1" templatename="Framing I-beam" templatename_fin="Runko I-palkki" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Left side vertical -->
            <planks group="vertical" axis="y" skipaxis="1">
              <material id="[matid_left;default=@matid;type=matid]" zoff="[zoff_left;default=0]" rotangle="[rotangle_left;type=real;default=0]"></material>
              <force>
                <parallel x1off="[off_center;default=mat_thickness*0.5]"></parallel>
              </force>
            </planks>

            <!-- Right side vertical -->
            <planks group="vertical" axis="y" skipaxis="1">
              <material id="[matid_right;default=@matid;type=matid]" zoff="[zoff_right;default=0]" rotangle="[rotangle_right;type=real;default=0]"></material>
              <force>
                <parallel x2off="-[off_center;default=mat_thickness*0.5]"></parallel>
              </force>
            </planks>

            <!-- bottom wood, assume rotangles 0/90 -->
            <planks group="bottom" axis="x" skipaxis="1">
              <material id="[matid_bot;default=@matid;type=matid]" zoff="[zoff_bot;default=@zoff]" rotangle="[rotangle_bot;type=real;default=@rotangle]">
                <objparam name="iCnc">[cnc_bottom;default=1;type=real]</objparam>
              </material>
              <force>
                <parallel x2off="-mat_thickness*0.5*abs(cos([rotangle_bot]*pi/180))-mat_height*0.5*abs(sin([rotangle_bot]*pi/180))"></parallel>
              </force>
            </planks>

            <!-- Top -->
            <planks group="top" axis="x" skipaxis="1">
              <material id="[matid_top;default=@matid;type=matid]" zoff="[zoff_top;default=@zoff]" rotangle="[rotangle_top;type=real;default=@rotangle]">
                <objparam name="iCnc">[cnc_top;default=1;type=real]</objparam>
              </material>
              <force>
                <parallel x1off="mat_thickness*0.5*abs(cos([rotangle_top]*pi/180))+mat_height*0.5*abs(sin([rotangle_top]*pi/180))"></parallel>
              </force>
            </planks>

            <planks group="vertical" axis="y" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
              <opening_side>
                <material id="[matid_opening_side;default=@matid;type=matid]" zoff="[zoff_opening_side;default=@zoff]" rotangle="[rotangle_opening_side;type=real;default=@rotangle]"></material>
              </opening_side>
              <opening_bot>
                <material id="[matid_opening_bot;default=@matid;type=matid]" zoff="[zoff_opening_bot;default=@zoff]" rotangle="[rotangle_opening_bot;type=real;default=@rotangle]"></material>
              </opening_bot>
              <opening_top>
                <material id="[matid_opening_top;default=@matid;type=matid]" zoff="[zoff_opening_top;default=@zoff]" rotangle="[rotangle_opening_top;type=real;default=@rotangle]"></material>
              </opening_top>
            </planks>

            <!-- Every other, axis=unused means every edge not handled in previous rules. Added planks for openings will not cut the studs and will have group suffix _opening -->
            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]"></material>
            </planks>

            <script ref="setcolours" currpre="1">
              gFillPen="[studs_fillpen;prompt=Studs fill pen, empty=default, -=none;default=]"
            </script>
            <script ref="ibeamframe"></script>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <groove target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove>
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="floor1" templatename="Floor/roof with sides" templatename_fin="Lattia/katto reunuksilla" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

            <planks group="contour" axis="y" extend="0" create="[createborder;default=1]">
              <material id="[bordermatid;default=block]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;type=length]" height="[borderheight;default=0.100;type=length]"></material>
            </planks>

            <planks group="contour" axis="x" extend="0" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <planks group="vertical" axis="y" skipaxis="1" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
              <force>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="[sideoff;type=length;default=0.5]" extend="1" handleto1="-[sideoff]">
                  <planks1 group="sideleft" axis="x" spacing="[spacing_side;type=length;default=0.6]" spacingtolerance="[spacingtolerance_side;type=length;default=0.02]">
                    <material id="[matid_side;default=@matid;type=matid]" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>

                <parallel x2off="-[sideoff]" extend="1" handleto1="[sideoff]">
                  <planks1 group="sideright" axis="x" spacing="[spacing_side;type=length;default=0.6]" spacingtolerance="[spacingtolerance_side;type=length;default=0.02]">
                    <material id="[matid_side;type=matid]" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>
              </force>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
			
              <!-- 11/2022: Trim contour_y longer than contourtilted -->
              <jointo target="contour_y*" operator="contourtilted*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
              </jointo>
				
              <jointo target="contourtilted*" operator="contour_y*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
		      <!-- 11/2022: Also make sure contourtilted is longer than contour_x -->
              <jointo target="contourtilted*" operator="contour_x">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
              </jointo>

              <jointo target="contour_x" operator="contourtilted*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

		      <joinends target="contourtilted*" operator="contourtilted*">
                <joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
              </joinends>
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="floor_studshort1" templatename="Floor/roof with sides studs short" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

            <planks group="contour" axis="y" extend="0" create="[createborder;default=1]">
              <material id="[bordermatid;default=block]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;type=length]" height="[borderheight;default=0.100;type=length]"></material>
            </planks>

            <planks group="contour" axis="x" extend="0" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <planks group="vertical" axis="y" skipaxis="1" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
              <force>
                <!-- parallel|normal, x1off refers to left side of axis, x2off to right side of the axis. Only the line that does not have anything in element polygon to offset direction is handled. -->
                <!-- extend extends the forced planks to outline polygon (to be cut later with top&bottom wood) -->
                <parallel x1off="[sideoff;type=length;default=0.5]" extend="1" handleto1="-[sideoff]">
                  <planks1 group="sideleft" axis="x" spacing="[spacing_side;type=length;default=0.6]" spacingtolerance="[spacingtolerance_side;type=length;default=0.02]">
                    <material id="[matid_side;default=@matid;type=matid]" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>

                <parallel x2off="-[sideoff]" extend="1" handleto1="[sideoff]">
                  <planks1 group="sideright" axis="x" spacing="[spacing_side;type=length;default=0.6]" spacingtolerance="[spacingtolerance_side;type=length;default=0.02]">
                    <material id="[matid_side;type=matid]" zoff="0" rotangle="0"></material>
                  </planks1>
                </parallel>
              </force>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <!-- Extend x at inner corners -->
              <jointo target="contour_x" operator="contour_y">
                <cut maxdisttoend="0.100" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour x longer -->
              <jointo target="contour_y" operator="contour_x">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
			
              <!-- 11/2022: Trim contour_y shorter than contourtilted -->
              <jointo target="contourtilted*" operator="contour_y*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
              </jointo>
				
              <jointo target="contour_y*" operator="contourtilted*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
		      <!-- 11/2022: Also make sure contourtilted is shorter than contour_x -->
              <jointo target="contour_x" operator="contourtilted*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
              </jointo>

              <jointo target="contourtilted*" operator="contour_x">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

		      <joinends target="contourtilted*" operator="contourtilted*">
                <joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
              </joinends>
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>

      <elemtemplate class="layer" templateid="floor2" templatename="Floor/roof no sides" templatename_fin="Lattia/katto ilman reunuksia" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

            <planks group="contour" axis="y" extend="0" create="[createborder;default=1;prompt=Create border 0/1]">
              <material id="[bordermatid;default=block;prompt=Border mat id]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;prompt=Border mat thickness;type=length]" height="[borderheight;default=0.100;prompt=Border mat height;type=length]"></material>
            </planks>

            <planks group="contour" axis="x" extend="0" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <planks group="vertical" axis="y" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- 11/2022: Trim contour_y longer than contourtilted -->
              <jointo target="contour_y*" operator="contourtilted*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
              </jointo>
				
              <jointo target="contourtilted*" operator="contour_y*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
		      <!-- 11/2022: Also make sure contourtilted is longer than contour_x -->
              <jointo target="contourtilted*" operator="contour_x">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
              </jointo>

              <jointo target="contour_x" operator="contourtilted*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

		      <joinends target="contourtilted*" operator="contourtilted*">
                <joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
              </joinends>
			</operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


		<elemtemplate class="layer" templateid="floor_studshort2" templatename="Floor/roof no sides studs short" templatename_fin="Lattia/katto ilman reunuksia vasta lyhyet" id="[id]">
			<settings>
				<newelemplank>
					<layer>[layer;type=layer]</layer>
					<elemparam name="material">[material3d;default=]</elemparam>
					<elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
					<elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
					<elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
					<elemparam name="cutfill">[cutfill;default=]</elemparam>
				</newelemplank>
				<neweleminsuprojside>
					<objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
				</neweleminsuprojside>
				<neweleminsu>
					<objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
				</neweleminsu>
			</settings>
			<layers>
				<layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

					<planks group="contour" axis="y" extend="0" create="[createborder;default=1;prompt=Create border 0/1]">
						<material id="[bordermatid;default=block;prompt=Border mat id]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;prompt=Border mat thickness;type=length]" height="[borderheight;default=0.100;prompt=Border mat height;type=length]"></material>
					</planks>

					<planks group="contour" axis="x" extend="0" create="[createborder]">
						<material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
					</planks>

					<planks group="vertical" axis="y" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
						<material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
					</planks>

					<planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
						<material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
					</planks>

					<!-- For customized plank IDs -->
					<renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

          <insulation
            create="[insu_create;type=real;default=0]"
            thickness="[insu_thickness;type=length;default=0]"
            zoff="[insu_zoff;type=length;default=0]"
            leftoff="[insu_leftoff;type=length;default=0]"
            rightoff="[insu_rightoff;type=length;default=0]"
            topoff="[insu_topoff;type=length;default=0]"
            botoff="[insu_botoff;type=length;default=0]"
            explode="[insu_explode;type=real;default=0]"
            minsize="[insu_minsize;type=length;default=0.010]"
            split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
            split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
            <settings>
							<layer>[insu_layer;type=layer]</layer>
							<objparam name="iShowDiaLine">0</objparam>
							<objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
							<objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
							<objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
							<objparam name="iUseRgb3D">1</objparam>
							<objparam name="iFillFrom3D">1</objparam>
							<objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
							<objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
							<objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
							<elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
							<elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
							<elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
							<elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
						</settings>
					</insulation>

					<operations>
						<!-- Extend x at inner corners -->
						<jointo target="contour_x" operator="contour_y">
							<cut maxdisttoend="0.100" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
						</jointo>

						<!-- Contour x longer -->
						<jointo target="contour_y" operator="contour_x">
							<cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
						</jointo>

						<jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
							<cut jointgap="0.000" extendmaxlen="0.0"></cut>
						</jointo>

						<!-- Trim to holes -->
						<jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
							<cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
						</jointo>

						<!-- Trim sides -->
						<jointo target="sideleft*|sideright*" operator="vertical*|contour*">
							<cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
						</jointo>

						<!-- 11/2022: Trim contour_y shorter than contourtilted -->
						<jointo target="contourtilted*" operator="contour_y*">
							<cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
						</jointo>

						<jointo target="contour_y*" operator="contourtilted*">
							<cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
						</jointo>

						<!-- 11/2022: Also make sure contourtilted is shorter than contour_x -->
						<jointo target="contour_x" operator="contourtilted*">
							<cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
						</jointo>

						<jointo target="contourtilted*" operator="contour_x">
							<cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
						</jointo>

						<joinends target="contourtilted*" operator="contourtilted*">
							<joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
						</joinends>
					</operations>

				</layer>
			</layers>
			<cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
		</elemtemplate>


		<elemtemplate class="layer" templateid="floorhor_1" templatename="Floor/roof horizontal no sides" templatename_fin="Lattia/katto vaaka ilman reunuksia" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" studmindist="[studmindist;type=length]" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

            <planks group="contour" axis="y" extend="0" create="[createborder;default=1;prompt=Create border 0/1]">
              <material id="[bordermatid;default=block;prompt=Border mat id]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;prompt=Border mat thickness;type=length]" height="[borderheight;default=0.100;prompt=Border mat height;type=length]"></material>
            </planks>

            <planks group="contour" axis="x" extend="0" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <planks group="vertical" axis="x" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="vertical_x|contour*">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
              <!-- 11/2022: Trim contour_y longer than contourtilted -->
              <jointo target="contour_y*" operator="contourtilted*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
              </jointo>
				
              <jointo target="contourtilted*" operator="contour_y*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
		          <!-- 11/2022: Also make sure contourtilted is longer than contour_x -->
              <jointo target="contourtilted*" operator="contour_x">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
              </jointo>

              <jointo target="contour_x" operator="contourtilted*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

              <joinends target="contourtilted*" operator="contourtilted*">
                <joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
              </joinends>

              <!-- 7/2023: opening tops&bottoms to contour line  -->
              <jointo target="vertical_x" operator="contour*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

              <!-- 7/2023: Spacing to opening sides  -->
              <jointo target="vertical_spacing" operator="vertical_y">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>
      

      <elemtemplate class="layer" templateid="floorlong1" templatename="Floor/roof no sides joists long" templatename_fin="Lattia/katto ilman reunuksia palkit pitkänä" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">

            <planks group="contour" axis="y" extend="0" create="[createborder;default=1;prompt=Create border 0/1]">
              <material id="[bordermatid;default=block;prompt=Border mat id]" zoff="0" rotangle="0" thickness="[borderthickness;default=0.025;prompt=Border mat thickness;type=length]" height="[borderheight;default=0.100;prompt=Border mat height;type=length]"></material>
            </planks>

            <planks group="contour" axis="x" extend="0" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <planks group="vertical" axis="y" skipaxis="0" opening_parallel="1" opening_normal="1" spacing="[spacing;type=length;default=0.6]" spacingtolerance="[spacingtolerance;type=length;default=0.005]" framingrule="[framingrule;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="0" rotangle="0"></material>
            </planks>

            <planks group="contourtilted" axis="unused" contour_unused="1" opening_unused="1" create="[createborder]">
              <material id="[bordermatid]" zoff="0" rotangle="0" thickness="[borderthickness]" height="[borderheight]"></material>
            </planks>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>
            
            <operations>
              <!-- Extend y at inner corners -->
              <jointo target="contour_y" operator="contour_x">
                <cut maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1"></cut>
              </jointo>

              <!-- Contour y longer -->
              <jointo target="contour_x" operator="contour_y">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_x|contour*" operator="vertical_y*|vertical_spacing|vertical_force">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim to holes -->
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="hasx" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!-- Trim sides -->
              <jointo target="sideleft*|sideright*" operator="vertical*|contour*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>
			
              <!-- 11/2022: Trim contour_y longer than contourtilted -->
              <jointo target="contour_y*" operator="contourtilted*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" toend="1" removepart="keeplonger"></cut>
              </jointo>
				
              <jointo target="contourtilted*" operator="contour_y*">
                <cut conntype="hasx" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>
				
		      <!-- 11/2022: Also make sure contourtilted is longer than contour_x -->
              <jointo target="contourtilted*" operator="contour_x">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.001" expandopfind="0.001" toend="1" removepart="keeplonger"></cut>
              </jointo>

              <jointo target="contour_x" operator="contourtilted*">
                <cut conntype="linex" maxdisttoend="0.200" jointgap="0.000" extendmaxlen="0.0" removepart="keeplonger"></cut>
              </jointo>

		      <joinends target="contourtilted*" operator="contourtilted*">
                <joinends conntype="hasx" maxdisttoend="0.001" jointgap="0.000" removepart="keeplonger"></joinends>
              </joinends>
            </operations>

          </layer>
        </layers>
      </elemtemplate>


      <elemtemplate class="layer" templateid="framing_win" templatename="Planks around openings" templatename_fin="Koolaukset aukkojen ympärille" id="[id]">
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer name="Core" visible="1" thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <!-- Spacing must be latest possible to get custom corners work the best -->
            <planks group="vertical" axis="y" skipaxis="1" opening_parallel="2" opening_normal="1" zstagger="[zstagger;type=real;default=0]" gablehipsplit="[gablehipsplit;type=real;default=0]">
              <material id="[matid;type=matid]" zoff="[zoff;default=0]" rotangle="[rotangle;type=real;default=0]" duplicate_zoff="[duplicate_zoff;type=length;default=0]"></material>
            </planks>

            <script ref="setcolours" currpre="1">
              gFillPen="[studs_fillpen;prompt=Studs fill pen, empty=default, -=none;default=]"
            </script>

            <!-- For customized plank IDs -->
            <renumscriptnew ref="[renum_script;prompt=Plank id assign script;default=]"></renumscriptnew>

            <insulation
              create="[insu_create;type=real;default=0]"
              thickness="[insu_thickness;type=length;default=0]"
              zoff="[insu_zoff;type=length;default=0]"
              leftoff="[insu_leftoff;type=length;default=0]"
              rightoff="[insu_rightoff;type=length;default=0]"
              topoff="[insu_topoff;type=length;default=0]"
              botoff="[insu_botoff;type=length;default=0]"
              explode="[insu_explode;type=real;default=0]"
              minsize="[insu_minsize;type=length;default=0.010]"
              split_if_bigger="[insu_split_if_bigger;type=length;default=0]"
              split_if_bigger_percentage="[insu_split_if_bigger_percentage;type=real;default=0]">
              <settings>
                <layer>[insu_layer;type=layer]</layer>
                <objparam name="iShowDiaLine">0</objparam>
                <objparam name="iFill">[insu_fill_2d;default=25 %]</objparam>
                <objparam name="iMatId">[insu_matid;default=INSULATION XXX]</objparam>
                <objparam name="iWeightM3">[insu_weight_kg_per_m3;type=real;default=30]</objparam>
                <objparam name="iUseRgb3D">1</objparam>
                <objparam name="iFillFrom3D">1</objparam>
                <objparam name="iRed">[insu_rgb_r;type=real;default=0.90]</objparam>
                <objparam name="iGreen">[insu_rgb_g;type=real;default=0.82]</objparam>
                <objparam name="iBlue">[insu_rgb_b;type=real;default=0.50]</objparam>
                <elemparam name="cutfillpen">[insu_cutfillpen;default=]</elemparam>
                <elemparam name="cutfillbgpen">[insu_cutfill_bg_pen;default=]</elemparam>
                <elemparam name="cutlinepen">[insu_cutlinepen;default=]</elemparam>
                <elemparam name="cutfill">[insu_cutfill;default=]</elemparam>
              </settings>
            </insulation>

            <operations>
              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="bottom*|top*|2ndbottom*|2ndtop*|vertical_x|contourtilted">
                <cut jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="endtoline" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <jointo target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="contourtilted_opening">
                <cut conntype="linex" maxdisttoend="0.050" jointgap="0.000" extendmaxlen="0.0"></cut>
              </jointo>

              <!--groove target="vertical_y|vertical_spacing|vertical_force|vertical_y_openingsupport|vertical_y_*double" operator="balktop*">
                <groove overtop="0.000" overbot="0.001" overside="0.000"></groove>
              </groove-->
            </operations>

          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>
      
      
      <elemtemplate class="layer" templateid="vertpanel1" id="[id]" templatename="Vertical planks fixed spacing" templatename_fin="Pystyverhoilu vakiovälistyksellä" >
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
            <objparam name="iColLines">3</objparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <planks group="vertical" axis="y" opening_parallel="0" opening_normal="0" spacing="[spacing;type=length;default=0.100]" stackingoffset="[stackingoffset;type=length;default=mat_height*0.5]" skipaxis="1">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
            </planks>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <elemtemplate class="layer" templateid="horpanel1" id="[id]" templatename="Horizontal planks fixed spacing" templatename_fin="Vaakaverhoilu vakiovälistyksellä" >
        <settings>
          <newelemplank>
            <layer>[layer;type=layer]</layer>
            <elemparam name="material">[material3d;default=]</elemparam>
            <elemparam name="cutfillpen">[cutfillpen;default=]</elemparam>
            <elemparam name="cutfillbgpen">[cutfill_bg_pen;default=]</elemparam>
            <elemparam name="cutlinepen">[cutlinepen;default=]</elemparam>
            <elemparam name="cutfill">[cutfill;default=]</elemparam>
            <objparam name="iColLines">3</objparam>
          </newelemplank>
          <neweleminsuprojside>
            <objparam name="iShowID2D">[insu_showid_projside;type=real;default=0]</objparam>
          </neweleminsuprojside>
          <neweleminsu>
            <objparam name="iShowID3D">[insu_showid_3d;type=real;default=0]</objparam>
          </neweleminsu>
        </settings>
        <layers>
          <layer thickness="[thickness;type=length]" type="core" circletorect="[circle_to_rect_max_diameter;type=length;default=0]" rotframing="[rotframing;type=real;default=0]">
            <planks group="vertical" axis="x" opening_parallel="0" opening_normal="0" spacing="[spacing;type=length;default=0.100]" stackingoffset="[stackingoffset;type=length;default=mat_height*0.5]" skipaxis="1">
              <material id="[matid;type=matid]" zoff="[zoff;default=mat_thickness*0.5]" rotangle="[rotangle;type=real;default=90]"></material>
            </planks>
          </layer>
        </layers>
        <cncinfo cnc_outputline="[cnc_outputline]" cnc_nailgun="[cnc_nailgun]" cnc_matindex="[cnc_matindex]" cnc_matname="[cnc_matname]" cnc_isframing="[cnc_isframing]"></cncinfo>
      </elemtemplate>


      <!-- 2018_03 BEGIN -->
      <elemtemplate class="composite" templateid="frame_singleproj10" templatename="Just framing with cutlist having machinings v 1.0" templatename_fin="Vain runko ja katkaisulista kolouksin v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <group layout="horizontal">
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="1.5,0.5,1.1,0.5" exclude="[excludeint;default=intstud*,extstud*]" boardpanels="[boardpanelsint;default=core]">
                  <dimlines>
                    <dimline ref="an_framing"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <opening text="#id#\n#width#\nx\n#height#">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="fontname">Arial</elemparam>
                      <elemparam name="fontsize">1.5</elemparam>
                      <elemparam name="fontstyle"></elemparam>
                      <elemparam name="just">center</elemparam>
                      <framelines create="[create_openig_frame_lines;default=0]">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="linetype">1</elemparam>
                      </framelines>
                    </opening>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                    <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                      <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                      <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                      <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                      <line>
                        <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                        <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                      </line>
                    </topplankangledim>
                  </elemmarkings>
                </projection>

                <projection type="top" layoutmargins="1.5,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>

              <group layout="vertical" >
                <cutlist layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_an_single" elemid="0" layoutminheight="3"></cutlist>
                <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
              </group>
            </group>
            <elemstamp layoutalign="-1" layoutmargins="0,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
              <script ref="elemstamp"></script>
            </elemstamp>
          </group>
        </projections>
      </elemtemplate>


      <elemtemplate class="composite" templateid="frame_singleproj10_rev_viewdir" templatename="Framing only, cutlist incl machinings, reversed view direction" templatename_fin="Vain runko, katkaisulista kolouksin, käännetty katselusuunta" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <group layout="horizontal">
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="back" layoutmargins="1.5,0.5,1.1,0.5" exclude="[excludeint;default=intstud*,extstud*]" boardpanels="[boardpanelsint;default=core]">
                  <dimlines>
                    <dimline ref="an_framing"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <opening text="#id#\n#width#\nx\n#height#">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="fontname">Arial</elemparam>
                      <elemparam name="fontsize">1.5</elemparam>
                      <elemparam name="fontstyle"></elemparam>
                      <elemparam name="just">center</elemparam>
                      <framelines create="[create_openig_frame_lines;default=0]">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="linetype">1</elemparam>
                      </framelines>
                    </opening>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                    <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                      <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                      <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                      <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                      <line>
                        <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                        <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                      </line>
                    </topplankangledim>
                  </elemmarkings>
                </projection>

                <projection type="top" rotate="180" layoutmargins="1.5,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top_rotated"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>

              <group layout="vertical" >
                <cutlist layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_an_single" elemid="0" layoutminheight="3"></cutlist>
                <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
              </group>
            </group>
            <elemstamp layoutalign="-1" layoutmargins="0,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
              <script ref="elemstamp"></script>
            </elemstamp>
          </group>
        </projections>
      </elemtemplate>


      <elemtemplate class="composite" templateid="ew_out_frameclad_10" templatename="Wall frame+cladding out to in with cutlist having machinings v 1.0" templatename_fin="Seinä runko+verhoilu ulkoa sisälle ja katkaisulista kolouksin v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                <elemparam name="pen">1</elemparam>
                <elemparam name="fontname">arial</elemparam>
                <elemparam name="fontsize">30</elemparam>
                <elemparam name="fontstyle"></elemparam>
              </text>
              <text content="CORE FROM OUTSIDE" content_fin="RUNKO ULKOA" anchor="1" x="1.5" y="-0.1">
                <elemparam name="pen">1</elemparam>
                <elemparam name="fontname">arial</elemparam>
                <elemparam name="fontsize">2.5</elemparam>
                <elemparam name="fontstyle"></elemparam>
              </text>
              <projection type="front" layoutmargins="1.5,0.5,1.1,0.5" exclude="[excludeext;default=intstud*,extstud*]" boardpanels="[boardpanelsext;default=finish_ext,core]">
                <dimlines>
                  <dimline ref="an_frame_cladding"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
                <projplanksettings type="extstud*">
                  <elemparam name="linetype">*dash*|*stipling*</elemparam>
                  <objparam name="iFill">0</objparam>
                  <objparam name="iShowID">0</objparam>
                  <objparam name="iShowLen">0</objparam>
                  <elemparam name="pen">2</elemparam>
                </projplanksettings>
              </projection>

              <projection type="top" layoutmargins="1.5,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
                <elemmarkings>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                </elemmarkings>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="0,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>

            <group layout="vertical" >
              <cutlist layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_an_single" elemid="0" layoutminheight="3"></cutlist>
              <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
            </group>
          </group>
        </projections>
      </elemtemplate>


      <elemtemplate class="composite" templateid="frame_singleproj_floor10" templatename="Just framing floor+roof with cutlist having machinings v 1.0" templatename_fin="Vain runko vp ja yp ja katkaisulista kolouksin v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <group layout="horizontal">
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="1.5,0.5,1.1,0.5" exclude="[excludeint;default=intstud*,extstud*]" boardpanels="[boardpanelsint;default=core]">
                  <dimlines>
                    <dimline ref="an_framing"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <opening text="#id#\n#width#\nx\n#height#">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="fontname">Arial</elemparam>
                      <elemparam name="fontsize">1.5</elemparam>
                      <elemparam name="fontstyle"></elemparam>
                      <elemparam name="just">center</elemparam>
                      <framelines create="[create_openig_frame_lines;default=0]">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="linetype">1</elemparam>
                      </framelines>
                    </opening>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                    <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                      <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                      <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                      <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                      <line>
                        <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                        <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                      </line>
                    </topplankangledim>
                  </elemmarkings>
                </projection>

                <projection type="bottom" layoutmargins="1.5,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>

              <group layout="vertical" >
                <cutlist layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_an_single" elemid="0" layoutminheight="3">
                  <luasettings>
                    <![CDATA[
                    gnFloorRoof=1   -- nil=not known or a wall, 1=it is a floor, 2=it is a roof
]]>
                  </luasettings>
                </cutlist>
                <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
              </group>
            </group>
            <elemstamp layoutalign="-1" layoutmargins="0,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
              <script ref="elemstamp"></script>
            </elemstamp>
          </group>
        </projections>
      </elemtemplate>
      
      
      <elemtemplate class="composite" templateid="an_extwall_10" templatename="Multisheet external wall from out to in v 1.0" templatename_fin="Moniarkkituloste ulkoseinät ulkoa sisälle v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <!-- PAGE 1 -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">MAIN</objparam>
              </frame>
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <text content="CORE FROM OUTSIDE" content_fin="RUNKO ULKOA" anchor="1" x="6" y="-2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="6,0.5,3,0.5" exclude="[excludeext;default=intstud*,extstud*]" boardpanels="[boardpanelsext;default=]">
                  <dimlines>
                    <dimline ref="an_framing"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <opening text="#id#\n#width#\nx\n#height#">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="fontname">Arial</elemparam>
                      <elemparam name="fontsize">1.5</elemparam>
                      <elemparam name="fontstyle"></elemparam>
                      <elemparam name="just">center</elemparam>
                      <framelines create="[create_openig_frame_lines;default=0]">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="linetype">1</elemparam>
                      </framelines>
                    </opening>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                    <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                      <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                      <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                      <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                      <line>
                        <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                        <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                      </line>
                    </topplankangledim>
                  </elemmarkings>
                  <projplanksettings type="extstud*">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <projection type="top" layoutmargins="6,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>

              <group layout="horizontal" >
                <cutlist layoutmargins="4.5,0.1,0.1,0.1" settingsref="cutlist_table_corestuds" elemid="0" layoutminheight="3"></cutlist>
                <cutlist layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_coreothers" elemid="0"></cutlist>
              </group>
            </group>

            <!-- PAGE 2 -->
            <group layout="horizontal">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">EXTERIOR</objparam>
              </frame>
              <group layout="vertical">
                <text content="WINDSHIELD BOARDS FROM OUTSIDE" content_fin="TS-LEVYT ULKOA" anchor="7" x="2" y="-0.9">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[windshieldboards;default=boarding_ext*]" exclude="[excludeext_windshield;default=intstud*,extstud*]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <text content="CLADDING FROM OUTSIDE" content_fin="VERHOILU ULKOA" anchor="7" x="2" y="0.1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="2,0,0,1" boardpanels="finish_ext" exclude="[exclude_cladding;default=intstud*,extstud2]">
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*|*katkoviiva*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>
              </group>
              <group layout="vertical" layoutmargins="1,0,0.1,0">
                <cutlist layoutmargins="0.1,0.1,0,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards" elemid="0"></cutlist>
                <cutlist layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extcladstuds" elemid="0"></cutlist>
              </group>
            </group>

            <!-- PAGE 3 -->
            <group layout="horizontal">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">INTERIOR</objparam>
              </frame>
              <group layout="vertical">
                <!-- VILLAKUVA -->
                <text content="INSULATION FROM INSIDE" content_fin="ERISTE SISÄLTÄ" anchor="1" x="2" y="-0.05">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="back" layoutmargins="2,0,1,0.5" exclude="*boarding*,*stud*,*finish*" boardpanels="[boards_page3_proj1;default=core]">
                  <dimlines>
                    <dimline ref="an_insu"></dimline>
                  </dimlines>
                  <projplanksettings type="core" objtype="1">
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                  </projplanksettings>
                </projection>

                <text content="INTERIOR STUDDING INSIDE" content_fin="SISÄKOOLAUS SISÄLTÄ" anchor="7" x="2" y="0.1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="back" layoutmargins="2,0,0,1" exclude="*ext*" boardpanels="[boards_page3_proj2;default=boarding_int*]">
                  <dimlines>
                    <dimline ref="an_horframing"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*|*katkoviiva*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>
              </group>
              <group layout="vertical" layoutmargins="1,0.5,0,1" >
                <cutlist layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="3.50" settingsref="cutlist_table_intstuds" elemid="0"></cutlist>
                <cutlist layoutmargins="0.1,0.1,0.5,0.1" layoutminwidth="3.50" settingsref="cutlist_table_intboards" elemid="0"></cutlist>
                <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="0.1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
              </group>
            </group>
          </group>
        </projections>
      </elemtemplate>
      <!-- 2018_03 END -->

      
      <!-- 2019_09 BEG -->
      <elemtemplate class="composite" templateid="inout_bsfbb_10" templatename="Multisheet inout Board+Stud+Frame+Board+Board 1.0" templatename_fin="Moniarkkituloste Levy+Kool+Runko+Levy+Levy 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <!-- PAGE 1 -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page1_layout_name;default=INSIDE]</objparam>
              </frame>
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <text content="[page1_proj1_name;default=FROM INSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="horizontal">
                  <projection type="front" layoutmargins="3,0.5,1,0.5" exclude="[page1_proj1_exclude;default=intstud*,extstud*,boarding*]" boardpanels="[page1_proj1_boards;default=core]">
                    <dimlines>
                      <dimline ref="an_framing"></dimline>
                    </dimlines>
                    <elemmarkings>
                      <opening text="#id#\n#width#\nx\n#height#">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="fontname">Arial</elemparam>
                        <elemparam name="fontsize">1.5</elemparam>
                        <elemparam name="fontstyle"></elemparam>
                        <elemparam name="just">center</elemparam>
                        <framelines create="[create_openig_frame_lines;default=0]">
                          <elemparam name="pen">1</elemparam>
                          <elemparam name="linetype">1</elemparam>
                        </framelines>
                      </opening>
                      <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                        <settings>
                          <layer>[layer_weight;type=layer]</layer>
                          <objparam name="iFill">*25*</objparam>
                          <objparam name="A">0.250</objparam>
                          <objparam name="B">0.325</objparam>
                        </settings>
                      </weight>
                      <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                        <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                        <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                        <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                        <line>
                          <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                          <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                        </line>
                      </topplankangledim>
                    </elemmarkings>
                  </projection>
                  <group layout="vertical">
                    <cutlist layoutmargins="0,0.5,1,0.5" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="3"></cutlist>
                    <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
                  </group>
                </group>

                <group layout="horizontal">
                  <projection type="front" layoutmargins="3,0.5,0.5,0.5" exclude="[page1_proj2_exclude;default=extstud*]" boardpanels="[page1_proj2_boards;default=boarding_int*]">
                    <dimlines>
                      <dimline ref="an_vertstud_board"></dimline>
                    </dimlines>

                    <projplanksettings type="core">
                      <elemparam name="linetype">*dash*|*katkoviiva*|*tratteggio*</elemparam>
                      <objparam name="iFill">0</objparam>
                      <objparam name="iShowID">0</objparam>
                      <objparam name="iShowLen">0</objparam>
                    </projplanksettings>
                  </projection>

                  <group layout="vertical">
                    <cutlist layoutmargins="0,0.5,0.5,0.25" settingsref="cutlist_table_intstuds" elemid="0" layoutminheight="1.4"></cutlist>
                    <cutlist layoutmargins="0,0.5,0,0.5" settingsref="cutlist_table_intboards" elemid="0" layoutminheight="1.35"></cutlist>
                  </group>
                </group>

                <projection type="top" layoutmargins="3,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>
            </group>

            <!-- PAGE 2 -->
            <group layout="horizontal">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page2_layout_name;default=OUTSIDE]</objparam>
              </frame>
              <group layout="vertical">
                <text content="[page2_proj1_name;default=FROM OUTSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                
                <projection type="back" layoutmargins="3,0.5,1,0.5" boardpanels="[page2_proj1_boards;default=boarding_ext2]" exclude="[page2_proj1_exclude;default=intstud*,extstud*]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <projection type="back" layoutmargins="3,0.5,0.5,0.5" boardpanels="[page2_proj2_boards;default=boarding_ext3]" exclude="[page2_proj2_exclude;default=intstud*,extstud*]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

              </group>
              <!-- Single cutlist for ext boards and cladding -->
              <cutlist layoutmargins="0,0.5,1,0.5" settingsref="cutlist_table_extall" elemid="0" layoutminheight="2"></cutlist>
            </group>
          </group>
        </projections>
      </elemtemplate>

      <elemtemplate class="composite" templateid="bfb_10" templatename="Board+Frame+Board with cutlist 1.0" templatename_fin="Levy+Runko+Levy katkaisulistalla 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                <elemparam name="pen">1</elemparam>
                <elemparam name="fontname">arial</elemparam>
                <elemparam name="fontsize">30</elemparam>
                <elemparam name="fontstyle"></elemparam>
              </text>
              <projection type="front" layoutmargins="3,0.5,1,0.5" exclude="[page1_proj1_exclude;default=intstud*,extstud*,boarding*]" boardpanels="[page1_proj1_boards;default=boarding_int*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>

              <projection type="top" layoutmargins="3,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
                <elemmarkings>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                </elemmarkings>
              </projection>

              <projection type="back" layoutmargins="3,0.5,1,0.5" exclude="[page1_proj3_exclude;default=intstud*,extstud*]" boardpanels="[page1_proj3_boards;default=boarding_ext*,core]">
                <dimlines>
                  <dimline ref="kw_levy"></dimline>
                </dimlines>
                <projplanksettings type="core">
                  <elemparam name="linetype">*dash*</elemparam>
                  <objparam name="iFill">0</objparam>
                  <objparam name="iShowID">0</objparam>
                  <objparam name="iShowLen">0</objparam>
                  <elemparam name="pen">2</elemparam>
                </projplanksettings>
              </projection>
            </group>

            <group layout="vertical">
              <cutlist layoutmargins="0,0.5,1,0.5" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="2"></cutlist>
              <cutlist layoutmargins="0,0.5,0,0.5" settingsref="cutlist_table_intboards" elemid="0" layoutminheight="1"></cutlist>
              <cutlist layoutmargins="0,0.5,0,0.5" settingsref="cutlist_table_extboards" elemid="0" layoutminheight="1"></cutlist>
              <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
            </group>
          </group>
        </projections>
      </elemtemplate>
      <!-- 2019_09 END -->

      <!-- 2020_06 beg-->
      <elemtemplate class="composite" templateid="inout_bbshbf_bshb_10" templatename="Multisheet inout Board+Board+Stud H+Board+Frame+Board+Stud H+Board 1.0" templatename_fin="Moniarkkituloste Levy+Levy+Kool+Levy+Runko+Levy+Kool+Levy 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <!-- PAGE 1 -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page1_layout_name;default=FRAMING]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <text content="[page1_proj1_name;default=FROM INSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1.3,0.5" exclude="[page1_proj1_exclude;default=intstud*,extstud*,boarding*,finish*]" boardpanels="[page1_proj1_boards;default=core]">
                    <dimlines>
                      <dimline ref="an_framing"></dimline>
                    </dimlines>
                    <elemmarkings>
                      <opening text="#id#\n#width#\nx\n#height#">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="fontname">Arial</elemparam>
                        <elemparam name="fontsize">1.5</elemparam>
                        <elemparam name="fontstyle"></elemparam>
                        <elemparam name="just">center</elemparam>
                        <framelines create="[create_openig_frame_lines;default=0]">
                          <elemparam name="pen">1</elemparam>
                          <elemparam name="linetype">1</elemparam>
                        </framelines>
                      </opening>
                      <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                        <settings>
                          <layer>[layer_weight;type=layer]</layer>
                          <objparam name="iFill">*25*</objparam>
                          <objparam name="A">0.250</objparam>
                          <objparam name="B">0.325</objparam>
                        </settings>
                      </weight>
                      <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                        <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                        <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                        <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                        <line>
                          <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                          <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                        </line>
                      </topplankangledim>
                    </elemmarkings>
                  </projection>

                  <projection type="top" layoutmargins="3,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                    <dimlines>
                      <dimline ref="wall_top_more_space"></dimline>
                    </dimlines>
                    <elemmarkings>
                      <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                        <settings>
                          <layer>[layer_weight;type=layer]</layer>
                          <objparam name="iFill">*25*</objparam>
                          <objparam name="A">0.250</objparam>
                          <objparam name="B">0.325</objparam>
                        </settings>
                      </weight>
                    </elemmarkings>
                  </projection>
                </group>
                <group layout="vertical">
                  <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="3"></cutlist>
                  <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
                </group>
              </group>
            </group>

            <!-- PAGE 2 -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page2_layout_name;default=BOARD1]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="[page2_proj1_name;default=FROM INSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1,1" exclude="[page2_proj1_exclude;default=*]" boardpanels="[page2_proj1_boards;default=boarding_int2]">
                    <dimlines>
                      <dimline ref="kw_levy"></dimline>
                    </dimlines>
                    <contourlines create="1" holes="0">
                      <elemparam name="pen">[framing_contour_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[framing_contour_linetype;default=*dash*|*katkoviiva*|*tratteggio*]</elemparam>
                      <layer>[framing_contour_line_layer;default=]</layer>
                    </contourlines>
                  </projection>
                </group>
                <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_intboards2" elemid="0" layoutminheight="3"></cutlist>
              </group>
            </group>

            <!-- PAGE 3, BOARD+STUD H -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page3_layout_name;default=BOARD2]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="[page3_proj1_name;default=FROM INSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1,1" exclude="[page3_proj1_exclude;default=extstud*,boarding*,finish*,core]" boardpanels="[page3_proj1_boards;default=boarding_int3]">
                    <dimlines>
                      <dimline ref="boards_and_studh"></dimline>
                    </dimlines>
                    <contourlines create="1" holes="0">
                      <elemparam name="pen">[framing_contour_line_pen]</elemparam>
                      <elemparam name="linetype">[framing_contour_linetype]</elemparam>
                      <layer>[framing_contour_line_layer;default=]</layer>
                    </contourlines>
                  </projection>
                </group>
                <group layout="vertical">
                  <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_intboards3" elemid="0" layoutminheight="0"></cutlist>
                  <cutlist layoutmargins="0,0.5,0,0.5" settingsref="cutlist_table_intstuds" elemid="0" layoutminheight="0"></cutlist>
                </group>
              </group>
            </group>

            <!-- PAGE 4, BOARD -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page4_layout_name;default=INT STUD]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="[page4_proj1_name;default=FROM INSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1,1" exclude="[page4_proj1_exclude;default=*]" boardpanels="[page4_proj1_boards;default=boarding_int4]">
                    <dimlines>
                      <dimline ref="kw_levy"></dimline>
                    </dimlines>
                    <contourlines create="1" holes="0">
                      <elemparam name="pen">[framing_contour_line_pen]</elemparam>
                      <elemparam name="linetype">[framing_contour_linetype]</elemparam>
                      <layer>[framing_contour_line_layer;default=]</layer>
                    </contourlines>
                  </projection>
                </group>
                <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_intboards4" elemid="0" layoutminheight="3"></cutlist>
              </group>
            </group>

            <!-- PAGE 5, WINDSHIELD BOARDS -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page5_layout_name;default=WS BOARDS]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="[page5_proj1_name;default=FROM OUTSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1,1" exclude="[page5_proj1_exclude;default=intstud*,extstud*,boarding*,finish*]" boardpanels="[page5_proj1_boards;default=boarding_ext,boarding_ext2]">
                    <dimlines>
                      <dimline ref="kw_levy"></dimline>
                    </dimlines>
                    <projplanksettings type="core">
                      <elemparam name="linetype">[framing_contour_linetype]</elemparam>
                      <objparam name="iFill">0</objparam>
                      <objparam name="iShowID">0</objparam>
                      <objparam name="iShowLen">0</objparam>
                      <elemparam name="pen">[framing_contour_line_pen]</elemparam>
                    </projplanksettings>
                  </projection>
                </group>
                <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_extboards2" elemid="0" layoutminheight="3"></cutlist>
              </group>
            </group>

            <!-- PAGE 6, CLAD+STUD H -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">[page6_layout_name;default=CLADDING]</objparam>
              </frame>
              <group layout="horizontal">
                <text content="[page6_proj1_name;default=FROM OUTSIDE]" anchor="1" x="3" y="-0.2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <group layout="vertical">
                  <projection type="front" layoutmargins="3,0.5,1,1" exclude="[page6_proj1_exclude;default=intstud*,boarding*,core]" boardpanels="[page6_proj1_boards;default=finish]">
                    <dimlines>
                      <dimline ref="boards_and_studh"></dimline>
                    </dimlines>
                    <contourlines create="1" holes="0">
                      <elemparam name="pen">[framing_contour_line_pen]</elemparam>
                      <elemparam name="linetype">[framing_contour_linetype]</elemparam>
                      <layer>[framing_contour_line_layer;default=]</layer>
                    </contourlines>
                  </projection>
                </group>
                <group layout="vertical">
                  <cutlist layoutmargins="0,0.5,0.2,0.5" settingsref="cutlist_table_extcladstuds" elemid="0" layoutminheight="0"></cutlist>
                </group>
              </group>
            </group>

          </group>
        </projections>
      </elemtemplate>
      <!-- 2020_06 end-->

      <!-- Added 2020_11 -->
      <elemtemplate class="composite" templateid="usa_extwall_cab_f_bb_1.0" templatename="Multisheet external wall from out to in Clad+Stud V+Board+Frame+Board+Board v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=0]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="vertical">
            <!-- PAGE 1 -->
            <group layout="vertical">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">MAIN</objparam>
              </frame>
              <group layout="vertical">
                <text content="#id#" anchor="7" x="0" y="0.1" update="1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">30</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <text content="CORE FROM OUTSIDE" content_fin="RUNKO ULKOA" anchor="1" x="6" y="-2">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="6,0.5,3,0.5" exclude="[excludeext;default=intstud*,extstud*]" boardpanels="[boardpanelsext;default=]">
                  <dimlines>
                    <dimline ref="an_framing"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <opening text="#id#\n#width#\nx\n#height#">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="fontname">Arial</elemparam>
                      <elemparam name="fontsize">1.5</elemparam>
                      <elemparam name="fontstyle"></elemparam>
                      <elemparam name="just">center</elemparam>
                      <framelines create="[create_openig_frame_lines;default=0]">
                        <elemparam name="pen">1</elemparam>
                        <elemparam name="linetype">1</elemparam>
                      </framelines>
                    </opening>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=3]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                    <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                      <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                      <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                      <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                      <line>
                        <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                        <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                      </line>
                    </topplankangledim>
                  </elemmarkings>
                  <projplanksettings type="extstud*">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <projection type="top" layoutmargins="6,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                  <dimlines>
                    <dimline ref="wall_top"></dimline>
                  </dimlines>
                  <elemmarkings>
                    <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                      <settings>
                        <layer>[layer_weight;type=layer]</layer>
                        <objparam name="iFill">*25*</objparam>
                        <objparam name="A">0.250</objparam>
                        <objparam name="B">0.325</objparam>
                      </settings>
                    </weight>
                  </elemmarkings>
                </projection>
              </group>

              <group layout="horizontal" >
                <cutlist layoutmargins="4.5,0.1,0.1,0.1" settingsref="cutlist_table_corestuds" elemid="0" layoutminheight="3"></cutlist>
                <cutlist layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_coreothers" elemid="0"></cutlist>
              </group>
            </group>

            <!-- PAGE 2 -->
            <group layout="horizontal">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">EXTERIOR</objparam>
              </frame>
              <group layout="vertical">
                <text content="WINDSHIELD BOARDS FROM OUTSIDE" content_fin="TS-LEVYT ULKOA" anchor="7" x="2" y="-0.9">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[windshieldboards;default=boarding_ext*]" exclude="[excludeext_windshield;default=intstud*,extstud*]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <text content="CLADDING FROM OUTSIDE" content_fin="VERHOILU ULKOA" anchor="7" x="2" y="0.1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="front" layoutmargins="2,0,0,1" boardpanels="finish_ext" exclude="[exclude_cladding;default=intstud*,extstud2]">
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*|*katkoviiva*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>
              </group>
              <group layout="vertical" layoutmargins="1,0,0.1,0">
                <cutlist layoutmargins="0.1,0.1,0,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards" elemid="0"></cutlist>
                <cutlist layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extcladstuds" elemid="0"></cutlist>
              </group>
            </group>

            <!-- PAGE 3 -->
            <group layout="horizontal">
              <frame x1off="0.01" x2off="-0.01" y1off="0.01" y2off="-0.01">
                <objparam name="name">INTERIOR</objparam>
              </frame>
              <group layout="vertical">
                <text content="BOARD1 FROM INSIDE" content_fin="LEVY1 SISÄLTÄ" anchor="1" x="2" y="-0.05">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="back" layoutmargins="2,0,1,0.5" exclude="[page3_proj1_exclude;default=extstud*,boarding*,finish*]" boardpanels="[page3_proj1_boards;default=boarding_int2]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core">
                    <elemparam name="linetype">*dash*|*katkoviiva*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>

                <text content="BOARD2 FROM INSIDE" content_fin="LEVY2 SISÄLTÄ" anchor="7" x="2" y="0.1">
                  <elemparam name="pen">1</elemparam>
                  <elemparam name="fontname">arial</elemparam>
                  <elemparam name="fontsize">2.5</elemparam>
                  <elemparam name="fontstyle"></elemparam>
                </text>
                <projection type="back" layoutmargins="2,0,0,1" exclude="[page3_proj2_exclude;default=extstud*,boarding*,finish*]" boardpanels="[page3_proj2_boards;default=boarding_int3,core]">
                  <dimlines>
                    <dimline ref="kw_levy"></dimline>
                  </dimlines>
                  <projplanksettings type="core" objtype="1">
                    <elemparam name="linetype">*dash*|*katkoviiva*</elemparam>
                    <objparam name="iFill">0</objparam>
                    <objparam name="iShowID">0</objparam>
                    <objparam name="iShowLen">0</objparam>
                    <elemparam name="pen">2</elemparam>
                  </projplanksettings>
                </projection>
              </group>
              <group layout="vertical" layoutmargins="1,0.5,0,1" >
                <cutlist layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="3.50" settingsref="cutlist_table_intboards2" elemid="0"></cutlist>
                <cutlist layoutmargins="0.1,0.1,0.5,0.1" layoutminwidth="3.50" settingsref="cutlist_table_intboards3" elemid="0"></cutlist>
                <cutlist create="[insu_create_cutlist;type=real;default=0]" layoutmargins="0.1,0.1,0.1,0.1" settingsref="cutlist_table_insulation"></cutlist>
              </group>
            </group>
          </group>
        </projections>
      </elemtemplate>
      

      <elemtemplate class="composite" templateid="composite_outin" templatename="Looked from out to in" templatename_fin="Katselusuunta ulkoa sisälle" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="[cutlist;default=cutlist;prompt=cutlist or cutlist_table]" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[boardpanelsext;default=finish_ext,boarding_ext*]" exclude="[excludeext;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
                <elemmarkings>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                </elemmarkings>
              </projection>
              <projection type="back" layoutmargins="2,0.5,0,1" boardpanels="[boardpanelsint;default=boarding_int*]" exclude="[excludeint;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                </elemmarkings>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtemplate>

      <elemtemplate class="composite" templateid="composite_inout" templatename="Looked from in to out" templatename_fin="Katselusuunta sisältä ulos" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="cutlist" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[boardpanelsint;default=boarding_int*]" exclude="[excludeint;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
                <elemmarkings>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_top;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                </elemmarkings>
              </projection>
              <projection type="back" layoutmargins="2,0.5,0,1" boardpanels="[boardpanelsext;default=finish_ext,boarding_ext*]" exclude="[excludeext;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                </elemmarkings>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtemplate>

      <elemtemplate class="composite" templateid="composite_outin_single" templatename="Looked from out to in single projection" id="[id]" templatename_fin="Katselusuunta ulkoa sisälle yksi projektio" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="[cutlist;default=cutlist;prompt=cutlist or cutlist_table]" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[boardpanelsext;default=finish_ext,boarding_ext*]" exclude="[excludeext;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtemplate>

      <elemtemplate class="composite" templateid="composite_inout_single" templatename="Looked from in to out single projection" templatename_fin="Katselusuunta sisältä ulos yksi projektio" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="[cutlist;default=cutlist;prompt=cutlist or cutlist_table]" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[boardpanelsint;default=boarding_int*]" exclude="[excludeint;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>
              <projection type="top" layoutmargins="2,0.5,0,0.5" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtemplate>

      <elemtemplate class="composite" templateid="composite_fromtop" templatename="Floors/roofs looked from top" templatename_fin="Lattiat ja katot ylhäältä katsottuna" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>

        <!-- Content of <layers> will be added by custom element tool -->

        <!-- Projections for the element inside one frame from top to bottom -->
        <projections>
          <group layout="horizontal">
            <group layout="vertical">
              <cutlist layoutalign="-1" layoutmargins="0.1,0.1,0.1,0.1" layoutminwidth="2.0" layoutminheight="7.0" settingsref="[cutlist;default=cutlist;prompt=cutlist or cutlist_table]" elemid="0"></cutlist>
            </group>
            <group layout="vertical">
              <projection type="front" layoutmargins="2,0.5,1,1" boardpanels="[boardpanelsext;default=finish_ext,boarding_ext*]" exclude="[excludeext;default=intstud*,extstud*]" rotate="[rotproj;default=0]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening text="#id#\n#width#\nx\n#height#">
                    <elemparam name="pen">1</elemparam>
                    <elemparam name="fontname">Arial</elemparam>
                    <elemparam name="fontsize">1.5</elemparam>
                    <elemparam name="fontstyle"></elemparam>
                    <elemparam name="just">center</elemparam>
                    <framelines create="[create_openig_frame_lines;default=0]">
                      <elemparam name="pen">1</elemparam>
                      <elemparam name="linetype">1</elemparam>
                    </framelines>
                  </opening>
                  <weight libname="{FD6C137D-C647-42FD-A904-181281909443}-{9060078A-0F41-48C8-8400-8E414A838053}" create="[show_weight_front;default=0]" text="[weight_text;default=(weight) KG]" units="[weight_unit;default=kg]">
                    <settings>
                      <layer>[layer_weight;type=layer]</layer>
                      <objparam name="iFill">*25*</objparam>
                      <objparam name="A">0.250</objparam>
                      <objparam name="B">0.325</objparam>
                    </settings>
                  </weight>
                  <topplankangledim create="[top_angle_create;default=0]" yoffset="[top_angle_yoffset;default=0;type=length]" radius="[top_angle_radius;default=0;type=length]">
                    <elemparam name="markertype">[top_angle_markertype;default=5]</elemparam>
                    <elemparam name="markersize">[top_angle_markersize;default=1]</elemparam>
                    <elemparam name="pen">[top_angle_pen;default=1]</elemparam>
                    <line>
                      <elemparam name="pen">[top_angle_line_pen;default=1]</elemparam>
                      <elemparam name="linetype">[top_angle_line_type;default=1]</elemparam>
                    </line>
                  </topplankangledim>
                </elemmarkings>
              </projection>
              <projection type="bottom" layoutmargins="2,0.5,0,1" boardpanels="[boardpanelstop;default=*]">
                <dimlines>
                  <dimline ref="wall_top"></dimline>
                </dimlines>
              </projection>
              <!--projection type="back" layoutmargins="2,0.5,0,1" boardpanels="[boardpanelsint;default=boarding_int*]" exclude="[excludeint;default=intstud*,extstud*]">
                <dimlines>
                  <dimline ref="wall_elevation"></dimline>
                </dimlines>
                <elemmarkings>
                  <opening ref="mark_opening"></opening>
                </elemmarkings>
              </projection-->
              <elemstamp layoutalign="-1" layoutmargins="-2.2,0,0,0" layoutminwidth="10.0" layoutminheight="1.0" libname="{9FD03D30-6A12-4B0F-AB3A-01410A529E38}-{D420792D-C066-42CF-988C-9596DD164EB7}" settingsref="elemstamp">
                <script ref="elemstamp"></script>
              </elemstamp>
            </group>
          </group>
        </projections>
      </elemtemplate>


      <elemtemplate class="composite" templateid="composite_noproj" templatename="No projections" templatename_fin="Ei elementtikuvia" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]">
        <settings>
          <masterelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">[showelemtype;default=1]</objparam>
            <objparam name="iShowID2D">1</objparam>
            <objparam name="iShowID3D">1</objparam>
          </masterelem>
          <slaveelem>
            <layer>[layer;type=layer]</layer>
            <objparam name="iShowElemType">0</objparam>
            <objparam name="iShowID2D">0</objparam>
            <objparam name="iShowID3D">0</objparam>
          </slaveelem>
        </settings>
      </elemtemplate>
    </elemtemplates>

    <options>
      <!-- To split into rolldown panes -->
      <optiongroups>
        <optiongroup id="topbot" name="Top and bottom" name_fin="Ylä ja ala" name_nor="Topp og bunn" name_por="Topo e base"/>
        <optiongroup id="mark" name="Markings" name_fin="Merkinnät" name_nor="Markings" name_por="Marcas"/>
        <optiongroup id="vert" name="Studding" name_fin="Tolpitus" name_nor="Studding" name_por="Studding"/>
        <optiongroup id="hor" name="Horizontal" name_fin="Vaakarakenteet" name_nor="Horizontal" name_por="Horizontal"/>
        <optiongroup id="settings" name="Settings" name_fin="Asetukset" name_nor="Settings" name_por="Definições"/>
      </optiongroups>

      <option groupid="topbot" id="doubletop" name="Double top" name_fin="Tuplayläjuoksu" name_nor="Dobbel Toppsvill" name_swe="Dubbla hammarband" name_ger="Doppelter oberer Lauf" name_ita="Raddoppia superiore" name_por="Dobro superior">
        <!-- If there is already grotop for the element, remove existing and set after running this option -->
        <reapply id="grotop"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <reapply id="balktopint"></reapply>
        <reapply id="balktopext"></reapply>
        <reapply id="reinforceall"></reapply>
        <reapply id="reinforcebotint"></reapply>
        <reapply id="reinforcebotext"></reapply>
        <reapply id="autocuttopbot"></reapply>
        <script ref="doubletopbot">
          <![CDATA[
gbTop=true
gsTopBotGroup="top_force"
gsDoubleGroup="2ndtop_force"
  ]]>
        </script>
      </option>

      <option groupid="topbot" id="doublebot" name="Double bottom" name_fin="Tupla-alajuoksu" name_nor="Dobbel Bunnsvill" name_swe="Dubbel syll" name_ger="Doppelter unterer Lauf" name_ita="Raddoppia inferiore" name_por="Dobro inferior">
        <!-- If there is already grobot for the element, remove existing and set after running this option -->
        <reapply id="grobot"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <reapply id="reinforceall"></reapply>
        <reapply id="reinforcebotint"></reapply>
        <reapply id="reinforcebotext"></reapply>
        <reapply id="autocuttopbot"></reapply>
        <script ref="doubletopbot">
          <![CDATA[
gbTop=false
gsTopBotGroup="bottom_force"
gsDoubleGroup="2ndbottom_force"
  ]]>
        </script>
      </option>


      <option groupid="topbot" id="balktopint" name="Top balk back" name_fin="Yläpalkki taka" name_nor="Topp Bjelke back" name_swe="Översta balk back" name_ger="Oberster Balken back" name_ita="Trave di Supporto Superiore - Retro" name_por="Trave de Suporte Superior - Atrás">
        <script ref="balktop">
          <![CDATA[
gOptGroupName="balktopin"
gOptInOut="in"
]]>
        </script>
      </option>

      <option groupid="topbot"  id="balktopext" name="Top balk front" name_fin="Yläpalkki etu" name_nor="Topp Bjelke Front" name_swe="Översta balk front" name_ger="Oberster Balken front" name_ita="Trave di Supporto Superiore - Fronte" name_por="Trave de Suporte Superior - Frente">
        <script ref="balktop">
          <![CDATA[
gOptGroupName="balktopout"
gOptInOut="out"
]]>
        </script>
      </option>

      <option groupid="topbot" id="reinforcebotint" name="Bottom balk back" name_fin="Palkki ala taka" name_ita="Trave di Supporto Inferiore - Retro" name_por="Trave de Suporte Inferior - Atrás" ordernum="999">
        <script ref="doubletopbot" ref1="reinforceall">
          g_issingle=true
          g_topin=0
          g_topout=0
          g_botin=1
          g_botout=0
          g_botinname="balkbottomin"
          g_botoutname="balkbottomout"
        </script>
      </option>

      <option groupid="topbot" id="reinforcebotext" name="Bottom balk front" name_fin="Palkki ala etu" name_ita="Trave di Supporto Inferiore - Fronte" name_por="Trave de Suporte Inferior - Frente" ordernum="999">
        <script ref="doubletopbot" ref1="reinforceall">
          g_issingle=true
          g_topin=0
          g_topout=0
          g_botin=0
          g_botout=1
          g_botinname="balkbottomin"
          g_botoutname="balkbottomout"
        </script>
      </option>

      <option groupid="topbot" id="reinforceall" name="Reinforce ALL" name_fin="Palkit kaikkialle" name_ita="Trave di Supporto - TUTTO" name_por="Trave de Suporte - TODOS" ordernum="999">
        <script ref="doubletopbot" ref1="reinforceall">
        </script>
      </option>

      <option groupid="topbot" id="walltofloortop" name="Wall to floor joint top" name_fin="Seinän yläreuna -> VP" ordernum="999">
        <script ref="walltofloortop">
        </script>
      </option>

        <option groupid="topbot" id="splitbot" name="Split bottom" name_fin="Alajuoksu kahdella kappaleella" name_nor="Splitt Bunnsvill" name_swe="Beskär nedre ända" name_ger="Zweiteliger unterer Lauf" name_ita="Dividi Perimetrale Inferiore (Binario)" name_por="Dividir Perímetro Inferior (Binário)" ordernum="998">
          <script ref="splittopbot">
            <![CDATA[
gbTop=false
gsTopBotGroup="bottom_force"
gsSplitGroup="bottom_forcesplit"
]]>
          </script>
        </option>

        <!--option id="grobot" name="Grooves bottom 2 mm" name_fin="Urat ala 2 mm" name_nor="Spor Bunnsvill 2 mm" name_swe="Skarv nedre ända 2 mm" name_ger="Rillen unten 2mm" name_ita="Scanalatura Inferiore 2mm" name_por="Ranhura Inferior 2mm" ordernum="999">
        <script ref="grotopbot">
          <![CDATA[
gOptGroTop=false
]]>
        </script>
      </option-->

      <!--option id="grotop" name="Grooves top 2 mm" name_fin="Urat ylä 2 mm" name_nor="Spor Toppsvill 2 mm" name_swe="Skarv övre ända 2 mm" name_ger="Rillen oben 2mm" name_ita="Scanalatura Superiore 2mm" name_por="Ranhura Superior 2mm" ordernum="999">
        <script ref="grotopbot">
          <![CDATA[
gOptGroTop=true
]]>
        </script>
      </option-->

      <option groupid="mark" id="markingsgro" name="Marking grooves" name_fin="Merkintäurat" name_ita="Scanalatura Montanti" name_por="Ranhura Montante" ordernum="999">
        <script ref="markingsgro">
        </script>
      </option>


      <option groupid="mark" id="markingslines" name="Marking lines" name_fin="Merkintäviivat" name_ita="Traccia dei Montanti" name_por="Traço dos Montantes" reapplyupdate="1" ordernum="1010">
        <script ref="markingslines">
        </script>
      </option>


      <!-- applystate="prespacing" means that option is applied before adding pieces from spacing rules -->
      <option groupid="vert" id="openingsides" name="Planks to openings sides" name_fin="Laudat aukkojen sivuille" name_nor="Utfyllingsbord" name_swe="Reglar för öppningens sidor" name_ger="Bretter an Seiten der Öffnung" name_ita="Telaio Verticale Finestra" name_por="Moldura de Janela Vertical" applystate="prespacing">
        <script ref="openingsides">
          <![CDATA[
]]>
        </script>
      </option>

      <option groupid="vert" id="openingdouble" name="Double studs to opening sides" name_fin="Tuplatolppa aukkojen sivuille" name_ita="Doppio Montante a Lato Finestra" name_por="Barra Vertical Dupla no Lado da Janela" applystate="prespacing">
        <reapply id="grotop"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="openingdouble">
          <![CDATA[
]]>
        </script>
      </option>

      <option groupid="vert" id="cornerdouble" name="Double studs to left and right" name_fin="Tuplatolppa reunoille" name_ita="Doppio Montante a Sinistra e Destra" name_por="Dupla Vertical Esquerda e Direita" applystate="prespacing">
        <reapply id="grotop"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="cornerdouble">
          <![CDATA[
]]>
        </script>
      </option>

      <option groupid="hor" id="lintenoload" name="Lintels no load (set only)" name_fin="Aukonylityspalkki ei-kantava (vain aseta)" name_nor="Overdekkning Ikke bærende" name_swe="Överliggare utan belastning (fasta inställningar)" name_ger="Überbruckungsbalken unbelastet (nur setzen)" name_ita="Architrave Non-Portante (solo Posiz.)" name_por="Lintéis sem carga (conjunto apenas)">
        <script ref="lintels">
          <![CDATA[
function Set()
  DoLintelNoLoad()
end
]]>
        </script>
      </option>


      <option groupid="hor" id="linteload" name="Lintels load bearing (set only)" name_fin="Aukonylityspalkki kantava (vain aseta)" name_nor="Overdekkning  bærende" name_swe="Överliggare med belastning (fasta inställningar)" name_ger="Überbruckungsbalken tragend (nur setzen)" name_ita="Architrave Portante (solo Posiz.)" name_por="Lintéis em Carga (conjunto apenas)">
        <script ref="lintels">
          <![CDATA[
function Set()
  DoLintelLoad()
end
]]>
        </script>
      </option>


      <option groupid="hor" id="lintelcustom" name="Lintels custom for selected pieces" name_fin="Aukonylityspalkki säädöillä valittuihin" name_nor="Overdekkning manuell" name_swe="Anpassad överliggare för valda delar" name_ger="Manueller Überbrückungsbalken" name_ita="Architrave Personale per Elementi selez." name_por="Lintéis à medida para peças seleccionadas" type="button">
        <reapply id="grotop"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="lintels">
          <![CDATA[
-- Called before setting to individual elements
function OnPreSet()
  gtblSettings=nil
  gbCancel=false
end

function Set()
  if not DoLintelCustom() then
    gbCancel=true
  end
end
]]>
        </script>
      </option>

      <option groupid="hor" id="windoorcuts" name="Cut window/door sills" name_fin="Ikkunan/oven alle viiste" name_ita="Taglia soglia da Porte/Finestre" name_por="Chanfro sob a janela/porta">
        <script ref="openingsbotcut">
        </script>
      </option>

      <option groupid="topbot" id="autocuttopbot" name="Automatic cut top and bottom" name_fin="Katko ylä- ja alajuoksu automaattisesti" name_ita="Taglio automatico superiore e inferiori" name_por="Corte superior e inferior automático">
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="autocuttopbot">
        </script>
      </option>

      <option groupid="vert" id="openingsupport" name="Opening support" name_fin="Tolpat aukon vaakapuun reunoihin" name_ita="Supporto per le Aperture" name_por="Suporte de Abertura">
        <reapply id="grobot"></reapply>
        <reapply id="grotop"></reapply>
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="openingsupport">
        </script>
      </option>

      <option groupid="vert" id="autocutstud" name="Automatic cut studding" name_fin="Katko koolaus automaattisesti">
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply>
        <reapply id="markingsgro"></reapply>
        <script ref="autocutstud">
        </script>
      </option>

      <option groupid="vert" id="floorsides" name="Floor side pieces" name_fin="Lattian reunavasat" type="button">
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply>
        <reapply id="markingsgro"></reapply>
        <script ref="floorsideplanks">
        </script>
      </option>


      <option groupid="hor" id="noggings" name="Noggings" name_fin="Nurjahduksenestokapulat" name_ita="Traverse" name_por="Tabique">
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="noggings">
        </script>
      </option>

      <option groupid="hor" id="boardedgesupportfront" name="Board edge support front" name_fin="Levysaumatuki etu" ordernum="999" applystate="postcreatelayers">
        <script ref="boardedgesupport">
          <![CDATA[
            g_OptGroupName="boardedgesupport_front"
            g_side=1
          ]]>
        </script>
      </option>

      <option groupid="hor" id="boardedgesupportback" name="Board edge support back" name_fin="Levysaumatuki taka" ordernum="999" applystate="postcreatelayers">
        <script ref="boardedgesupport">
            g_OptGroupName="boardedgesupport_back"
            g_side=2
        </script>
      </option>

      <option groupid="mark" id="automodule" name="Automatic opening module IDs" name_fin="Automaattiset aukkomoduulitunnukset" name_ita="ID Automatico Aperture" name_por="ID Automatico de Abertura">
        <script>
          <![CDATA[
function Set()
  af_request("elem_automodules")
end

-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return ResetInt(false)
end


function Reset()
  ResetInt(true)
end

function ResetInt(execute)
  local i,s, res
  
  res=false
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s=ac_objectget("iElemModule")
    if s and s~="" then
      res=true
      if not execute then
        break
      end
      ac_objectset("iElemModule", "")
    end
    ac_objectclose()
  end
  
  return res
end
]]>
        </script>
      </option>


      <option groupid="settings" id="elemsettings" name="Element settings" name_fin="Elementtiasetukset" name_ita="Settaggi Elementi" name_por="Definições de Elemento">
        <script ref="elemsettings">
        </script>
      </option>
    </options>


    <corners>
      <!-- Script included to every corner type. Contains all corner types -->
      <common_script>
        <![CDATA[
-- ArchiFrame sets globals:
-- gAdjustElems true=type set from corner UI, set elements - no planking, false=called after creating planks - adjust planks
-- gbCornerFindOther, UI value for check box Find connecting corner
-- gbCornerAdjustOther, UI value for check box Adjust connecting corner
-- Type numbers: 1 long, 2 long left, 3 long right, 4=long left2, 5=long right2, 6=long corner to corner style, 7=Long double at the end
-- 8=Long left variation 3, 9=Long right variation 3 (also used for short)
-- 100 hedalm style, 101 anebyhus, 102 omatalo, 108=Nordic Baltic left, 109=Nordic Baltic right
-- 110=Plusshus long ext, 110=Plusshus short ext
-- 120=YIT long/short outer corner
-- 121=YIT long/short inner corner


-- Compatibility with older prog version
function IsFindOther()
  return gbCornerFindOther==nil or gbCornerFindOther==true
end

function IsAdjustOther()
  return gbCornerAdjustOther==nil or gbCornerAdjustOther==true
end


-- Dumps given variable into string
function DumpTblInt(o)
  local s,k,v
  
  if type(o) == 'table' then
    s = '{ '
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"'..k..'"' end
      s = s .. '['..k..'] = ' .. DumpTblInt(v) .. ','
    end
    s=s .. '} '
  else
    s=tostring(o)
  end
  return s
end


function DumpTbl(o)
  ac_environment("tolog", DumpTblInt(o))
end

function FindStuds()
  local tblStuds, plank, i, s, nStuds

  tblStuds={}
  nStuds=0

  tblStuds={}
  nStuds=0

  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s=ac_objectget("iElemGroup")
    if string.match(s, "^vertical_%a*") then
      plank={}
      plank.elemgroup=s
      plank.elemdata=ac_objectget("#af_elemdata")
      if math.abs(plank.elemdata.x1-plank.elemdata.x2)<0.001 then
        plank.plankinfo=af_request("plankinfo")
        nStuds=nStuds+1
        tblStuds[nStuds]=plank
      end
    end
    ac_objectclose()
  end

  return tblStuds,nStuds
end


function FindThickerMat(orgMatId)
  local tblMat, i, v, matInfo

  
  matInfo=af_request("singlemat", orgMatId)
  
  tblMat=af_request("matlist")
  for i,v in pairs(tblMat) do
    if v.thickness>0.001 and v.thickness>matInfo.thickness+0.001 and v.thickness<matInfo.thickness*1.5 and math.abs(v.height-matInfo.height)<0.0009 then
      -- Return first applicable
      return v.id
	  end
  end

  return nil
end


-- Adjusts planks for given corner 1/2
-- nType  See top
-- Called with element planks opened
function DoLongPlanks(layerType, nCorner, nType, guidElem)
  local tblStuds, plank, i, s, nStuds, dir, nCreate

  gtblCreate={}
  nCreate=0
  
  if nCorner>2 then
    return
  end

  dir=1
  if nCorner==2 then
    -- Right
    dir=-1
  end

  ac_objectopen(guidElem)
  s=ac_objectget("iElemTypeId")
  ac_objectclose()
  if string.match(s, "%a*HOR$") then
    -- Horizontal element
    if layerType=="intstud" and nType>=2 and nType<=5 then
      -- Change top piece to bigger
      local i, s, newType, info

      af_request("elem_getpoly")
      

      for i=1,gnPlanks do
        ac_objectopen(string.format("#%d", i))
        s=ac_objectget("iElemGroup")
        if (s=="top_force" and nCorner==1) or (s=="bottom_force" and nCorner==2) then
          info=af_request("plankinfo")
          s=ac_objectget("iMatId")
          tblEdit={}
          tblEdit.elemdata=ac_objectget("#af_elemdata")
          tblEdit.guid=tblEdit.elemdata.ptr
          tblEdit.mat=nil
          
          if s=="45x45" then
            if af_request("singlemat", "45x95")~=nil then
              -- Ökoehituse
              tblEdit.mat="45x95"
            end
          end

          if tblEdit.mat==nil then
            -- Block
            tblEdit.mat="block"
            tblEdit.thickness=info.width
            tblEdit.height=info.height*2
          end

          tblEdit.elemdata.rotangle=-90
          if nCorner==2 then
            tblEdit.elemdata.rotangle=90
          end

          tblEdit.elemdata.x1=tblEdit.elemdata.x1-info.width*dir*0.5
          tblEdit.elemdata.z1=tblEdit.elemdata.z1+info.height*0.5
          tblEdit.elemdata.x2=tblEdit.elemdata.x2-info.width*dir*0.5
          tblEdit.elemdata.z2=tblEdit.elemdata.z1

          af_request("editplank", tblEdit)

        end
        ac_objectclose()
      end
    end
    return
  end

  af_request("elem_getpoly")
  tblStuds,nStuds=FindStuds()
  if #tblStuds<1 then
    return
  end

  -- Sort so that corner piece is the first one in the table
  if nCorner==1 then
    -- Left side
	  table.sort(tblStuds, function (n1, n2)
      return n1.elemdata.x1 < n2.elemdata.x1
	  end)
  else
    -- Right side
	  table.sort(tblStuds, function (n1, n2)
      return n1.elemdata.x1 > n2.elemdata.x1
	  end)
  end

  local nStud, stud, x1, x2, w2

  if layerType=="core" then
    -- core - Duplicate the corner stud
    nStud=1
    while tblStuds[1] and tblStuds[nStud] and math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]
    
      plank={}
      plank.guidsettings=stud.elemdata.ptr
      
      w2=stud.plankinfo.width*0.5
      if (nType>=2 and nType<=5) or nType==8 or nType==9 or nType==108 or nType==109 then
        -- L
        local orgMatId, addx
        
        ac_objectopen(stud.elemdata.ptr)
        orgMatId=ac_objectget("iMatId")
        ac_objectclose()
        addx=0
        
        if nType==8 or nType==9 or nType==108 or nType==109 then
          -- Duplicate end piece and make the last one slightly thicker - find the thicker material
          local newMat

          newMat=FindThickerMat(orgMatId)
          if newMat then
            local tblEdit, dx
            
            addx=(af_request("singlemat", newMat).thickness-stud.plankinfo.width) * 0.5
            dx=dir*addx

            tblEdit={}
            tblEdit.guid=stud.elemdata.ptr
            tblEdit.elemdata=stud.elemdata
            tblEdit.elemdata.x1=tblEdit.elemdata.x1+dx
            tblEdit.elemdata.x2=tblEdit.elemdata.x2+dx
            tblEdit.mat=newMat

            af_request("editplank", tblEdit)
          end
          
          -- Duplicate corner stud
          plank.group="vertical_force"
          plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.width+addx)
          plank.y1=stud.elemdata.y1
          plank.x2=plank.x1
          plank.y2=stud.elemdata.y2
          plank.extendtoelem=1
          plank.id=orgMatId
          nCreate=nCreate+1
          gtblCreate[nCreate]=plank
          plank={}
          plank.guidsettings=stud.elemdata.ptr
          
          addx=addx+stud.plankinfo.width
        end
        
        if nType==4 or nType==5 or nType==8 or nType==9 or nType==108 or nType==109 then
          plank.group="vertical_force"
          plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.width+stud.plankinfo.height+addx)
          plank.y1=stud.elemdata.y1
          plank.x2=plank.x1
          plank.y2=stud.elemdata.y2
          plank.extendtoelem=1
          plank.id=orgMatId
          nCreate=nCreate+1
          gtblCreate[nCreate]=plank
          plank={}
          plank.guidsettings=stud.elemdata.ptr
        end

        plank.group="vertical_force"
        plank.x1=stud.elemdata.x1+dir*(w2+addx)
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        if nType==3 or nType==5 or nType==9 then
          plank.zoff=w2
        else
          plank.zoff=stud.plankinfo.height-w2
        end
        plank.rotangle=-90*dir
        plank.extendtoelem=1
        plank.id=orgMatId
        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*(w2+addx+stud.plankinfo.height)
        if nType>=4 then
          x2=x2+dir*stud.plankinfo.width
        end
      elseif nType==100 or nType==102 then
        -- Hedalm Long, Omatalo long duplicate end
        if nType==100 then
          plank.group="vertical_force"
          plank.x1=stud.elemdata.x1+dir*stud.plankinfo.width
          plank.y1=stud.elemdata.y1
          plank.x2=plank.x1
          plank.y2=stud.elemdata.y2
          plank.extendtoelem=1
          nCreate=nCreate+1
          gtblCreate[nCreate]=plank
        end
        
        -- Duplicate another
        plank={}
        plank.guidsettings=stud.elemdata.ptr
        plank.group="vertical_force"
        if nType==100 then
        plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.height+0.063)     -- Gives 229-36/2 mm for 148 mm stud
        else
          plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.height-stud.plankinfo.width)
        end
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1

        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      elseif nType==101 then
        -- Anybyhus duplicate closer
        plank.group="vertical_force"
        plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.height-w2-w2)
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1
        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      elseif nType==110 then
        -- Plusshus duplicate further
        plank.group="vertical_force"
        plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.height+0.045)
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1
        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      elseif nType==120 then
        -- YIT long ext
        -- Duplicate another
        plank={}
        plank.guidsettings=stud.elemdata.ptr
        plank.group="vertical_force"
        plank.x1=stud.elemdata.x1+dir*(stud.plankinfo.height-stud.plankinfo.width+0.009)
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1

        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      elseif nType==121 then
        -- YIT long ext inner
        -- Duplicate another
        plank={}
        plank.guidsettings=stud.elemdata.ptr
        plank.group="vertical_force"
        plank.x1=stud.elemdata.x1+dir*0.290
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1

        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      else
        -- Duplicate, types 1,6,7
        plank.group="vertical_force"
        if nType==7 then
          plank.x1=stud.elemdata.x1+dir*stud.plankinfo.width
        else
          plank.x1=stud.elemdata.x1+dir*stud.plankinfo.height
          if nType==1 then
            plank.x1=plank.x1-dir*w2
          end
        end
        plank.y1=stud.elemdata.y1
        plank.x2=plank.x1
        plank.y2=stud.elemdata.y2
        plank.extendtoelem=1
        x1=stud.elemdata.x1-dir*w2
        x2=plank.x1+dir*w2
      end

      nCreate=nCreate+1
      gtblCreate[nCreate]=plank
      af_request("elem_marknoplanks", x1, plank.y1-10, x2, plank.y2+10)
      
      nStud=nStud+1
    end
  elseif layerType=="intstud" and nType==120 then
    nStud=1
    while tblStuds[nStud] and math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      -- Corner piece duplicated
      plank={}
      plank.guidsettings=stud.elemdata.ptr
      plank.group="vertical_force"
      
      plank.x1=stud.elemdata.x1+dir*(0.009+0.198)
      plank.y1=stud.elemdata.y1
      plank.x2=plank.x1
      plank.y2=stud.elemdata.y2
      plank.extendtoelem=1
      plank.force=true
      
      nCreate=nCreate+1
      gtblCreate[nCreate]=plank

      nStud=nStud+1
    end

  elseif layerType=="intstud" and nType==121 then
    local x1, x2

    nStud=1
    while tblStuds[nStud] and math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      -- Corner piece rotated and different material
      tblEdit={}
      tblEdit.elemdata=stud.elemdata
      tblEdit.guid=tblEdit.elemdata.ptr
      tblEdit.mat="48x98"
          
      tblEdit.elemdata.rotangle=-90
      if nCorner==2 then
        tblEdit.elemdata.rotangle=90
      end

      tblEdit.elemdata.x1=tblEdit.elemdata.x1-0.048*dir*0.5
      tblEdit.elemdata.z1=tblEdit.elemdata.z1+0.048*0.5
      tblEdit.elemdata.x2=tblEdit.elemdata.x2-0.048*dir*0.5
      tblEdit.elemdata.z2=tblEdit.elemdata.z1
      af_request("editplank", tblEdit)
      
      x1=stud.elemdata.x1
      x2=stud.elemdata.x1+dir*0.098
      
      nStud=nStud+1
    end

    if x1 then
      af_request("elem_marknoplanks", x1, -10, x2, 10)
    end

  elseif layerType=="extstud" and (nType==8 or nType==9 or nType==108 or nType==109) then
    local finishThick
    
    finishThick=0.023
    nStud=1
    while math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      -- Corner piece, 
      plank={}
      plank.guidsettings=stud.elemdata.ptr
      plank.group="vertical_force"
      plank.id="block"
      plank.thickness=0.022
      plank.height=0.123
      
      plank.x1=stud.elemdata.x1-stud.plankinfo.height-stud.plankinfo.width-finishThick+plank.height
      plank.rotangle=90
      if dir<0 then
        plank.x1=stud.elemdata.x1+stud.plankinfo.height+stud.plankinfo.width+finishThick-plank.height
        plank.rotangle=-90
      end
      plank.y1=stud.elemdata.y1
      plank.x2=plank.x1
      plank.y2=stud.elemdata.y2
      plank.zoff=-finishThick-plank.thickness*0.5   -- change zoff sign if element built from in to out, 0.023 is thickness of finishing layer
      plank.extendtoelem=2
      plank.force=true
      
      nCreate=nCreate+1
      gtblCreate[nCreate]=plank

      nStud=nStud+1
    end

  elseif layerType=="intstud" or (layerType=="extstud" and nType==100) then
    -- intstud, rotate corner stud and move it
    local tblEdit, height, x1, x2, w2, orgMatId

    nStud=1
    while tblStuds[nStud] and math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      ac_objectopen(stud.elemdata.ptr)
      orgMatId=ac_objectget("iMatId")
      ac_objectclose()

      if math.abs(stud.elemdata.rotangle)<1 then
        w2=stud.plankinfo.width*0.5
        tblEdit=nil
        if layerType=="extstud" and nType==100 then
          -- do not rotate, change from 19x48 to 19x73
          if math.abs(stud.plankinfo.width-0.048)<0.001 then
            local newWidth
            
            newWidth=0.073
            stud.elemdata.x1=stud.elemdata.x1+(newWidth - stud.plankinfo.width)*0.5*dir
            stud.elemdata.x2=stud.elemdata.x1

            tblEdit={}
            tblEdit.guid=stud.elemdata.ptr
            tblEdit.elemdata=stud.elemdata
            tblEdit.mat="block"
            tblEdit.thickness=newWidth
            tblEdit.height=stud.plankinfo.height
            
            -- No planks area
            if nCorner==1 then
              x1=tblEdit.elemdata.x1
              x2=tblEdit.elemdata.x1+tblEdit.thickness
            elseif nCorner==2 then
              x1=tblEdit.elemdata.x1-tblEdit.thickness
              x2=tblEdit.elemdata.x1
            end

          end

        else
          -- intstud
          -- Zero rotate, set size and rotate
          stud.elemdata.rotangle=-90
          if nCorner==2 then
            stud.elemdata.rotangle=90
          end

          stud.elemdata.x1=stud.elemdata.x1-w2*dir
          stud.elemdata.z1=stud.elemdata.z1+stud.plankinfo.height*0.5
          stud.elemdata.x2=stud.elemdata.x2-w2*dir
          stud.elemdata.z2=stud.elemdata.z1

          tblEdit={}
          tblEdit.guid=stud.elemdata.ptr
          tblEdit.elemdata=stud.elemdata
          tblEdit.mat="block"
          tblEdit.thickness=stud.plankinfo.height
          tblEdit.height=stud.plankinfo.height*2
        
          if nType==100 then
            -- Hedalm Long, different material
            tblEdit.height=stud.plankinfo.width*2
          end
          
          if nType==110 then
            -- Plusshus, corner is bigger
            tblEdit.mat="45x195"
            tblEdit.thickness=stud.plankinfo.height
            tblEdit.height=0.195
          end
          
          -- No planks area
          if nCorner==1 then
            x1=tblEdit.elemdata.x1
            x2=tblEdit.elemdata.x1+tblEdit.height
          elseif nCorner==2 then
            x1=tblEdit.elemdata.x1-tblEdit.height
            x2=tblEdit.elemdata.x1
          end
        end

        if tblEdit then
          af_request("editplank", tblEdit)
          
          if nType==101 then
            -- Anebyhus corner, duplicate another rotated
            plank={}
            plank.guidsettings=tblEdit.guid           -- is a ptr
            plank.group="vertical_force"
            plank.id=tblEdit.mat
            plank.thickness=tblEdit.thickness
            plank.height=tblEdit.height
            plank.x1=stud.elemdata.x1+dir*(0.195)     -- HARD CODED core STUD
            plank.y1=stud.elemdata.y1
            plank.x2=plank.x1
            plank.y2=stud.elemdata.y2
            plank.zoff=stud.elemdata.z1
            plank.extendtoelem=1
            plank.rotangle=stud.elemdata.rotangle
            plank.force=true
            nCreate=nCreate+1
            gtblCreate[nCreate]=plank
            if nCorner==1 then
              x2=plank.x1+plank.height
            else
              x1=plank.x1-plank.height
            end
          elseif nType==110 then
            -- Plusshus corner, duplicate two 45x45 next to 45x195 at corner
            local plank2

            plank={}
            plank.guidsettings=stud.elemdata.ptr
            plank.id=orgMatId
            plank.group="vertical_force"
            plank.x1=stud.elemdata.x1+dir*tblEdit.height     -- HARD CODED core STUD
            plank.y1=stud.elemdata.y1
            plank.x2=plank.x1
            plank.y2=stud.elemdata.y2
            plank.zoff=stud.elemdata.z1
            plank.extendtoelem=1
            plank.rotangle=stud.elemdata.rotangle
            plank.force=true
            nCreate=nCreate+1
            gtblCreate[nCreate]=plank
            
            -- Another one
            plank2={}
            plank2.guidsettings=stud.elemdata.ptr
            plank2.id=orgMatId
            plank2.thickness=stud.plankinfo.width
            plank2.height=stud.plankinfo.height
            plank2.group="vertical_force"
            plank2.x1=plank.x1+dir*stud.plankinfo.height
            plank2.y1=stud.elemdata.y1
            plank2.x2=plank2.x1
            plank2.y2=stud.elemdata.y2
            plank2.zoff=stud.elemdata.z1
            plank2.extendtoelem=1
            plank2.rotangle=stud.elemdata.rotangle
            plank2.force=true
            nCreate=nCreate+1
            gtblCreate[nCreate]=plank2

            if nCorner==1 then
              x2=plank2.x1+stud.plankinfo.width
            else
              x1=plank2.x1-stud.plankinfo.width
            end
          end

--ac_environment("tolog", string.format("x1=%f x2=%f\n", x1, x2))
          af_request("elem_marknoplanks", x1, tblEdit.elemdata.y1-10, x2, tblEdit.elemdata.y2+10)

          -- Remove any stud in x1, x2 area (double studding)
          local scan, vscan
          for scan,vscan in ipairs(tblStuds) do
            if vscan.elemdata.x1-vscan.plankinfo.width*0.5+0.010>x1 and vscan.elemdata.x1+vscan.plankinfo.width*0.5-0.010<x2 and vscan.elemdata.ptr~=stud.elemdata.ptr then
--ac_environment("tolog", string.format("DEL vscan.elemdata.x1=%f\n", vscan.elemdata.x1))
              ac_objectopen(vscan.elemdata.ptr)
              af_request("delplank")
              ac_objectclose()
            end
          end
        end
      end
      nStud=nStud+1
    end
  end

  if nCreate>0 then
    af_request("elem_createplanks")
  end
  
end



-- Adjusts planks for given corner 1/2
-- nType  See top
-- Called with element planks opened
function DoShortPlanks(layerType, nCorner, nType, guidElem)
  local tblStuds, plank, i, s, nStuds, dir, nCreate

  gtblCreate={}
  nCreate=0
  
  if nCorner>2 then
    return
  end

  ac_objectopen(guidElem)
  s=ac_objectget("iElemTypeId")
  ac_objectclose()
  if string.match(s, "%a*HOR$") then
    return
  end

  af_request("elem_getpoly")
  tblStuds,nStuds=FindStuds()
  if #tblStuds<1 then
    return
  end

  -- Sort so that corner piece is the first one in the table
  if nCorner==1 then
    -- Left side
    dir=1
	  table.sort(tblStuds, function (n1, n2)
      return n1.elemdata.x1 < n2.elemdata.x1
	  end)
  else
    -- Right side
    dir=-1
	  table.sort(tblStuds, function (n1, n2)
      return n1.elemdata.x1 > n2.elemdata.x1
	  end)
  end

  local nStud, stud, x1, x2, w2

  if layerType=="extstud" and (nType==8 or nType==9 or nType==108 or nType==109) then
    local finishThick
    
    finishThick=0.023
    nStud=1
    while math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      -- Corner piece, 
      plank={}
      plank.guidsettings=stud.elemdata.ptr
      plank.group="vertical_force"
      plank.id="block"
      plank.thickness=0.022
      plank.height=0.148
      
      plank.x1=stud.elemdata.x1-stud.plankinfo.height-stud.plankinfo.width-finishThick-plank.thickness+plank.height
      plank.rotangle=90
      if dir<0 then
        plank.x1=stud.elemdata.x1+stud.plankinfo.height+stud.plankinfo.width+finishThick+plank.thickness-plank.height
        plank.rotangle=-90
      end
      plank.y1=stud.elemdata.y1
      plank.x2=plank.x1
      plank.y2=stud.elemdata.y2
      plank.zoff=-finishThick-plank.thickness*0.5   -- change zoff sign if element built from in to out, 0.023 is thickness of finishing layer
      plank.extendtoelem=2
      plank.force=true
      
      nCreate=nCreate+1
      gtblCreate[nCreate]=plank

      nStud=nStud+1
    end
  elseif layerType=="intstud" and nType==121 then
    nStud=1
    while tblStuds[nStud] and math.abs(tblStuds[1].elemdata.x1 - tblStuds[nStud].elemdata.x1)<0.001 do
      stud=tblStuds[nStud]

      -- Corner piece rotated and different material
      tblEdit={}
      tblEdit.elemdata=stud.elemdata
      tblEdit.guid=tblEdit.elemdata.ptr
      tblEdit.mat="48x148"
          
      tblEdit.elemdata.rotangle=-90
      if nCorner==2 then
        tblEdit.elemdata.rotangle=90
      end

      tblEdit.elemdata.x1=tblEdit.elemdata.x1-0.048*dir*0.5
      tblEdit.elemdata.z1=tblEdit.elemdata.z1+0.048*0.5
      tblEdit.elemdata.x2=tblEdit.elemdata.x2-0.048*dir*0.5
      tblEdit.elemdata.z2=tblEdit.elemdata.z1
      af_request("editplank", tblEdit)
      
      x1=stud.elemdata.x1
      x2=stud.elemdata.x1+dir*0.148
      
      nStud=nStud+1
    end

    if x1 then
      af_request("elem_marknoplanks", x1, -10, x2, 10)
    end
 end

  if nCreate>0 then
    af_request("elem_createplanks")
  end
  
end


-- Save connections for this script to be able to make shape for related element(s)
function AddConn(guidthis, cornerthis, relData)
  if not IsAdjustOther() then
    return
  end

  local item

--ac_environment("tolog", string.format("guidthis=%s, cornerthis=%s, guidother=%s, cornerother=%s\n", tostring(guidthis), tostring(cornerthis), tostring(guidother), tostring(cornerother)))
  item={}
  item.guidthis   =guidthis
  item.cornerthis =cornerthis
  item.guidother  =relData.this.guidother
  item.cornerother=relData.other.reltype
  item.reldata    =relData                -- Also full relData
  gtblConn[#gtblConn+1]=item
end


-- Handles every layer not having tblParent[nLayer].handled set to true
function DoDefaultLong(tblParent, nCorner, coreElem, nType)
  if not gAdjustElems then
    return
  end

  local i, v, off

  if nType==nil then
    nType=1
  end
  
  if nType==110 then
    return      -- NOP for Plusshus
  end

  -- Keep core in place, move all others
  for i,v in ipairs(tblParent.tblelems) do
    if not v.handled then
      af_request("elem_openlayer", v.guid)
      off=nil
      if nType==100 or nType==102 then
        -- Hedalm
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if v.type=="panel_ext" then
            off=off+0.049
          elseif v.type=="boarding_ext" then
            off=off+v.thickness
          end
        end
      elseif nType==120 then
        -- YIT ext 1
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if v.type=="finish_ext" then
            off=off+0.034
          elseif v.type=="boarding_int" then
            off=off-0.009-0.198
          end
        end
      elseif nType==121 then
        -- YIT ext int 1
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if v.type=="finish_ext" or string.match(v.type, "^extstud%a*") then
            off=off-0.305
          elseif v.type=="boarding_int" or string.match(v.type, "^intstud%a*") then
            off=off+0.048
          end
        end
      else
        if nType==101 then
          -- This type is made from int to ext
          off=(v.zoff+v.thickness)-(coreElem.zoff+coreElem.thickness)
          if v.type=="intstud" then
            -- Extend this as far as core
            off=off+coreElem.thickness
          end
        else
          -- Default ext to int
          off=coreElem.zoff-v.zoff
        end
        if nCorner==1 then
          off=off-v.x1off
        elseif nCorner==2 then
          off=off-v.x2off
        elseif nCorner==3 then
          off=off-v.y1off
        elseif nCorner==4 then
          off=off-v.y2off
        else
          error(string.format("bad corner %s", tostring(nCorner)))
        end
      end
      if gAdjustElems and off then
        af_request("elem_moveside", nCorner, off)
      end
      af_request("elem_closelayer")
    end
  end
end


-- Looks for core layer relation and returns information for long core layer
-- layerType  nil="core", others=override
-- Returns (anything can be nil): relFound, x1offCore, x2offCore, coreLayer
function FindCoreRel(tblParent, nCorner, layerType)
  if not IsFindOther() then
    return
  end

  local i, v, tblRel, coreLayer
  local iRel, vRel, relFound
  local x1offCore, x2offCore

  if layerType==nil then
    layerType="core"
  end

  for i,v in ipairs(tblParent.tblelems) do
    if v.type==layerType then
      coreLayer=v
      tblRel=af_request("elem_getrelations", v.guid)
      if tblRel then
        if nCorner==1 then
          for iRel,vRel in ipairs(tblRel) do
            if vRel.this.reltype==1 then
              relFound=vRel
              x1offCore=-vRel.this.x1
              break
            end
          end
        elseif nCorner==2 then
          for iRel,vRel in ipairs(tblRel) do
            if vRel.this.reltype==2 then
              relFound=vRel
              x2offCore=vRel.this.x2-v.xsize
              break
            end
          end
        end
      end
    end
  end
  
  return relFound, x1offCore, x2offCore, coreLayer
end


function DoWithRelLong(tblParent, nCorner, coreElem, nType)
  local i, v, off, tblRel
  local iRel, vRel, relFound, reFoundCore
  local x1offCore, x2offCore      -- How much the core must be adjusted

  reFoundCore, x1offCore, x2offCore=FindCoreRel(tblParent, nCorner)
--ac_environment("tolog", string.format("LONG %s x1offCore=%s, x2offCore=%s", tostring(nType), tostring(x1offCore), tostring(x2offCore)))
  
  if nType==100 or nType==102 then
    -- Hedalm long, find core relation
    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore
        if v.type=="panel_ext" then
          off=off+0.049
        elseif v.type=="boarding_ext" then
          off=off+v.thickness
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore
        if v.type=="panel_ext" then
          off=off+0.049
        elseif v.type=="boarding_ext" then
          off=off+v.thickness
        end
      end
      if off then
        AddConn(v.guid, nCorner, reFoundCore)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  end

  if nType==120 then
    -- YIT Long 1
    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore+0.009        -- Add crossing wall's windshield board thickness
        if v.type=="finish_ext" then
          off=off+0.034
        elseif v.type=="boarding_int" then
          off=off-0.009-0.198
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore+0.009
        if v.type=="finish_ext" then
          off=off+0.034
        elseif v.type=="boarding_int" then
          off=off-0.009-0.198
        end
      end
      if off then
        AddConn(v.guid, nCorner, reFoundCore)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  end
  
  if nType==121 then
    -- YIT Long inner 1
    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore
        if v.type=="finish_ext" or string.match(v.type, "^extstud%a*") then
          off=off-0.290
        elseif v.type=="boarding_int" or v.type=="intstud" then
          off=off+0.048
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore
        if v.type=="finish_ext" or string.match(v.type, "^extstud%a*") then
          off=off-0.290
        elseif v.type=="boarding_int" or v.type=="intstud" then
          off=off+0.048
        end
      end
      if off then
        AddConn(v.guid, nCorner, reFoundCore)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  end
  
  -- Check if built from out to in
  local firstExt, s
  
  firstExt=false
  s=tblParent.tblelems[1].type
  if string.match(s, "_ext.*") or string.match(s, "^ext.*") then
    firstExt=true
  end
--ac_environment("tolog", string.format("tblParent.tblelems[1].type=%s firstExt=%s", tblParent.tblelems[1].type, tostring(firstExt)))

  -- Match to related element
  for i,v in ipairs(tblParent.tblelems) do
    tblRel=nil
    if IsFindOther() then
      tblRel=af_request("elem_getrelations", v.guid)
    end
    
    if tblRel and (gGuidElemToPlank==nil or gGuidElemToPlank==v.guid) then
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 then
        for iRel,vRel in ipairs(tblRel) do
          if vRel.this.reltype==1 then
            relFound=vRel
            off=-vRel.this.x1
            break
          end
        end
        
      elseif nCorner==2 then
        for iRel,vRel in ipairs(tblRel) do
          if vRel.this.reltype==2 then
            relFound=vRel
            off=vRel.this.x2-v.xsize
--ac_environment("tolog", string.format("vRel.this.x2=%f vRel.this.angledeg=%f vRel.other.angledeg=%f v.xsize=%f", vRel.this.x2, vRel.this.angledeg, vRel.other.angledeg, v.xsize))
            break
          end
        end
      else
        error(string.format("bad corner %s", tostring(nCorner)))
      end

      s=v.type
      if relFound and (nType==8 or nType==9 or nType==108 or nType==109 or nType==110) and (string.match(s, "_ext.*") or string.match(s, "^ext.*")) and (s~="boarding_ext" or nType==110) then
        -- Make extstud, finish_ext shorter (adjust to boarding_ext) if found
        -- For type 110/Plusshus: Adjust to main framing
        local relBoard, x1offBoard, x2offBoard, boardLayer

        if nType==110 then
          relBoard, x1offBoard, x2offBoard, boardLayer=FindCoreRel(tblParent, nCorner, "core")
        else
          relBoard, x1offBoard, x2offBoard, boardLayer=FindCoreRel(tblParent, nCorner, "boarding_ext")
        end
        if relBoard then
          if (relFound.this.angledeg>0 and firstExt==true) or (relFound.this.angledeg<0 and firstExt==false) then
            -- Outer corner
            if nCorner==1 then
              off=boardLayer.x1off-v.x1off
              off=off+x1offBoard
            elseif nCorner==2 then
              off=boardLayer.x2off-v.x2off
              off=off+x2offBoard
            end
          else
            -- Inner corner, reduce thickness of all layers from this to the last exterior layer
            local i2
            
            if firstExt then
              i2=i
              while i2>0 do
                off=off-tblParent.tblelems[i2].thickness
                i2=i2-1
              end
            else
              i2=i
              while tblParent.tblelems[i2]~=nil do
                off=off-tblParent.tblelems[i2].thickness
                i2=i2+1
              end
            end
          end
        end
      end

      if off then
        if (nType==101 or nType==110) and v.type=="intstud" then
          -- Extend this as far as core
          off=off+coreElem.thickness
        end

        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end
  end
end


-- Handles every layer not having tblParent[nLayer].handled set to true
function DoDefaultShort(tblParent, nCorner, coreElem, nType)
  local i, v, off

  if nType==110 then
    return      -- NOP for Plusshus
  end

  -- Keep core in place, move all others
  for i,v in ipairs(tblParent.tblelems) do
    if not v.handled then
      af_request("elem_openlayer", v.guid)
      off=nil
      if nType==100 then
        -- Hedalm
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if v.type=="panel_ext" then
            off=off+coreElem.thickness+0.061+0.028
          elseif v.type=="extstud" or v.type=="boarding_ext" then
            off=off+coreElem.thickness+0.061
          end
        end
      elseif nType==120 then
        -- YIT Short ext 1
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if string.match(v.type, "^extstud%a*") then
            off=off+0.274
          elseif string.match(v.type, "^finish_ext%a*") then
            off=off+0.330
          end
        end
      elseif nType==121 then
        -- YIT Short ext inner 1
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          -- Should stop inner studding&boarding to next stud
        end
      elseif nType==102 then
        -- Omatalo
        if nCorner==1 then
          off=-v.x1off
        elseif nCorner==2 then
          off=-v.x2off
        end

        if off then
          if v.type=="boarding_ext" then
            off=off+coreElem.thickness+0.013
          end
        end
      else
        if nType==101 then
          -- This type is made from int to ext
          off=(v.zoff)-(coreElem.zoff)
          
          if nType==101 and v.type=="core" and tblParent.tblelems[i-1]~=nil and tblParent.tblelems[i-1].type=="intstud" then
            -- Core gives space for long one's intstud
            off=off-tblParent.tblelems[i-1].thickness
          end

        else
          -- Default ext to int
          off=(coreElem.zoff+coreElem.thickness)-(v.zoff+v.thickness)
        end
        if nCorner==1 then
          off=off-v.x1off
        elseif nCorner==2 then
          off=off-v.x2off
        elseif nCorner==3 then
          off=off-v.y1off
        elseif nCorner==4 then
          off=off-v.y2off
        else
          error(string.format("bad corner %s", tostring(nCorner)))
        end
      end
      if gAdjustElems and off then
        af_request("elem_moveside", nCorner, off)
      end
      af_request("elem_closelayer")
    end
  end
end


function DoWithRelShort(tblParent, nCorner, coreElem, nType)
  local i, v, off, tblRel
  local iRel, vRel, relFound


  if nType==100 then
    local x1offCore, x2offCore, coreLayer      -- How much the core must be adjusted
    
    -- Hedalm short, find core relation
    relFound, x1offCore, x2offCore, coreLayer=FindCoreRel(tblParent, nCorner)

    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore-coreLayer.thickness-0.061
        if v.type=="panel_ext" then
          off=off+coreLayer.thickness+0.061+0.028
        elseif v.type=="extstud" or v.type=="boarding_ext" then
          off=off+coreLayer.thickness+0.061
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore-coreLayer.thickness-0.061
        if v.type=="panel_ext" then
          off=off+coreLayer.thickness+0.061+0.028
        elseif v.type=="extstud" or v.type=="boarding_ext" then
          off=off+coreLayer.thickness+0.061
        end
      end
      if off then
        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  elseif nType==120 then
    local x1offCore, x2offCore, coreLayer      -- How much the core must be adjusted
    
    -- YIT short, find core relation
    relFound, x1offCore, x2offCore, coreLayer=FindCoreRel(tblParent, nCorner)

    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore-coreLayer.thickness-0.048-0.028
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore-coreLayer.thickness-0.048-0.028
      end
      if off then
        if v.type=="boarding_int" then
          off=off
        elseif string.match(v.type, "^extstud%a*") then
          off=off+coreLayer.thickness+0.048+0.028
        elseif string.match(v.type, "^finish_ext%a*") then
          off=off+coreLayer.thickness+0.048+0.028+0.009+0.045+0.002
        end
        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
    
  elseif nType==121 then
    local x1offCore, x2offCore, coreLayer      -- How much the core must be adjusted
    
    -- YIT short inner, find core relation
    relFound, x1offCore, x2offCore, coreLayer=FindCoreRel(tblParent, nCorner)

    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore-coreLayer.thickness-0.024
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore-coreLayer.thickness-0.024
      end
      if off then
        if v.type=="boarding_int" then
          off=off+0.283
        elseif string.match(v.type, "^intstud%a*") then
          off=off+0.100
        end
        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  elseif nType==102 then
    -- Omatalo
    local x1offCore, x2offCore, coreLayer      -- How much the core must be adjusted
    
    -- Hedalm short, find core relation
    relFound, x1offCore, x2offCore, coreLayer=FindCoreRel(tblParent, nCorner)
    
    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore-coreLayer.thickness-0.013
        if v.type=="core" then
          off=off-0.010
        elseif v.type=="boarding_ext" then
          off=off+coreLayer.thickness+0.013
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x1off+x2offCore-coreLayer.thickness-0.013
        if v.type=="core" then
          off=off-0.010
        elseif v.type=="boarding_ext" then
          off=off+coreLayer.thickness+0.013
        end
      end
      if off then
        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  elseif nType==110 then
    -- Plusshus (short)
    local x1offCore, x2offCore, coreLayer      -- How much the core must be adjusted
    
    relFound, x1offCore, x2offCore, coreLayer=FindCoreRel(tblParent, nCorner)
    for i,v in ipairs(tblParent.tblelems) do
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 and x1offCore then
        off=-v.x1off+x1offCore-coreLayer.thickness-0.053      -- 0.045+0.008
        if string.match(v.type, "_ext.*") or string.match(v.type, "^ext.*") then
          off=off+coreLayer.thickness+0.053
        end
      elseif nCorner==2 and x2offCore then
        off=-v.x2off+x2offCore-coreLayer.thickness-0.053
        if string.match(v.type, "_ext.*") or string.match(v.type, "^ext.*") then
          off=off+coreLayer.thickness+0.053
        end
      end
      if off then
        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end

    return
  end

  -- Check if built from out to in
  local firstExt, s
  
  firstExt=false
  s=tblParent.tblelems[1].type
  if string.match(s, "_ext.*") or string.match(s, "^ext.*") then
    firstExt=true
  end

  for i,v in ipairs(tblParent.tblelems) do
    tblRel=nil
    if IsFindOther() then
      tblRel=af_request("elem_getrelations", v.guid)
    end
    if tblRel then
      af_request("elem_openlayer", v.guid)
      off=nil
      if nCorner==1 then
        for iRel,vRel in ipairs(tblRel) do
          if vRel.this.reltype==1 then
            relFound=vRel
            off=-(vRel.this.x2-vRel.this.x2off)
            break
          end
        end
      elseif nCorner==2 then
        for iRel,vRel in ipairs(tblRel) do
          if vRel.this.reltype==2 then
            relFound=vRel
            off=(vRel.this.x1+vRel.this.x1off)-v.xsize
            break
          end
        end
      else
        error(string.format("bad corner %s", tostring(nCorner)))
      end

      s=v.type
      if relFound and (nType==8 or nType==9 or nType==108 or nType==109) and (string.match(s, "_ext.*") or string.match(s, "^ext.*")) and s~="boarding_ext" then
        -- Make extstud, finish_ext shorter if found
        local relBoard, x1offBoard, x2offBoard, boardLayer

        relBoard, x1offBoard, x2offBoard, boardLayer=FindCoreRel(tblParent, nCorner, "boarding_ext")
        if relBoard then
          local i2

          if (relFound.this.angledeg>0 and firstExt==true) or (relFound.this.angledeg<0 and firstExt==false) then
            -- Outer corner
            i2=i
            while true do
              if firstExt then
                i2=i2+1
              else
                i2=i2-1
              end
              if tblParent.tblelems[i2]==nil then
                break
              end
              s=tblParent.tblelems[i2].type
              if s=="boarding_ext" or not (string.match(s, "_ext.*") or string.match(s, "^ext.*")) then
                break
              end
              off=off-tblParent.tblelems[i2].thickness
            end
          else
            -- Inner corner, reduce thickness of all layers from this to the last exterior layer
            i2=i
            while true do
              if firstExt then
                i2=i2-1
              else
                i2=i2+1
              end
              if i2<1 or i2>#tblParent.tblelems then
                break
              end
              off=off-tblParent.tblelems[i2].thickness
            end
          end
        end
      end

      if off then
        if nType==101 and v.type=="core" and tblParent.tblelems[i-1]~=nil and tblParent.tblelems[i-1].type=="intstud" then
          -- Core gives space for long one's intstud
          off=off-tblParent.tblelems[i-1].thickness
        end

        AddConn(v.guid, nCorner, relFound)
        if gAdjustElems then
          af_request("elem_moveside", nCorner, off)
        end
        v.handled=true
      end
      af_request("elem_closelayer")
    end
  end
end


-- nType as for creating planks: nil=no specs
function SetLongElem( sSettings, guidElem, nCorner, nType )
  local tblParent
  local coreElem, nSaveElems

  gtblConn={}
  tblParent=af_request("elem_openparent", guidElem)

  -- Find core layer
  coreElem=nil
  for i,v in ipairs(tblParent.tblelems) do
    if v.type=="core" then
      coreElem=v
      break
    end
  end

  if coreElem==nil then
    af_request("elem_closeparent", 0)
    return
  end
  
  gGuidElemToPlank=guidElem
  nSaveElems=0
  if gAdjustElems then
    nSaveElems=1
    gGuidElemToPlank=nil
  end

  DoWithRelLong(tblParent, nCorner, coreElem, nType)
  DoDefaultLong(tblParent, nCorner, coreElem, nType)
  af_request("elem_closeparent", nSaveElems)
  
  if #gtblConn>0 and gAdjustElems then
    -- To other part
    local v
    
    v=gtblConn[1]
    
    if v.cornerother==1 or v.cornerother==2 then
      v.idother="short"     -- To be saved into other element's settings
      if nType==100 then
        v.idother="short_hedalm"
      elseif nType==101 then
        v.idother="short_anebyhus"
      elseif nType==102 then
        v.idother="short_omatalo"
      elseif nType==8 or nType==9 or nType==108 or nType==109 then
        v.idother="short3"
      elseif nType==110 then
        v.idother="plusshus_short_ext1"
      elseif nType==120 then
        v.idother="yit_short1"
      elseif nType==121 then
        v.idother="yit_shortint1"
      end
      tblParent=af_request("elem_openparent", v.guidother)
      DoWithRelShort(tblParent, v.cornerother, nil, nType)
      af_request("elem_closeparent", 1)
    end
  end
end


function SetShortElem( sSettings, guidElem, nCorner, nType )
  local tblParent
  local coreElem

  gtblConn={}
  tblParent=af_request("elem_openparent", guidElem)

  -- Find core layer
  coreElem=nil
  for i,v in ipairs(tblParent.tblelems) do
    if v.type=="core" then
      coreElem=v
      break
    end
  end

  if coreElem==nil then
    af_request("elem_closeparent", 0)
    return
  end

  gGuidElemToPlank=guidElem
  nSaveElems=0
  if gAdjustElems then
    nSaveElems=1
    gGuidElemToPlank=nil
  end

  DoWithRelShort(tblParent, nCorner, coreElem, nType)
  DoDefaultShort(tblParent, nCorner, coreElem, nType)
  af_request("elem_closeparent", nSaveElems)
  
  if #gtblConn>0 and gAdjustElems then
    -- To other part
    local v
    
    v=gtblConn[1]
    
    if v.cornerother==1 or v.cornerother==2 then
      v.idother="long"     -- To be saved into other element's settings
      if nType==100 then
        v.idother="long_hedalm"
      elseif nType==101 then
        v.idother="long_anebyhus"
      elseif nType==102 then
        v.idother="long_omatalo"
      elseif nType==8 or nType==9 or nType==108 or nType==109 then
        if v.reldata.other.angledeg>0 then
          v.idother="long_l_left3"
        else
          v.idother="long_l_right3"
        end
      elseif nType==110 then
        v.idother="plusshus_long_ext1"
      elseif nType==120 then
        v.idother="yit_long1"
      elseif nType==121 then
        v.idother="yit_longint1"
      end
      tblParent=af_request("elem_openparent", v.guidother)
      DoWithRelLong(tblParent, v.cornerother, coreElem, nType)
      af_request("elem_closeparent", 1)
    end
  end
end



-- Example of offsetting layers with constant values
function DoDefaultTopBottom(tblParent, nCorner, coreElem, nType)
  local i, v, off

  -- Keep core in place, move all others
  for i,v in ipairs(tblParent.tblelems) do
    -- Following condition is always true for bottom & top since no element relation are used
    if not v.handled then
      af_request("elem_openlayer", v.guid)
      off=nil
      -- Keep core unmoved
      if v~=coreElem then
        if nCorner==3 then
          -- Bottom
          off=-v.y1off
        else
          -- Top
          off=-v.y2off
        end
        
        if v.type=="intstud" or v.type=="boarding_int" then
          if nCorner==3 then
            off=off-0.050
          else
            off=2.5 - v.ysize   -- Height=2500
          end
        elseif v.type=="boarding_ext" then
          if nCorner==3 then
            -- Adjust bottom to core
          else
            off=off+0.1         -- Top 100 mm over core
          end
        elseif v.type=="extstud" or v.type=="finish_ext" then
          if nCorner==3 then
            off=off-0.15         -- Bottom 150 mm up from core bottom
          else
            off=off+0.15         -- Top 150 mm over core
          end
        else
          ac_environment("tolog", string.format("Unknown element layer type=%s", v.type))
          off=nil               -- No change
        end
      end

      if gAdjustElems and off then
        af_request("elem_moveside", nCorner, off)
      end
      af_request("elem_closelayer")
    end
  end
end


function SetTopBottomEx( sSettings, guidElem, nCorner, nType )
  local tblParent
  local coreElem

  gtblConn={}
  tblParent=af_request("elem_openparent", guidElem)

  -- Find core layer
  coreElem=nil
  for i,v in ipairs(tblParent.tblelems) do
    if v.type=="core" then
      coreElem=v
      break
    end
  end

  if coreElem==nil then
    af_request("elem_closeparent", 0)
    return
  end

  gGuidElemToPlank=guidElem
  nSaveElems=0
  if gAdjustElems then
    nSaveElems=1
    gGuidElemToPlank=nil
  end

  DoDefaultTopBottom(tblParent, nCorner, coreElem, nType)
  af_request("elem_closeparent", nSaveElems)
end


function SetTopBottom( guidElem, nCorner, offBoardInt, offBoardExt, offStuddingExt1, offStuddingExt2, offFinishExt )
  local tblParent
  local coreElem
  local i, v, off

  tblParent=af_request("elem_openparent", guidElem)

  -- Find core layer
  coreElem=nil
  for i,v in ipairs(tblParent.tblelems) do
    if v.type=="core" then
      coreElem=v
      break
    end
  end

  if coreElem==nil then
    af_request("elem_closeparent", 0)
    return
  end

  gGuidElemToPlank=guidElem
  nSaveElems=0
  if gAdjustElems then
    nSaveElems=1
    gGuidElemToPlank=nil
  end

  -- Keep core in place, move all others
  for i,v in ipairs(tblParent.tblelems) do
    -- Following condition is always true for bottom & top since no element relation are used
    af_request("elem_openlayer", v.guid)
    off=nil
    -- Keep core unmoved
    if v~=coreElem then
      if nCorner==3 then
        -- Bottom
        off=-v.y1off
      else
        -- Top
        off=-v.y2off
      end

      if string.match(v.type, "^intstud%a*") or string.match(v.type, "^boarding_int%a*") then
        off=off+offBoardInt
      elseif string.match(v.type, "^boarding_ext%a*") then
        off=off+offBoardExt
      elseif string.match(v.type, "^extstud%a*") then
        off=off+offStuddingExt1
      elseif string.match(v.type, "^extstud2%a*") then
        off=off+offStuddingExt2
      elseif string.match(v.type, "^finish_ext%a*") then
        off=off+offFinishExt
      else
        ac_environment( "tolog", string.format("WARNING: SET TOP&BOTTOM, UNKONWN LAYER: %s", v.type))
        off=nil               -- No change
      end
    end

    if gAdjustElems and off then
      af_request("elem_moveside", nCorner, off)
    end
    af_request("elem_closelayer")
  end

  af_request("elem_closeparent", nSaveElems)
end



function SetStraight( guidElem, nCorner )
  local tblParent
  local coreElem
  local i, v, off

  tblParent=af_request("elem_openparent", guidElem)

  -- Find core layer
  coreElem=nil
  for i,v in ipairs(tblParent.tblelems) do
    if v.type=="core" then
      coreElem=v
      break
    end
  end

  if coreElem==nil then
    af_request("elem_closeparent", 0)
    return
  end

  gGuidElemToPlank=guidElem
  nSaveElems=0
  if gAdjustElems then
    nSaveElems=1
    gGuidElemToPlank=nil
  end


  -- Keep core in place, move all others
  for i,v in ipairs(tblParent.tblelems) do
    -- Following condition is always true for bottom & top since no element relation are used
    af_request("elem_openlayer", v.guid)
    off=nil
    -- Keep core unmoved
    if v~=coreElem then
      if nCorner==1 then
        off=-v.x1off
      elseif nCorner==2 then
        off=-v.x2off
      elseif nCorner==3 then
        off=-v.y1off
      elseif nCorner==4 then
        off=-v.y2off
      end
    end

    if gAdjustElems and off and math.abs(off)>0.0001 then
      af_request("elem_moveside", nCorner, off)
    end
    af_request("elem_closelayer")
  end

  af_request("elem_closeparent", nSaveElems)
end
]]>
      </common_script>


      <corner id="long" name="Long" name_fin="Pitkä" name_nor="Lang" name_swe="Lång" name_ger="Lang" name_ita="Lungo" name_por="Grande" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 1, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long2" name="Long 2" name_fin="Pitkä 2" name_nor="Lang 2" name_swe="Lång 2" name_ger="Lang 2" name_ita="Lungo 2" name_por="Grande 2" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 6, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long3" name="Long 3" name_fin="Pitkä 3" name_nor="Lang 3" name_swe="Lång 3" name_ger="Lang 3" name_ita="Lungo 3" name_por="Grande 3" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 7, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long_l_left" name="Long L left" name_fin="Pitkä L vasen" name_nor="Lang L vänster" name_swe="Lång L vänster" name_ger="Lang L links" name_ita="Lungo L Sinistro" name_por="Grande L Esquerdo">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 2, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long_l_right" name="Long L right" name_fin="Pitkä L oikea" name_nor="Lang L höger" name_swe="Lång L höger" name_ger="Lang L rechts" name_ita="Lungo L Destro" name_por="Grande L Direito">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 3, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long_l_left2" name="Long L left layered" name_fin="Pitkä L vasen kerros" name_nor="Lang L vänster 2" name_swe="Lång L vänster 2" name_ger="Lang L links geschichtet" name_ita="Lungo L Sinistro multistrato" name_por="Grande L Esquerdo multicamada">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 4, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long_l_right2" name="Long L right layered" name_fin="Pitkä L oikea kerros" name_nor="Lang L höger 2" name_swe="Lång L höger 2" name_ger="Lang L rechts geschichtet" name_ita="Lungo L Destro multistrato" name_por="Grande L Direito multicamada">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 5, guidElem)
end
]]>
        </script>
      </corner>



      <corner id="long_l_left3" name="Long L left layered 3" name_fin="Pitkä L vasen kerros 3" name_nor="Lang L vänster 3" name_swe="Lång L vänster 3" name_ger="Lang L links geschichtet 3" name_ita="Lungo L sinistro multistrato 3" name_por="Grande L Esquerdo multicamada 3">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner, 8 )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 8, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="long_l_right3" name="Long L right layered 3" name_fin="Pitkä L oikea kerros 3" name_nor="Lang L höger 3" name_swe="Lång L höger 3" name_ger="Lang L rechts geschichtet 3" name_ita="Lungo L destro multistrato 3" name_por="Grande L Direito multicamada 3">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetLongElem( sSettings, guidElem, nCorner, 9 )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoLongPlanks(layerType, nCorner, 9, guidElem)
end
]]>
        </script>
      </corner>


      <corner id="short" name="Short" name_fin="Lyhyt" name_nor="Kort" name_swe="Kort" name_ger="Kurz" name_ita="Corto" name_por="Curto" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetShortElem( sSettings, guidElem, nCorner )
end
]]>
        </script>
      </corner>


      <corner id="short3" name="Short 3" name_fin="Lyhyt 3" name_nor="Kort 3" name_swe="Kort 3" name_ger="Kurz 3" name_ita="Corto 3" name_por="Curto 3">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetShortElem( sSettings, guidElem, nCorner, 8 )
end


function OnPlanksCreated( sSettings, guidElem, layerType, nCorner )
  DoShortPlanks(layerType, nCorner, 9, guidElem)
end

]]>
        </script>
      </corner>


      <corner id="straigt_all" name="Straight" name_fin="Tasattu" name_ita="Dritto" name_por="Recto" sides="1" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetStraight( guidElem, nCorner )
end
]]>
        </script>
      </corner>

      <corner id="topbottomexoff" name="Top and bottom example 1" name_fin="Ylä ja ala esimerkki 1" name_ger="Oberes u. unteres Beispiel 1" name_ita="Sup. e Inf. esempio 1" name_por="Topo e Base exemplo 1" sides="0" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetTopBottom( guidElem, nCorner, 0.050, 0.050, 0.100, 0.100, 0.150 )
end
]]>
        </script>
      </corner>

      <!-- Raise all layers from core -->
      <corner id="topbottomex1" name="Top and bottom example 2" name_fin="Ylä ja ala esimerkki 2" name_ger="Oberes u. unteres Beispiel 2" name_ita="Sup. e Inf. esempio 2" name_por="Topo e Base exemplo 2" sides="0" bottom="1" top="1">
        <script ref="elem/corners/common_script">
          <![CDATA[
function Set( sSettings, guidElem, nCorner )
  SetTopBottomEx( sSettings, guidElem, nCorner )
end
]]>
        </script>
      </corner>
    </corners>


    <panelings>
      <paneling thickness="0.050" height="0.135" rot="90" id="PANEL_VERT_OUTIN" name="Paneling vertical out to in" name_fin="Rimalaudoitus ulkoa sisälle" name_swe="Vertikala paneler ut till in" name_nor="Stående kledning utside til innside" name_ger="Paneelierung senkrecht von außen nach innen" name_ita="Doghe verticali Ext-Int" name_por="Ripas verticais Ext-Int">
        <panel thickness="0.025" height="0.125" y1="0.025" y2="0.050" x1="0.000" x2="0.125">
          <profile>
            <point xym="0.00000000 0.05000000 15"/>
            <point xym="0.00000000 0.02500000 15"/>
            <point xym="0.12500000 0.02500000 15"/>
            <point xym="0.12500000 0.05000000 15"/>
            <point xym="0.00000000 0.05000000 -1"/>
          </profile>
        </panel>
        <panel thickness="0.025" height="0.050" y1="0.000" y2="0.025" x1="0.105" x2="0.155">
          <profile>
            <point xym="0.10500000 0.02500000 15"/>
            <point xym="0.10500000 0.00000000 15"/>
            <point xym="0.15500000 0.00000000 15"/>
            <point xym="0.15500000 0.02500000 15"/>
            <point xym="0.10500000 0.02500000 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.023" height="0.135" rot="0" id="PANEL_HOR_OUTIN" name="Paneling horizontal out to in 23x145/135" name_fin="Vaakalaudoitus ulkoa sisälle 23x145/135" name_swe="Horizontella paneler ut till in 23x145/135" name_nor="Liggende kledning utside til innside 23x145/135" name_ger="Paneelierung wagerecht von außen nach innen 23x145/135" name_ita="Doghe orizzontali Ext-Int 23x145/135" name_por="Ripas horizontais Ext-Int 23x145/135"> 
        <panel id="PANEL 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
          <profile>
            <point xym="-0.01000000 0.01456783 15"/>
            <point xym="-0.01000000 0.00784452 15"/>
            <point xym="0.01413317 0.00784452 15"/>
            <point xym="0.01872867 0.00000000 15"/>
            <point xym="0.13054592 0.00000000 15"/>
            <point xym="0.13497980 0.00787226 15"/>
            <point xym="0.12169031 0.00787226 15"/>
            <point xym="0.12169031 0.01568008 15"/>
            <point xym="0.13500000 0.01568008 15"/>
            <point xym="0.13500000 0.02300000 15"/>
            <point xym="0.09396181 0.02300000 15"/>
            <point xym="0.09396181 0.01682631 15"/>
            <point xym="0.08186436 0.01682631 15"/>
            <point xym="0.08186436 0.02300000 15"/>
            <point xym="0.05409523 0.02300000 15"/>
            <point xym="0.05409523 0.01682631 15"/>
            <point xym="0.04188986 0.01682631 15"/>
            <point xym="0.04188986 0.02300000 15"/>
            <point xym="0.00200068 0.02300000 15"/>
            <point xym="0.00200068 0.01456783 15"/>
            <point xym="-0.01000000 0.01456783 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.050" height="0.135" rot="90" id="PANEL_VERT_INOUT" name="Paneling vertical in to out" name_fin="Rimalaudoitus sisältä ulos" name_swe="Vertikala paneler in till ut" name_nor="Stående kledning innside til utside" name_ger="Paneelierung senkrecht von innen nach außen" name_ita="Doghe verticali Int-Ext" name_por="Ripas verticais Int-Ext">
        <panel thickness="0.1250" height="0.0250" x1="0.0000" x2="0.1250" y1="0.0000" y2="0.0250">
          <profile>
            <point xym="0.000000 0.025000 15"/>
            <point xym="0.000000 0.000000 15"/>
            <point xym="0.125000 0.000000 15"/>
            <point xym="0.125000 0.025000 15"/>
            <point xym="0.000000 0.025000 -1"/>
          </profile>
        </panel>
        <panel thickness="0.0500" height="0.0250" x1="0.1050" x2="0.1550" y1="0.0250" y2="0.0500">
          <profile>
            <point xym="0.105000 0.050000 15"/>
            <point xym="0.105000 0.025000 15"/>
            <point xym="0.155000 0.025000 15"/>
            <point xym="0.155000 0.050000 15"/>
            <point xym="0.105000 0.050000 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.023" height="0.135" rot="0" id="PANEL_HOR_INOUT" name="Paneling horizontal in to out 23x145/135" name_fin="Vaakalaudoitus sisältä ulos 23x145/135" name_swe="Horizontella paneler in till ut 23x145/135" name_nor="Liggende kledning innside til utside 23x145/135" name_ger="Paneelierung wagerecht von innen nach außen 23x145/135" name_ita="Doghe orizzontali Int-Ext 23x145/135" name_por="Ripas horizontais Int-Ext 23x145/135">
        <panel id="PANEL 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
          <profile>
            <point xym="-0.01000000 0.01515500 15"/>
            <point xym="-0.01000000 0.00843200 15"/>
            <point xym="0.00200100 0.00843200 15"/>
            <point xym="0.00200100 0.00000000 15"/>
            <point xym="0.04189000 0.00000000 15"/>
            <point xym="0.04189000 0.00617400 15"/>
            <point xym="0.05409500 0.00617400 15"/>
            <point xym="0.05409500 0.00000000 15"/>
            <point xym="0.08186400 0.00000000 15"/>
            <point xym="0.08186400 0.00617400 15"/>
            <point xym="0.09396200 0.00617400 15"/>
            <point xym="0.09396200 0.00000000 15"/>
            <point xym="0.13500000 0.00000000 15"/>
            <point xym="0.13500000 0.00732000 15"/>
            <point xym="0.12169000 0.00732000 15"/>
            <point xym="0.12169000 0.01512800 15"/>
            <point xym="0.13498000 0.01512800 15"/>
            <point xym="0.13054600 0.02300000 15"/>
            <point xym="0.01872900 0.02300000 15"/>
            <point xym="0.01413300 0.01515500 15"/>
            <point xym="-0.01000000 0.01515500 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.023" height="0.135" rot="0" id="PANEL_23x145/135_OUTIN" name="Panel gro 23x145/135 outin" name_fin="Paneeli valeura 23x145/135 ulkoa sisälle" name_ita="Doghe lisce orizzontali Ext-Int 23x145/135" name_por="Ripas horizontais lisas Ext-Int 23x145/135">
        <panel id="PANEL GRO 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
          <profile>
            <point xym="-0.01000000 0.01459500 15"/>
            <point xym="-0.01000000 0.00787200 15"/>
            <point xym="0.01413300 0.00787200 15"/>
            <point xym="0.01872900 0.00002700 15"/>
            <point xym="0.06329500 0.00000000 15"/>
            <point xym="0.06772900 0.00787200 15"/>
            <point xym="0.08172900 0.00787200 15"/>
            <point xym="0.08616300 0.00000000 15"/>
            <point xym="0.13054600 0.00002700 15"/>
            <point xym="0.13498000 0.00789900 15"/>
            <point xym="0.12169000 0.00789900 15"/>
            <point xym="0.12169000 0.01570700 15"/>
            <point xym="0.13500000 0.01570700 15"/>
            <point xym="0.13500000 0.02302700 15"/>
            <point xym="0.00200100 0.02302700 15"/>
            <point xym="0.00200100 0.01459500 15"/>
            <point xym="-0.01000000 0.01459500 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.023" height="0.135" rot="0" id="PANEL_23x145/135_INOUT" name="Panel gro 23x145/135 inout" name_fin="Paneeli valeura 23x145/135 sisältä ulos" name_ita="Doghe lisce orizzontali Int-Ext 23x145/135" name_por="Ripas horizontais lisas Ext-Int 23x145/135">
        <panel id="PANEL GRO 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
          <profile>
            <point xym="-0.01000000 0.01515500 15"/>
            <point xym="-0.01000000 0.00843200 15"/>
            <point xym="0.00200100 0.00843200 15"/>
            <point xym="0.00200100 0.00000000 15"/>
            <point xym="0.13500000 0.00000000 15"/>
            <point xym="0.13500000 0.00732000 15"/>
            <point xym="0.12169000 0.00732000 15"/>
            <point xym="0.12169000 0.01512800 15"/>
            <point xym="0.13498000 0.01512800 15"/>
            <point xym="0.13054600 0.02300000 15"/>
            <point xym="0.08616300 0.02302700 15"/>
            <point xym="0.08172900 0.01515500 15"/>
            <point xym="0.06772900 0.01515500 15"/>
            <point xym="0.06329500 0.02302700 15"/>
            <point xym="0.01872900 0.02300000 15"/>
            <point xym="0.01413300 0.01515500 15"/>
            <point xym="-0.01000000 0.01515500 -1"/>
          </profile>
        </panel>
      </paneling>


      <!-- 22x145/130 -->
      <paneling thickness="0.0220" height="0.130" rot="0" id="PANEL 22x145/130 OUTIN" name="Panel 22x145/130 outin" name_ita="Doghe lisce orizzontali Ext-Int 22x145/135" name_por="Ripas horizontais lisas Ext-Int 22x145/135">
        <panel id="Panel 22x145/130" thickness="0.022" height="0.145" y1="0.000" y2="0.022" x1="0.000" x2="0.130">
          <profile>
            <point xym="0.00200100 0.01456800 15"/>
            <point xym="-0.01500000 0.01456800 15"/>
            <point xym="-0.01500000 0.00784500 15"/>
            <point xym="0.01413300 0.00784500 15"/>
            <point xym="0.01872900 0.00000000 15"/>
            <point xym="0.12554600 0.00000000 15"/>
            <point xym="0.12998000 0.00787200 15"/>
            <point xym="0.11169000 0.00787200 15"/>
            <point xym="0.11169000 0.01568000 15"/>
            <point xym="0.13000000 0.01568000 15"/>
            <point xym="0.13000000 0.02200000 15"/>
            <point xym="0.00200100 0.02200000 15"/>
            <point xym="0.00200100 0.01456800 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0220" height="0.130" rot="0" id="PANEL 22x145/130 INOUT" name="Panel 22x145/130 inout" name_ita="Doghe lisce orizzontali Int-Ext 22x145/135" name_por="Ripas horizontais lisas Ext-Int 22x145/135">
        <panel id="Panel 22x145/130" thickness="0.022" height="0.145" y1="0.000" y2="0.022" x1="0.000" x2="0.130">
          <profile>
            <point xym="-0.01500000 0.00743200 15"/>
            <point xym="0.00200100 0.00743200 15"/>
            <point xym="0.00200100 0.00000000 15"/>
            <point xym="0.13000000 0.00000000 15"/>
            <point xym="0.13000000 0.00632000 15"/>
            <point xym="0.11169000 0.00632000 15"/>
            <point xym="0.11169000 0.01412800 15"/>
            <point xym="0.12998000 0.01412800 15"/>
            <point xym="0.12554600 0.02200000 15"/>
            <point xym="0.01872900 0.02200000 15"/>
            <point xym="0.01413300 0.01415500 15"/>
            <point xym="-0.01500000 0.01415500 15"/>
            <point xym="-0.01500000 0.00743200 -1"/>
          </profile>
        </panel>
      </paneling>


      <!-- 22x120/105 -->
      <paneling thickness="0.0220" height="0.105" rot="0" id="PANEL 22x120/105 OUTIN" name="Panel 22x120/105 outin" name_ita="Doghe 22x120/105 Ext-Int" name_por="Ripas 22x120/105 Ext-Int">
        <panel id="Panel 22x120/105" thickness="0.022" height="0.120" y1="0.000" y2="0.022" x1="0.000" x2="0.105">
          <profile>
            <point xym="0.00200100 0.01456800 15"/>
            <point xym="-0.01500000 0.01456800 15"/>
            <point xym="-0.01500000 0.00784500 15"/>
            <point xym="0.01413300 0.00784500 15"/>
            <point xym="0.01872900 0.00000000 15"/>
            <point xym="0.10054600 0.00000000 15"/>
            <point xym="0.10498000 0.00787200 15"/>
            <point xym="0.08669000 0.00787200 15"/>
            <point xym="0.08669000 0.01568000 15"/>
            <point xym="0.10500000 0.01568000 15"/>
            <point xym="0.10500000 0.02200000 15"/>
            <point xym="0.00200100 0.02200000 15"/>
            <point xym="0.00200100 0.01456800 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0220" height="0.105" rot="0" id="PANEL 22x120/105 INOUT" name="Panel 22x120/105 inout" name_ita="Doghe 22x120/105 Int-Ext" name_por="Ripas 22x120/105 Ext-Int">
        <panel id="Panel 22x120/105" thickness="0.022" height="0.120" y1="0.000" y2="0.022" x1="0.000" x2="0.105">
          <profile>
            <point xym="-0.01500000 0.00743200 15"/>
            <point xym="0.00200100 0.00743200 15"/>
            <point xym="0.00200100 0.00000000 15"/>
            <point xym="0.10500000 0.00000000 15"/>
            <point xym="0.10500000 0.00632000 15"/>
            <point xym="0.08669000 0.00632000 15"/>
            <point xym="0.08669000 0.01412800 15"/>
            <point xym="0.10498000 0.01412800 15"/>
            <point xym="0.10054600 0.02200000 15"/>
            <point xym="0.01872900 0.02200000 15"/>
            <point xym="0.01413300 0.01415500 15"/>
            <point xym="-0.01500000 0.01415500 15"/>
            <point xym="-0.01500000 0.00743200 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0150" height="0.110" rot="0" id="PANEL 15x120/110" name="Panel 15x120/110 nogroove" name_ita="Doghe 15x120/110 no scanalature" name_por="Ripas 15x120/110 Ext-Int sem ranhura">
        <panel id="Panel 15x120/110" thickness="0.015" height="0.120" y1="0.000" y2="0.015" x1="0.000" x2="0.110">
          <profile>
            <point xym="-0.01000000 0.01000000 15"/>
            <point xym="-0.01000000 0.00500000 15"/>
            <point xym="0.00100000 0.00500000 15"/>
            <point xym="0.00100000 0.00000000 15"/>
            <point xym="0.11000000 0.00000000 15"/>
            <point xym="0.11000000 0.00400000 15"/>
            <point xym="0.09900000 0.00400000 15"/>
            <point xym="0.09900000 0.01100000 15"/>
            <point xym="0.11000000 0.01100000 15"/>
            <point xym="0.11000000 0.01500000 15"/>
            <point xym="0.00100000 0.01500000 15"/>
            <point xym="0.00100000 0.01000000 15"/>
            <point xym="-0.01000000 0.01000000 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0140" height="0.110" rot="0" id="PANEL 14x120/110" name="Panel 14x120/110 nogroove" name_ita="Doghe 14x120/110 no scanalature" name_por="Ripas 14x120/110 Ext-Int sem ranhura">
        <panel id="Panel 14x120/110" thickness="0.014" height="0.120" y1="0.000" y2="0.014" x1="0.000" x2="0.110">
          <profile>
            <point xym="-0.01000000 0.00950000 15"/>
            <point xym="-0.01000000 0.00450000 15"/>
            <point xym="0.00100000 0.00450000 15"/>
            <point xym="0.00100000 0.00000000 15"/>
            <point xym="0.11000000 0.00000000 15"/>
            <point xym="0.11000000 0.00350000 15"/>
            <point xym="0.09900000 0.00350000 15"/>
            <point xym="0.09900000 0.01050000 15"/>
            <point xym="0.11000000 0.01050000 15"/>
            <point xym="0.11000000 0.01400000 15"/>
            <point xym="0.00100000 0.01400000 15"/>
            <point xym="0.00100000 0.00950000 15"/>
            <point xym="-0.01000000 0.00950000 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0190" height="0.130" rot="90" id="19x148/130 outin" name="19x148/130 outin" name_ita="19x148/130 Ext-Int" name_por="19x148/130 Ext-Int">
        <panel id="Panel 19x148/130" thickness="0.019" height="0.148" y1="0.000" y2="0.019" x1="0.000" x2="0.130">
          <profile>
            <point xym="-0.00000000 0.01000000 15"/>
            <point xym="-0.01800000 0.01000000 15"/>
            <point xym="-0.01800000 0.00000000 15"/>
            <point xym="0.10000000 0.00000000 15"/>
            <point xym="0.10000000 0.01000000 15"/>
            <point xym="0.13000000 0.01000000 15"/>
            <point xym="0.13000000 0.01900000 15"/>
            <point xym="-0.00000000 0.01900000 15"/>
            <point xym="-0.00000000 0.01000000 -1"/>
          </profile>
        </panel>
      </paneling>

      <paneling thickness="0.0190" height="0.130" rot="90" id="19x148/130 inout" name="19x148/130 inout" name_ita="19x148/130 Int-Ext" name_por="19x148/130 Ext-Int">
        <panel id="Panel 19x148/130" thickness="0.019" height="0.148" y1="0.000" y2="0.019" x1="0.000" x2="0.130">
          <profile>
            <point xym="-0.01800000 0.00900000 15"/>
            <point xym="-0.00000000 0.00900000 15"/>
            <point xym="-0.00000000 0.00000000 15"/>
            <point xym="0.13000000 0.00000000 15"/>
            <point xym="0.13000000 0.00900000 15"/>
            <point xym="0.10000000 0.00900000 15"/>
            <point xym="0.10000000 0.01900000 15"/>
            <point xym="-0.01800000 0.01900000 15"/>
            <point xym="-0.01800000 0.00900000 -1"/>
          </profile>
        </panel>
      </paneling>


      <paneling thickness="0.0190" height="0.052" rot="90" id="19x70/52 outin" name="19x70/52 outin" name_ita="19x70/52 Ext-Int" name_por="19x70/52 Ext-Int">
        <panel id="Panel 19x70/52" thickness="0.019" height="0.070" y1="0.000" y2="0.019" x1="0.000" x2="0.052">
          <profile>
            <point xym="0.00000000 0.01000000 15"/>
            <point xym="-0.01800000 0.01000000 15"/>
            <point xym="-0.01800000 0.00000000 15"/>
            <point xym="0.02200000 0.00000000 15"/>
            <point xym="0.02200000 0.01000000 15"/>
            <point xym="0.05200000 0.01000000 15"/>
            <point xym="0.05200000 0.01900000 15"/>
            <point xym="0.00000000 0.01900000 15"/>
            <point xym="0.00000000 0.01000000 -1"/>
          </profile>
        </panel>
      </paneling>


      <paneling thickness="0.0190" height="0.052" rot="90" id="19x70/52 inout" name="19x70/52 inout" name_ita="19x70/52 Int-Ext" name_por="19x70/52 Int-Ext">
        <panel id="Panel 19x70/52" thickness="0.019" height="0.070" y1="0.000" y2="0.019" x1="0.000" x2="0.052">
          <profile>
            <point xym="-0.01800000 0.00900000 15"/>
            <point xym="0.00000000 0.00900000 15"/>
            <point xym="0.00000000 0.00000000 15"/>
            <point xym="0.05200000 0.00000000 15"/>
            <point xym="0.05200000 0.00900000 15"/>
            <point xym="0.02200000 0.00900000 15"/>
            <point xym="0.02200000 0.01900000 15"/>
            <point xym="-0.01800000 0.01900000 15"/>
            <point xym="-0.01800000 0.00900000 -1"/>
          </profile>
        </panel>
      </paneling>
    </panelings>

  </elem>

</archiframe>
