<?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" sort="yx" sortboard="xy"></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>
		<!-- Let it come from the master element: 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>
		<!-- Let it come from the master element: 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 (milling), will set the type to router if it is inner cut up to given length -->
      <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>
        <!-- ### SHARED BETWEEN ALL DATA FOLDERS BEGIN -->
        <dimlines id="common_boardonly_front">
          <dimline side="top" margin="0.50" elemvecx="1" addminmax="1" addx="1" anchorfirst="1" anchorlast="1" include="*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" content_kor="보드" content_pol="DESKA" 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>

          <!-- Dimension line for openings horizontal -->
          <dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" addopeningmin="1" addopeningmax="1" minpoints="3" exclude="*" include="core" onlyelem="1">
            <text content="OPENING" content_fin="AUKKO" content_nor="ÅPNINGER" content_kor="개구부" content_pol="OTWÓR" 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>

          <!-- Boards vert, addx will add non rotated boards -->
          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" addx="1" anchorfirst="1" anchorlast="1" include="*">
            <dimlinesettings>
            </dimlinesettings>
            <text content="BOARD" content_fin="LEVY" content_nor="SKIVA" content_kor="보드" content_pol="DESKA" 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>

          <!-- 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" content_kor="개구부" content_pol="OTWÓR" 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 -->
          <dimline side="right" margin="0.25" elemvecy="1" addminmax="1" exclude="*" includeelem="*core*">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>
        </dimlines>
        <!-- ### SHARED BETWEEN ALL DATA FOLDERS END -->


        <!-- 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="외장재" content_pol="PŁYTOWANIE" 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" content_kor="스터드 중앙" content_pol="ŚRODEK SŁUPKA" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="외장재" content_pol="PŁYTOWANIE" 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" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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="wall_top_groupstuds" 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*" scriptfind="FindCoreStudGroupsForDim">
						<dimlinesettings>
							<elemparam name="dimensiontype">cumulative</elemparam>
							<elemparam name="markertype">5</elemparam>
						</dimlinesettings>
						<text content="STUD LEFT" content_fin="TOLPPA VASEN" content_nor="STENDERE VENSTRE" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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" content_kor="서까래 좌측" content_pol="KROKWIE OD LEWEJ" 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_rotated" script="dim_scripts" scriptcreate="TopDimLines">
          <!-- Element thickness -->
          <dimline side="left" margin="1.0" elemvecz="1" addminmax="1">
            <dimlinesettings>
              <elemparam name="fontsize">2</elemparam>
            </dimlinesettings>
          </dimline>

          <!-- Dimension line for vertical posts cumulative -->
          <dimline side="top" margin="1" elemvecx="1" addy="1" anchorfirst="1">
            <dimlinesettings>
              <elemparam name="dimensiontype">cumulative</elemparam>
            </dimlinesettings>
            <text content="STENDERE V" 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 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" content_kor="스터드 중앙" content_pol="ŚRODEK SŁUPKA" 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" content_kor="개구부" content_pol="OTWÓR" 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>

        <dimlines id="an_framing_groupstuds" script="dim_scripts" scriptcreate="AddCoreModules">
          <!-- Tolpat väli keskellä -->
          <dimline side="bottom" margin="1" elemvecx="1" addy="1" anchormid="1" exclude="*" include="*core*" scriptfind="FindCoreStudGroupsForDim">
            <text content="STUD MID" content_fin="TOLPPA KESKI" content_nor="STENDERE SENTER" content_kor="스터드 중앙" content_pol="ŚRODEK SŁUPKA" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="개구부" 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" content_kor="단열재" content_pol="IZOLACJA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="스터드 중앙" content_pol="ŚRODEK SŁUPKA" 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" content_kor="스터드 좌측" content_pol="SŁUPKI OD LEWEJ" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_pol="ŚRODEK SŁUPKA" content_kor="스터드 중앙" 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" content_kor="개구부" content_pol="OTWÓR" 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" content_kor="외장재" content_pol="PŁYTOWANIE" 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" content_kor="외장재" content_pol="PŁYTOWANIE" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드1" content_pol="DESKA1" 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" content_kor="보드2" content_pol="DESKA2" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="단열재" content_pol="IZOLACJA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="보드" content_pol="DESKA" 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" content_kor="하단" content_pol="DÓŁ" 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" content_kor="보드" content_pol="DESKA" 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>

				<!-- Added 9/2024 -->
				<dimlines id="framing_stud">
					<dimline side="bottom" margin="0.5" elemvecx="1" addy="1" anchorfirst="1" minpoints="3" exclude="*" include="*stud*">
						<dimlinesettings>
							<elemparam name="dimensiontype">cumulative</elemparam>
							<elemparam name="markertype">5</elemparam>
						</dimlinesettings>
					</dimline>

					<dimline side="bottom" margin="0.25" elemvecx="1" addminmax="1" minpoints="3" exclude="*" includeelem="*core*,*stud*" onlyelem="1">
					</dimline>
				</dimlines>
				
				<!-- Added 9/2024 -->
				<dimlines id="horframing_stud">
					<dimline side="right" margin="0.5" elemvecy="1" addx="1" anchorfirst="1" minpoints="3" exclude="*" include="*stud*">
						<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*,*stud*" onlyelem="1">
					</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"
elseif gLang=="kor" then
  gListSettings.title="#id# 코어"
  elseif gLang=="pol" then
  gListSettings.title="#id# RDZEŃ"
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" 
elseif gLang=="kor" then
  gListSettings.title="#id# 스터드"
  elseif gLang=="pol" then
  gListSettings.title="#id# SŁUPKI"
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="ANDRE" 
elseif gLang=="por" then
  gListSettings.title="OUTROS" 
elseif gLang=="kor" then
  gListSettings.title="기타"
  elseif gLang=="pol" then
  gListSettings.title="INNE"
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"
elseif gLang=="kor" then
  gListSettings.title="모듈"
  elseif gLang=="pol" then
  gListSettings.title="MODUŁY"
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" 
elseif gLang=="kor" then
  gListSettings.title="#id# 단열재"
  elseif gLang=="pol" then
  gListSettings.title="#id# IZOLACJA"
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"
elseif gLang=="kor" then
  gListSettings.title="외부 보딩"
  elseif gLang=="pol" then
  gListSettings.title="DESKI ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외부 보딩"
  elseif gLang=="pol" then
  gListSettings.title="DESKI ZEWNĘTRZNE"
end

gListSettings.funccollect=function(plank)
  if plank.elemtype and (plank.elemtype=="boarding_ext" or plank.elemtype=="boarding_ext2") 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_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"
elseif gLang=="kor" then
  gListSettings.title="외부 보딩"
  elseif gLang=="pol" then
  gListSettings.title="PŁYTY ZEWNĘTRZNE"
end

gListSettings.funccollect=function(plank)
  if plank.elemtype and plank.elemtype=="boarding_ext3" 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_extboards3>

				<!-- Exterior boards 4 -->
				<cutlist_table_extboards4 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"
elseif gLang=="kor" then
  gListSettings.title="외부 보딩"
  elseif gLang=="pol" then
  gListSettings.title="PŁYTY ZEWNĘTRZNE"
end

gListSettings.funccollect=function(plank)
  if plank.elemtype and plank.elemtype=="boarding_ext4" 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_extboards4>


				<!-- 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"
elseif gLang=="kor" then
  gListSettings.title="외장재 및 외부 스터딩"
  elseif gLang=="pol" then
  gListSettings.title="OKŁADZINY I SŁUPKI ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외부"
  elseif gLang=="pol" then
  gListSettings.title="ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="내부 스터딩 및 내장재"
  elseif gLang=="pol" then
  gListSettings.title="SŁUPKI WEWNĘTRZNE I OKŁADZINY WEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외부 스터딩"
  elseif gLang=="pol" then
  gListSettings.title="SŁUPKI ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외부 스터딩"
  elseif gLang=="pol" then
  gListSettings.title="SŁUPKI ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외부 스터딩"
  elseif gLang=="pol" then
gListSettings.title="SŁUPKI ZEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="외장재"
  elseif gLang=="pol" then
  gListSettings.title="OKŁADZINY"
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"
elseif gLang=="kor" then
  gListSettings.title="내부 보딩"
  elseif gLang=="pol" then
  gListSettings.title="PŁYTOWANIE WEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="내부 보딩 1"
  elseif gLang=="pol" then
gListSettings.title="PŁYTOWANIE WEWNĘTRZNE 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"
elseif gLang=="kor" then
  gListSettings.title="내부 보딩 2"
elseif gLang=="kor" then
  gListSettings.title="PŁYTOWANIE WEWNĘTRZNE 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"
elseif gLang=="kor" then
  gListSettings.title="내부 보딩 3"
elseif gLang=="pol" then
  gListSettings.title="PŁYTOWANIE WEWNĘTRZNE 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"
elseif gLang=="kor" then
  gListSettings.title="내부 스터딩"
elseif gLang=="pol" then
  gListSettings.title="SŁUPKI WEWNĘTRZNE"
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"
elseif gLang=="kor" then
  gListSettings.title="#id# 코어"
elseif gLang=="pol" then
  gListSettings.title="#id# RDZEŃ"
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"
elseif gLang=="kor" then
  gListSettings.title="#id# 기타 물품"
elseif gLang=="pol" then
  gListSettings.title="#id# AKCESORIA"
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()
  return af_request("aflang")
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"
      elseif lang=="kor" then
        elemgroup="블록킹"
        elseif lang=="pol" then
        elemgroup="Rygiel"
      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"
      elseif lang=="kor" then
        elemgroup="측면 빔"
         elseif lang=="pol" then
        elemgroup="Słupki boczne"
      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
      elseif lang=="kor" then
        elemgroup="장선"
      elseif lang=="pol" then
        elemgroup="Belka wymianowa"
      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
      elseif lang=="kor" then
        elemgroup="장선"
      elseif lang=="pol" then
        elemgroup="Belka modułowa"
      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
      elseif lang=="kor" then
        elemgroup="장선"
      elseif lang=="pol" then
        elemgroup="Belka boczna"
      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"
      elseif lang=="kor" then
        elemgroup="윤곽 피스"
      elseif lang=="pol" then
        elemgroup="Listwa krawędziowa"
      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"
      elseif lang=="kor" then
        elemgroup="장선"
      elseif lang=="pol" then
        elemgroup="Legar"
      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"
      elseif lang=="kor" then
        elemgroup="상단/하단"
      elseif lang=="pol" then
        elemgroup="góra/dół"
      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"
      elseif lang=="kor" then
        elemgroup="서까래"
      elseif lang=="pol" then
        elemgroup="Krokiew"
      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"
      elseif lang=="kor" then
        elemgroup="스터드"
      elseif lang=="pol" then
        elemgroup="słupek"
      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"
      elseif lang=="kor" then
        elemgroup="스터드"
      elseif lang=="pol" then
        elemgroup="słupek"
      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"
      elseif lang=="kor" then
        elemgroup="문/창"
      elseif lang=="pol" then
        elemgroup="Drzwi/Okno"
      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"
      elseif lang=="kor" then
        elemgroup="수평"
      elseif lang=="pol" then
        elemgroup="Poziomo"
      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"
      elseif lang=="kor" then
        elemgroup="각도"
      elseif lang=="pol" then
        elemgroup="Pod kątem"
      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"
      elseif lang=="kor" then
        elemgroup="보크"
      elseif lang=="pol" then
        elemgroup="Belka"
      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"
      elseif lang=="kor" then
        elemgroup="W/D 빔"
      elseif lang=="pol" then
        elemgroup="Belka nadprożowa"
      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"
      elseif lang=="kor" then
        elemgroup="보강"
      elseif lang=="pol" then
        elemgroup="Wzmocnienie"
      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"
      elseif lang=="kor" then
        elemgroup="블록킹"
      elseif lang=="pol" then
        elemgroup="Wsparcie wyboczenia"
      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"
      elseif lang=="kor" then
        elemgroup="측면 빔"
      elseif lang=="pol" then
        elemgroup="Belki boczne"
      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"
      elseif lang=="kor" then
        elemgroup="탑 플레이트"
      elseif lang=="pol" then
        elemgroup="Nadproże górne"
      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"
      elseif lang=="kor" then
        elemgroup="바텀 플레이트"
      elseif lang=="pol" then
        elemgroup="Podwalina"
      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"
      elseif lang=="kor" then
        elemgroup="탑/바텀 플레이트"
      elseif lang=="pol" then
        elemgroup="Nadproże górne/podwalina"
      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"
      elseif lang=="kor" then
        elemgroup="창/문"
      elseif lang=="pol" then
        elemgroup="Okno/Drzwi"
      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"
      elseif lang=="kor" then
        elemgroup="스터드"
      elseif lang=="pol" then
        elemgroup="Słupek"
      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"
      elseif lang=="kor" then
        elemgroup="각도"
      elseif lang=="pol" then
        elemgroup="Pod kątem"
      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"
      elseif lang=="kor" then
        elemgroup="빔 상단"
      elseif lang=="pol" then
        elemgroup="Belka górna"
      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"
      elseif lang=="kor" then
        elemgroup="빔 하단"
      elseif lang=="pol" then
        elemgroup="Belka dolna"
      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"
      elseif lang=="kor" then
        elemgroup="W/D 빔"
      elseif lang=="pol" then
        elemgroup="Belka nadprożowa"
      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"
      elseif lang=="kor" then
        elemgroup="블록킹"
      elseif lang=="pol" then
        elemgroup="Wzmocnienie wyboczenia"
      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"
      elseif lang=="kor" then
        elemgroup="측면 빔"
      elseif lang=="pol" then
        elemgroup="Belki boczne"
      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


function GetAngleStr(angleDeg)
  return ac_environment ("ntos", angleDeg*0.0174532925199, "angle", "dim")    -- angleDeg*PI/180
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
          elseif lang=="kor" then
            s="전면"
            if side==1 then
              s="후면"
            end
          elseif lang=="pol" then
            s="przód"
            if side==1 then
              s="tył"
            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
          elseif lang=="kor" then
            s="하단"
            if side==1 then
              s="상단"
            end
          elseif lang=="pol" then
            s="góra"
            if side==1 then
              s="dół"
            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))
            elseif lang=="kor" then
              s=string.format("슬롯 %s %sx%s 하단부터 %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            elseif lang=="pol" then
              s=string.format("Wycięcie %s %sx%s od dołu %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))
            elseif lang=="kor" then
              s=string.format("슬롯 %s %sx%s 시작부터 %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            elseif lang=="pol" then
              s=string.format("Wycięcie %s %sx%s od podstawy %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))
            elseif lang=="kor" then
              s=string.format("슬롯 %s %sx%s 상단부터 %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            elseif lang=="pol" then
              s=string.format("Wycięcie %s %sx%s od góry %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            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))
            elseif lang=="kor" then
              s=string.format("슬롯 %s %sx%s 끝부터 %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            elseif lang=="pol" then
              s=string.format("Wycięcie %s %sx%s od końca %s", s, Len2Str(depth), Len2Str(width), Len2Str(distBot))
            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
      elseif lang=="kor" then
        fmt="각도 시작"
        if mc==201 then
          fmt="각도 끝"
        end
      elseif lang=="pol" then
        fmt="Kąt na początku"
        if mc==201 then
          fmt="Kąt na końcu"
        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 %s", fmt, GetAngleStr(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 %s", fmt, GetAngleStr(math.abs(a2-90)))
       elseif lang=="kor" then
          s=string.format("%s 높이 방향으로 %s", fmt, GetAngleStr(math.abs(a2-90)))
       elseif lang=="pol" then
          s=string.format("%s w kierunku wysokości %s", fmt, GetAngleStr(math.abs(a2-90)))
        else
          s=string.format("%s in height dir %s", fmt, GetAngleStr(math.abs(a2-90)))
        end
      else
        if lang=="fin" then
          s=string.format("%s kahteen suuntaan, katso ohje", fmt)
       elseif lang=="kor" then
          s=string.format("%s 이중 각도, 자세히 보기", fmt)
       elseif lang=="pol" then
          s=string.format("%s podwójny kąt, zobacz szczegóły", 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))
          elseif lang=="kor" then
            s=string.format("길이방향 자르기 %sx%s", Len2Str(depth), Len2Str(height))
          elseif lang=="pol" then
            s=string.format("cięcie wzdłużnie %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)
    elseif lang=="kor" then
      s=string.format("다른 절단 %d pcs - 자세히 보기", nUnknown)
    elseif lang=="pol" then
      s=string.format("inne cięcia %d szt. - zobacz szczegóły", 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"
        elseif lang=="kor" then
          s="이중 스터드"
        elseif lang=="pol" then
          s="podwójny słupek"
        else
          s="double stud"
        end
      else
        if lang=="fin" then
          s=string.format("%d x tolppa", i)
        elseif lang=="kor" then
          s=string.format("%d x 스터드", i)
        elseif lang=="pol" then
          s=string.format("%d x słupek", 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)
      elseif lang=="kor" then
        res=res .. string.format("%d 개 %s", tblGroup[i], s)
      elseif lang=="pol" then
        res=res .. string.format("%d szt. %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" 
    elseif lang=="kor" then
      elemTypeName="기타" 
    elseif lang=="pol" then
      elemTypeName="Inne" 
    else
      elemTypeName="OTHERS"
    end        
    
    if vElem.elemtype=="core" then
      elemTypeSort="001"
      if lang=="fin" then
        elemTypeName="TOLPAT"
      elseif lang=="kor" then
        elemTypeName="스터드" 
      elseif lang=="pol" then
        elemTypeName="Słupki" 
      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" 
      elseif lang=="kor" then
        tblElemSortToName["002"]="기타" 
      elseif lang=="pol" then
        tblElemSortToName["002"]="Inne" 
      else
        tblElemSortToName["002"]="OTHERS"
      end
    elseif string.match(vElem.elemtype, "^intstud*") then
      elemTypeSort="010"
      if lang=="fin" then
        elemTypeName="SISÄKOOLAUS"
      elseif lang=="kor" then
        elemTypeName="내부 스터딩"
      elseif lang=="pol" then
        elemTypeName="SłUPKI WEWNĘTRZNE"
      else
        elemTypeName="INT STUDDING"
      end        
    elseif string.match(vElem.elemtype, "^extstud*") then
      elemTypeSort="020"
      if lang=="fin" then
        elemTypeName="ULKOKOOLAUS"
      elseif lang=="kor" then
        elemTypeName="외부 스터딩"
      elseif lang=="pol" then
        elemTypeName="SŁUPKI ZEWNĘTRZNE"
      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"
      elseif lang=="kor" then
        elemTypeName="외장재"
      elseif lang=="pol" then
        elemTypeName="OKŁADZINY"
      else
        elemTypeName="CLADDING"
      end
    elseif string.match(vElem.elemtype, "^boarding_ext*") then
      elemTypeSort="040"
      if lang=="fin" then
        elemTypeName="LEVY ULKO"
      elseif lang=="kor" then
        elemTypeName="외부 보딩"
      elseif lang=="pol" then
        elemTypeName="PŁYTOWANIE ZEWNĘTRZNE"
      else
        elemTypeName="BOARD EXT"
      end
    elseif string.match(vElem.elemtype, "^boarding_int*") then
      elemTypeSort="050"
      if lang=="fin" then
        elemTypeName="LEVY SISÄ"
      elseif lang=="kor" then
        elemTypeName="내부 보딩"
      elseif lang=="pol" then
        elemTypeName="PŁYTOWANIE WEWNĘTRZNE"
      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"
      elseif lang=="kor" then
        typeName="외부 스터드 및 외장재"
       elseif lang=="pol" then
        typeName="SŁUPKI ZEWNĘTRZNE I OKŁADZINY"
      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"
        elseif lang=="kor" then
          typeName="외장재"
        elseif lang=="pol" then
          typeName="SŁUPKI ZEWNĘTRZNE"
        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
     elseif lang=="pol" 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]" windowtext_kor="창문 [width]x[height]" doortext_kor="문 [width]x[height]" windowtext_pol="Okno [width]x[height]" doortext_pol="Drzwi [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>
          <!-- Applied after elem/settings/dimlinesettings and before script created settings. Note: Run before undo-session opened so not possible to create layers -->
          <!--
            <dimlinesettings>
              <layer>AF Planks</layer>
              <elemparam name="pen">33</elemparam>
            </dimlinesettings>
          -->

          <projection id="freeproj_default" name="Zero depth no dim lines" name_fin="Nollasyvyinen ilman mittoja" name_kor="깊이 0 치수 라인 없음" name_pol="Głębokość zerowa bez linii wymiarowych" 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" name_kor="깊이 0 치수 라인 없음 +90도 회전" name_pol="Głębokość zerowa bez linii wymiarowych obrót +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" name_kor="깊이 0 치수 라인 없음 -90도 회전" name_pol="Głębokość zerowa bez linii wymiarowych obrót -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" name_kor="깊이 0 치수 라인 100% v 1.0" name_pol="Głębokość zerowa z liniami wymiarowymi 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" name_kor="깊이 0 치수 라인 +90도 회전" name_pol="Głębokość zerowa z liniami wymiarowymi obrót +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" name_kor="깊이 0 치수 라인 -90도 회전" name_pol="Głębokość zerowa z liniami wymiarowymi obrót -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="*" name_kor="깊이 0 코어만 치수 라인 100% v 1.0" name_pol="Głębokość zerowa sam rdzeń z liniami wymiarowymi obrót 100% v 1.0" 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" name_kor="깊이 0 치수 라인 200% v 1.0" name_pol="Głębokość zerowa z liniami wymiarowymi 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" name_kor="깊이 0 코어만 치수 라인 200% v 1.0" name_pol="Głębokość zerowa sam rdzeń z liniami wymiarowymi 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 ***


function FindCoreStudGroupsForDimMid()
  return FindCoreStudGroupsForDim(0, 1, 0)
end


function FindCoreStudGroupsForDimLast()
  return FindCoreStudGroupsForDim(0, 0, 1)
end


-- Dim line creator uses to find just first stud in stud groups
function FindCoreStudGroupsForDim(anchorFirst, anchorMid, anchorLast)
  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
	
	
  if anchorFirst==nil then
			anchorFirst=1
	end
	if anchorMid==nil then
			anchorMid=0
	end
	if anchorLast==nil then
			anchorLast=0
	end
  
  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=anchorFirst     -- No need to mirror this one since projection knows which is left in projected pieces
        tbl.anchormid=anchorMid
        tbl.anchorlast=anchorLast
        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\" content_kor=\"외장재\" content_pol=\"OKŁADZINY\" 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\" content_kor=\"외장재\" content_pol=\"OKŁADZINY\" 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


	-- Localized strings BEG
	local strTitle = "Lintel settings"
	local strMat = "Material"
	local strElemMat = "Use element's material as default (affects prev setting)"
	local strThickness = "Thickness if not fixed"
	local strHeight = "Height if not fixed"
	local strBeamsFront = "Beams to front side"
	local strBeamsBack = "Beams to back side"
	local strRemoveOrg = "Remove original piece"
	local strExtendOrg = "Extend original piece"
	local strCutStuds = "Cut studs above lintel (grooves if not)"
	local strNumStuds = "Number of additional studs"
	local strBelowTop = "Place below top plate"
	local strExtraMat = "Extra studs mat id (empty=original)"
	local strExtendKing = "Extend beams to furthest side of the king studs"
	local strJoinBeams = "Join beams if closer than"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Aukonylityspalkin asetukset"
	  strMat = "Materiaali"
	  strElemMat = "Käytä elementin materiaalia oletuksena (vaikuttaa ed asetukseen)"
	  strThickness = "Paksuus jos ei vakio"
	  strHeight = "Korkeus jos ei vakio"
	  strBeamsFront = "Palkkeja etupuolelle"
	  strBeamsBack = "Palkkeja takapuolelle"
	  strRemoveOrg = "Poista alkuperäinen kappale"
	  strExtendOrg = "Jatka alkuperäistä kappaletta"
	  strCutStuds = "Katkaise tolpat palkin yläpuolella (kolot jos ei)"
	  strNumStuds = "Lisätolppien lkm"
	  strBelowTop = "Sijoita yläjuoksun alapuolelle"
	  strExtraMat = "Lisättävien tolppien materiaali-ID (tyhjä=alkup)"
	  strExtendKing = "Jatka palkkeja reunimmaisiin tolppiin"
	  strJoinBeams = "Liitä palkit, jos lähempänä kuin"
  elseif s=="kor" then
	  strTitle = "헤더 설정"
	  strMat = "소재"
	  strElemMat = "요소의 소재를 디폴트로 사용 (이전 설정에 영향을 미침)"
	  strThickness = "고정되지 않았을 경우 두께"
	  strHeight = "고정되지 않았을 경우 높이"
	  strBeamsFront = "전면부에 빔"
	  strBeamsBack = "후면부에 빔"
	  strRemoveOrg = "원본 피스 제거"
	  strExtendOrg = "원본 피스 연장"
	  strCutStuds = "헤더 위 스터드 절단 (아니면 홈 파기)"
	  strNumStuds = "추가 스터드의 수"
	  strBelowTop = "탑 플레이트 아래에 배치"
	  strExtraMat = "추가 스터드 소재 ID (빈값=원본)"
	  strExtendKing = "킹 스터드 가장 바깥 쪽으로 빔 연장"
	  strJoinBeams = "다음 값보다 작을 경우 빔 합치기"
  elseif s=="pol" then
    strTitle = "Ustawienia nadproża"
    strMat = "Materiał"
    strElemMat = "Użyj materiału elementu jako domyślnego (wpływa na poprzednie ustawienia)"
    strThickness = "Grubość, jeśli niestandardowa"
    strHeight = "Wysokość, jeśli niestandardowa"
    strBeamsFront = "Belki od przodu"
    strBeamsBack = "Belki od tyłu"
    strRemoveOrg = "Usuń oryginalny element"
    strExtendOrg = "Przedłuż oryginalny element"
    strCutStuds = "Przytnij słupki nad nadprożem (wcięcia, jeśli nie)"
    strNumStuds = "Liczba dodatkowych słupków"
    strBelowTop = "Umieść poniżej górnej belki (nadproża)"
    strExtraMat = "ID materiału dodatkowych słupków (puste = oryginał)"
    strExtendKing = "Przedłuż belki do najdalszej strony zewnętrznych słupków"
    strJoinBeams = "Połącz belki, jeśli jest odległość mniejsza niż"
	end
	-- Localized strings END

  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	=strMat
    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	=strElemMat
    gtblSettings[2].key		="usedefault"
    gtblSettings[2].defvalue	=1

    gtblSettings[3]			={}
    gtblSettings[3].cfgonly	=0
    gtblSettings[3].type		=3
    gtblSettings[3].prompt	=strThickness
    gtblSettings[3].key		="thickness"
    gtblSettings[3].defvalue	=0.050

    gtblSettings[4]			={}
    gtblSettings[4].cfgonly	=0
    gtblSettings[4].type		=3
    gtblSettings[4].prompt	=strHeight
    gtblSettings[4].key		="height"
    gtblSettings[4].defvalue	=0.100

    gtblSettings[5]			={}
    gtblSettings[5].cfgonly	=0
    gtblSettings[5].type		=4
    gtblSettings[5].prompt	=strBeamsFront
    gtblSettings[5].key		="beam_front"
    gtblSettings[5].defvalue	=1

    gtblSettings[6]			={}
    gtblSettings[6].cfgonly	=0
    gtblSettings[6].type		=4
    gtblSettings[6].prompt	=strBeamsBack
    gtblSettings[6].key		="beam_back"
    gtblSettings[6].defvalue	=0

    gtblSettings[7]			={}
    gtblSettings[7].cfgonly	=0
    gtblSettings[7].type		=2
    gtblSettings[7].prompt	=strRemoveOrg
    gtblSettings[7].key		="delorg"
    gtblSettings[7].defvalue	=0

    gtblSettings[8]			={}
    gtblSettings[8].cfgonly	=0
    gtblSettings[8].type		=2
    gtblSettings[8].prompt	=strExtendOrg
    gtblSettings[8].key		="extorg"
    gtblSettings[8].defvalue	=0

    gtblSettings[9]			={}
    gtblSettings[9].cfgonly	=0
    gtblSettings[9].type		=2
    gtblSettings[9].prompt	=strCutStuds
    gtblSettings[9].key		="cutabove"
    gtblSettings[9].defvalue	="0"

    gtblSettings[10]			={}
    gtblSettings[10].cfgonly	=0
    gtblSettings[10].type		=4
    gtblSettings[10].prompt	=strNumStuds
    gtblSettings[10].key		="numstuds"
    gtblSettings[10].defvalue	="1"

    gtblSettings[11]			={}
    gtblSettings[11].cfgonly	=0
    gtblSettings[11].type		=2
    gtblSettings[11].prompt	=strBelowTop
    gtblSettings[11].key		="totop"
    gtblSettings[11].defvalue	=0

    gtblSettings[12]			={}
    gtblSettings[12].cfgonly	=0
    gtblSettings[12].type		=4
    gtblSettings[12].prompt	=strExtraMat
    gtblSettings[12].key		="matidstud"
    gtblSettings[12].defvalue	=""

    gtblSettings[13]			={}
    gtblSettings[13].cfgonly	=0
    gtblSettings[13].type		=2
    gtblSettings[13].prompt	=strExtendKing
    gtblSettings[13].key		="extbeam"
    gtblSettings[13].defvalue	=0

    gtblSettings[14]			={}
    gtblSettings[14].cfgonly	=0
    gtblSettings[14].type		=3
    gtblSettings[14].prompt	=strJoinBeams
    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", strTitle, 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

-- tblNewEdited   New doubles and edited originals are collected here (only if horizontal). Has fields bx1, by1, bx2, by2 telling the bounding box in element's coordinates and oldindex for edited planks telling the plank index
-- 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(tblNewEdited)
  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
						
						if math.abs(p1.y - p2.y)<0.0001 and math.abs(origElemData.rotangle)<0.0001 then
						  -- Horizontal and no angle in watching direction, add to new/edited planks
							local t={}
							
							t.bx1 = p1.x
							t.by1 = p1.y - newOrigMaterial.thickness * 0.5
							t.bx2 = p2.x
							t.by2 = p1.y + newOrigMaterial.thickness * 0.5
							if t.bx1>t.bx2 then
							  t.bx1,t.bx2 = t.bx2,t.bx1
							end
							t.oldindex = edge.tblPlankNumsAll[j]
              table.insert(tblNewEdited, t)
						end
          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)

			if math.abs(doublePlank.y1 - doublePlank.y2)<0.0001 and math.abs(doublePlank.rotangle)<0.0001 then
				-- Horizontal and no angle in watching direction, add to new/edited planks
				local t={}

				t.bx1 = doublePlank.x1
				t.by1 = doublePlank.y1 - doubleMaterial.thickness * 0.5
				t.bx2 = doublePlank.x2
				t.by2 = doublePlank.y2 + doubleMaterial.thickness * 0.5
				if t.bx1>t.bx2 then
					t.bx1,t.bx2 = t.bx2,t.bx1
				end
        table.insert(tblNewEdited, t)
			end

      -- 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")

  -- Collect connections to all operators to handle double cut studs correctly
  local tblConnections={}       -- index=vertical plank, value=table of indexes of the double planks to adjust to
  local t, k, v

  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
        t=tblConnections[verticalPlank.index]
        if t==nil then
          t={}
          tblConnections[verticalPlank.index]=t
        end
        t[#t+1]=bottomEdge.operatorId
      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
        t=tblConnections[verticalPlank.index]
        if t==nil then
          t={}
          tblConnections[verticalPlank.index]=t
        end
        t[#t+1]=bottomEdge.operatorId
      end
    end
  end

  for k,v in pairs(tblConnections) do
    local operatorId
    local operatorIds="#"
    for i, operatorId in ipairs(v) do
      if i>1 then
        operatorIds = operatorIds .. ","
      end
      operatorIds=string.format("%s%d", operatorIds, operatorId)
    end
	
    operations=string.format(
        "%s" ..
        "  <jointo target=\"#%d\" operator=\"%s\">\n" ..
        "    <cut endshape=\"angleddelfirst\" removepart=\"%s\"></cut>\n" ..
        "  </jointo>\n",
        operations, k, operatorIds, removePart)
  end

--ac_environment("tolog", operations)

  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


-- Returns: true=b1 contains b2, false=nope
function ContainsBox(b1, b2)
  local eps=0.0001
	
	return b1.bx1-eps < b2.bx1 and b1.by1-eps < b2.by1 and b1.bx2+eps > b2.bx2 and b1.by2+eps > b2.by2
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
	
	local tblNewEdited={}      -- Collect new and changed planks here to be able to remove 100% covered old planks
	
  gxmlOperations=DoDoubleTopBot(tblNewEdited)
	
  local i, v, e
	
	for _,v in ipairs(tblNewEdited) do
	  for i=1,gnPlanks do
		  ac_objectopen(string.format("#%d", i))
			e = ac_objectget("#af_elemdata")
			
			if math.abs(e.rotangle)<0.0001 and ContainsBox(v, e) and (v.oldindex==nil or i~=v.oldindex) then
--ac_environment("tolog", string.format("DEL %s", ac_objectget("#id")))
			  af_request("delplank")
			end
			
			ac_objectclose()
		end
	end
	
  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

  -- Collect connections to all operators to handle double cut studs correctly
  local tblConnections={}       -- index=vertical plank, value=table of indexes of the double planks to adjust to
  local t, k, v

  for i, edge in ipairs(angledEdges) do
    for j, plankId in ipairs(edge.tblPlankNumsAll) do
      for k, verticalPlank in ipairs(verticalPlanksToReset) do
        t=tblConnections[verticalPlank.index]
		if t==nil then
		  t={}
		  tblConnections[verticalPlank.index]=t
		end
		t[#t+1]=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
        t=tblConnections[verticalPlank.index]
		if t==nil then
		  t={}
		  tblConnections[verticalPlank.index]=t
		end
		t[#t+1]=plankId
      end
    end
  end

  for k,v in pairs(tblConnections) do
    local operatorId
	local operatorIds="#"
	for i, operatorId in ipairs(v) do
	  if i>1 then
	    operatorIds = operatorIds .. ","
	  end
	  operatorIds=string.format("%s%d", operatorIds, operatorId)
	end
	
    operations=string.format(
        "%s" ..
        "  <jointo target=\"#%d\" operator=\"%s\">\n" ..
        "    <cut endshape=\"angleddelfirst\"></cut>\n" ..
        "  </jointo>\n",
        operations, k, operatorIds)
  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
	
	
	-- Localized strings BEG
	local strTitle = "Double top/bottom materials"
  local strNoChange = "No change/Same as the top or bottom"
	local strMatOrg = "Material original"
	local strMatDouble = "Material double"
	local strDistOrg = "Distance from front original"
	local strDistDouble = "Distance from front double"
	local strLayerOrg = "Change layer name for original if doubled"
	local strWubOrgEbt = "Wup cnc: Mark original as EBT"
	local strOrgCnc = "Saw cnc: Include original in cnc-file"
	local strApplyAngled = "Apply to angled beams"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Tuplaylä/alajuoksun asetukset"
    strNoChange = "Ei muutosta/sama kuin ylä tai ala"
	  strMatOrg = "Materiaali alkuperäinen"
	  strMatDouble = "Materiaali tuplattu"
	  strDistOrg = "Etäisyys edestä alkuperäinen"
	  strDistDouble = "Etäisyys edestä tuplattu"
	  strLayerOrg = "Vaihda alkuperäisen kuvataso, jos tuplataan"
	  strWubOrgEbt = "Wup cnc: Merkitse alkuperäinen EBT"
	  strOrgCnc = "Kapulat cnc: Alkuperäinen cnc-tiedostoon"
	  strApplyAngled = "Käsittele myös vinot juoksut"
  elseif s=="kor" then
	  strTitle = "더블 탑/바텀 소재"
    strNoChange = "변경 사항 없음/탑 또는 바텀과 같음"
	  strMatOrg = "소재 오리지널"
	  strMatDouble = "소재 더블"
	  strDistOrg = "전면 원본으로부터의 거리"
	  strDistDouble = "전면 더블로부터의 거리"
	  strLayerOrg = "더블 적용시 원본의 레이어 이름 변경 "
	  strWubOrgEbt = "Wup cnc: 원본을 EBT로 마킹"
	  strOrgCnc = "Saw cnc: 원본을 cnc 파일에 포함"
	  strApplyAngled = "각진 빔에 적용"
  elseif s=="pol" then
    strTitle = "Materiał zdwojonej góry/dołu"
    strNoChange = "Bez zmian/Takie same jak górne lub dolne"
    strMatOrg = "Materiał oryginalny"
    strMatDouble = "Materiał zdwojony"
    strDistOrg = "Odległość od przedniej krawędzi oryginalnego"
    strDistDouble = "Odległość od przedniej krawędzi zdwojonego"
    strLayerOrg = "Zmień nazwę warstwy dla oryginalnego, jeśli zdwojony"
    strWubOrgEbt = "Wup cnc: Oznacz oryginalny jako EBT"
    strOrgCnc = "Saw cnc: Uwzględnij oryginalny w pliku cnc"
    strApplyAngled = "Zastosuj do belek ukośnych"
	end
	-- Localized strings END

  tblMat=af_request("matlist")
  s=""
  strSep=""

  tblSorted={}

  tblSorted[1]={}
  tblSorted[1].name=strNoChange
  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 =strMatOrg
  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 =strMatDouble
  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 =strDistOrg
  tblSettings[3].key    ="distorg"

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type   =3
  tblSettings[4].prompt =strDistDouble
  tblSettings[4].key    ="distdouble"

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type   =4
  tblSettings[5].prompt =strLayerOrg
  tblSettings[5].key    ="orglayer"

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type   =2
  tblSettings[6].prompt =strWubOrgEbt
  tblSettings[6].key    ="orgebt"

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type   =2
  tblSettings[7].prompt =strOrgCnc
  tblSettings[7].defvalue = 1
  tblSettings[7].key    ="orgcnc"

  tblSettings[8]          = {}
  tblSettings[8].cfgonly  = 0
  tblSettings[8].type     = 2
  tblSettings[8].prompt   = strApplyAngled
  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", strTitle, 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
    
	-- Localized strings BEG
	local strTitle = "Split bottom settings"
	local strMatFront = "Material front"
	local strMatBack = "Material back"
	local strRotFront = "Rotate front 90 deg"
	local strRotBack = "Rotate back 90 deg"
	
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Kahden kappaleen alajuoksun asetukset"
	  strMatFront = "Materiaali etu"
	  strMatBack = "Materiaali taka"
	  strRotFront = "Kierrä etu 90 astetta"
	  strRotBack = "Kierrä taka 90 astetta"
  elseif s=="kor" then
	  strTitle = "스플릿 바텀 설정"
	  strMatFront = "소재 전면"
	  strMatBack = "소재 후면"
	  strRotFront = "전면 회전 90도"
	  strRotBack = "후면 회전 90도"
  elseif s=="pol" then
    strTitle = "Ustawienia podzielonego dołu"
    strMatFront = "Materiał przodu"
    strMatBack = "Materiał tyłu"
    strRotFront = "Obróć przód o 90 stopni"
    strRotBack = "Obróć tył o 90 stopni"
	end
	-- Localized strings END

  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	=strMatFront
	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	=strMatBack
	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	=strRotFront
  tblSettings[3].key		="rotfront"
  tblSettings[3].defvalue	=0

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=2
  tblSettings[4].prompt	=strRotBack
  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", strTitle, 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

g_newz1 = 0     -- Z-offsets in element's watching direction of the new planks to be added
g_newz2 = 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 tblSortedMaterials, strMaterials = GetSortedMaterials()
	
	-- Localized strings BEG
	local strTitle = "Board edge support"
  local strPartsToAdjust = "Parts to adjust"
  local strPartsToAdjustVal = "\"1:Grooves to studs\",\"2:Cut board edge support piece between studs\""
	local strMat = "Material"
  local strMaterialRotation = "Material rotation"
  local strRotationVal = "\"1:0 degrees\",\"2:90 degrees\""
  local strFramingRotAngle = "Framing rotation"
  local strSpacingStart = "Spacing rule start"
  local strSpacingStartVal = "\"1:Top\",\"2:Bottom\""
	local strSpacigStartOff = "Spacing start offset"
  local strSpacingRule = "Spacing rule"
  local strSpacingRuleVal = "\"1:Fixed spacing\",\"2:Override\",\"3:Automatic\""
	local strFixedSpacingVal = "Fixed spacing value"
	local strTop = "Add to top"
	local strBot = "Add to bottom"
	local strOverTop = "Oversize top"
	local strOverBot = "Oversize bottom"
	local strOverBehind = "Oversize behind"
	local strOverEnd = "Oversize ends"
	local strSpacingOverride = "Spacing override #%d"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Levyn sauman tuki"
    strPartsToAdjust = "Tuen liittyminen tolppiin/palkkeihin"
    strPartsToAdjustVal = "\"1:Luo urat\",\"2:Katko tuet tukirakenteiden väliin\""
	  strMat = "Materiaali"
    strMaterialRotation = "Materiaalin kierto"
    strRotationVal = "\"1:0 astetta\",\"2:90 astetta\""
    strFramingRotAngle = "Rungon kapuloinnin kierto"
    strSpacingStart = "Välistysäännön alkupaikka"
    strSpacingStartVal = "\"1:Ylhäältä\",\"2:Alhaalta\""
	  strSpacigStartOff = "Ensimmäisen tuen paikka alkupaikasta"
    strSpacingRule = "Välistyssääntö"
    strSpacingRuleVal = "\"1:Vakiovälistys\",\"2:Annettuihin paikkoihin\",\"3:Automaattinen\""
	  strFixedSpacingVal = "Välistys"
	  strTop = "Lisää ylös"
	  strBot = "Lisää alas"
	  strOverTop = "Asennusvara ylä"
	  strOverBot = "Asennusvara ala"
	  strOverBehind = "Asennusvara takana"
	  strOverEnd = "Asennusvara päät"
	  strSpacingOverride = "Annettu paikka #%d"
  elseif s=="kor" then
	  strTitle = "보드 가장자리 지지"
    strPartsToAdjust = "조정할 부분들"
    strPartsToAdjustVal = "\"1:스터드에 홈\",\"2:스터드 사이 보드 가장자리 지지 피스 절단\""
	  strMat = "소재"
    strMaterialRotation = "소재 회전"
    strRotationVal = "\"1:0도\",\"2:90도\""
    strFramingRotAngle = "프레이밍 회전"
    strSpacingStart = "간격 규칙 시작"
    strSpacingStartVal = "\"1:상단\",\"2:하단\""
	  strSpacigStartOff = "간격 시작 오프셋"
    strSpacingRule = "간격 규칙"
    strSpacingRuleVal = "\"1:고정 간격\",\"2:우선 적용\",\"3:자동\""
	  strFixedSpacingVal = "고정 간격 값"
	  strTop = "상단에 추가"
	  strBot = "하단에 추가"
	  strOverTop = "오버사이즈 상단"
	  strOverBot = "오버사이즈 하단"
	  strOverBehind = "오버사이즈 후면"
	  strOverEnd = "오버사이즈 끝부분"
	  strSpacingOverride = "간격 우선 적용 #%d"
  elseif s=="pol" then
    strTitle = "Wsparcie krawędzi płyt"
    strPartsToAdjust = "Dostosowanie wsparcia do słupków/belek"
    strPartsToAdjustVal = "\"1:Wcięcia w słupkach\",\"2:Przytnij element wsparcia krawędzi płyty między słupkami\""
    strMat = "Materiał"
    strMaterialRotation = "Obrót Materiału"
    strRotationVal = "\"1:0 stopni\",\"2:90 stopni\""
    strFramingRotAngle = "Obrót elementów ramy"
    strSpacingStart = "Punkt początkowy dla zasady odstępów"
    strSpacingStartVal = "\"1:Od góry\",\"2:Od dołu\""
    strSpacigStartOff = "Pozycja pierwszego wsparcia od punktu początkowego"
    strSpacingRule = "Zasada odstępów"
    strSpacingRuleVal = "\"1:Stałe odstępy\",\"2:Według podanych pozycji\",\"3:Automatyczne\""
    strFixedSpacingVal = "Wartość stałego odstępu"
    strTop = "Dodaj na górze"
    strBot = "Dodaj na dole"
    strOverTop = "Nadwyżka na górze"
    strOverBot = "Nadwyżka na dole"
    strOverBehind = "Nadwyżka z tyłu"
    strOverEnd = "Nadwyżka na końcach"
    strSpacingOverride = "Nadpisanie odstępu #%d"
	end
	-- Localized strings END

  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


  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     = strMat
  tblSettings[idx].key        = "material"
  tblSettings[idx].valuelist  = strMaterials
  tblSettings[idx].defvalue   = defaultMaterial
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 1
  tblSettings[idx].prompt     = strMaterialRotation
  tblSettings[idx].key        = "materialRotation"
  tblSettings[idx].valuelist  = strRotationVal
  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

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 1
  tblSettings[idx].prompt     = strFramingRotAngle
  tblSettings[idx].key        = "framingRotAngle"
  tblSettings[idx].valuelist  = strRotationVal
  tblSettings[idx].defvalue   =  1
  idx = idx + 1

  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     = strSpacigStartOff
  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     = strFixedSpacingVal
  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     = strTop
  tblSettings[idx].key        = "addToTop"
  tblSettings[idx].defvalue   = 0
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 2
  tblSettings[idx].prompt     = strBot
  tblSettings[idx].key        = "addToBottom"
  tblSettings[idx].defvalue   = 0
  idx = idx + 1

  tblSettings[idx]            = {}
  tblSettings[idx].cfgonly    = 0
  tblSettings[idx].type       = 3 
  tblSettings[idx].prompt     = strOverTop
  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     = strOverBot
  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     = strOverBehind
  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     = strOverEnd
  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(strSpacingOverride, 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", strTitle, 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 ***


-- Removes parts of lv having a parallel piece in tblFraming. Marks removed parts to seg
-- Returns new seg
function RemoveAlreadySupported(tblFraming, seg, lv)
  local k, v, dx, dy
  local off, dist1, len, dist2
	
	dx = lv.c2.x - lv.c1.x
	dy = lv.c2.y - lv.c1.y
	len = math.sqrt(dx * dx + dy * dy)
	if len<EPS then
	  return seg
	end
	dx = dx / len
	dy = dy / len
	
  for k,v in ipairs(tblFraming) do
	  -- Check if new plank would be intersecting in z-dir with existing one
	  -- cos 1 deg=0.99984769515639123915701155881391

	  if math.abs(dx * v.dx + dy * v.dy) > 0.999 then
--ac_environment("tolog", "POLY")
--DumpTbl(v.elemdata.poly)
      local clipLines = ac_geo("linepolyx", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v.elemdata.polys, false, false)
		
		  if clipLines then
			
--ac_environment("tolog", string.format("g_newz1=%f g_newz2=%f, v.elemdata.bz1=%f, v.elemdata.bz2=%f, v.elemdata.x1=%f v.elemdata.y1=%f v.elemdata.x2=%f v.elemdata.y2=%f", g_newz1, g_newz2, v.elemdata.bz1, v.elemdata.bz2, v.elemdata.x1, v.elemdata.y1, v.elemdata.x2, v.elemdata.y2))
        if g_newz2 - EPS > v.elemdata.bz1 and g_newz1 + EPS < v.elemdata.bz2 then
		      local k2, v2
			
			    for k2,v2 in ipairs(clipLines) do
				
			      off, dist1, len = ac_geo ("linedist", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v2.x1, v2.y1)
			      off, dist2, len = ac_geo ("linedist", lv.c1.x, lv.c1.y, lv.c2.x, lv.c2.y, v2.x2, v2.y2)
				
				    if dist1>dist2 then
				      dist1,dist2 = dist2,dist1
				    end

				    seg = SegDifference(seg, dist1, dist2)

--ac_environment("tolog", string.format("Removed: d1=%f d2=%f, #seg=%d", dist1, dist2, #seg))
			    end
				end
		  end
		end
  end
	
	return seg
end


-- Adds parts of lv not intersecting with elemLines to target polyLines
-- 12/2024: Added tblFraming that contais all framing pieces: Also remove any piece that has a plank behind
function AddNoEdgeX(elemLines, tblFraming, 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
	
	if #seg>0 then
  	seg = RemoveAlreadySupported(tblFraming, seg, lv)
	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)
  -- Make polygons of each framing piece to filter out lines that already have a piece behind
  local i, tblFraming, t, len

  tblFraming={}
  for i=1, gnPlanks do
    ac_objectopen(string.format("#%d", i))
		  t = {}
			t.info = af_request("plankinfo")
			t.elemdata = ac_objectget("#af_elemdata")
      -- tblElemPlankMat = af_request("singlemat", info.matname)
    ac_objectclose()

  	t.dx = t.elemdata.x2 - t.elemdata.x1
  	t.dy = t.elemdata.y2 - t.elemdata.y1
		len = math.sqrt(t.dx*t.dx + t.dy*t.dy)
		if len>EPS then
		  t.dx = t.dx / len
		  t.dy = t.dy / len
			t.elemdata.polys = {}
			t.elemdata.polys[1] = t.elemdata.poly     -- Needs polygon list, build it ready
  		tblFraming[#tblFraming+1] = t
		end
  end


  -- 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, tblFraming, 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

  -- zoff moves the piece on the horizontal plane (from the front toward the back)
  local zoff = 0.0
  local infoElem = af_request("plankinfo", gGuidElem)
  local materialThickness = tblMaterial.thickness
  local materialHeight    = tblMaterial.height
	
	g_newz1 = 0
	g_newz2 = materialHeight
	
  if g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_0 then
    zoff = infoElem.width - materialHeight
	  g_newz1 = zoff
	  g_newz2 = infoElem.width
  elseif g_side == SIDE_BACK and g_materialRotation == MATERIAL_ROTATION_90 then
    zoff = infoElem.width - (materialThickness * 0.5)
	  g_newz1 = infoElem.width - materialThickness
	  g_newz2 = infoElem.width
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_0 then
    zoff = 0.0
	  g_newz2 = materialHeight
  elseif g_side == SIDE_FRONT and g_materialRotation == MATERIAL_ROTATION_90 then
    zoff = 0.5 * materialThickness
	  g_newz2 = materialThickness
  end

  --
  -- Calculations
  --
  local materialId        = tblMaterial.id
  local tblRot, tblInvRot = GetRotationMatrices()
  local tblElemPoly = GetElemPoly(gGuidElem)
  local tblElemPolyWithHoles = GetElemPoly(gGuidElem, true)

  -- 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

  --
  -- 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
    
	-- Localized strings BEG
	local strTitle = "Top balk settings"
	local strMat = "Material"
	local strThickness = "Thickness if not fixed"
	local strHeight = "Height if not fixed"
	local strDistTop = "Balk distance from element top (top wood thickness)"
	local strNumPlanks = "Number of planks to add"
	local strOverBelow = "Oversize below the beam"
	local strOverAbove = "Oversize above the beam"
	local strOverSide = "Oversize at the side of the beam"
	local strDistStud = "Beam distance from stud surface"
	
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Yläpalkin asetukset"
	  strMat = "Materiaali"
	  strThickness = "Paksuus jos ei vakio"
	  strHeight = "Korkeus jos ei vakio"
	  strDistTop = "Palkin et. element yläreunasta (yläjuoksun paksuus)"
	  strNumPlanks = "Lisättävien palkkien lukumäärä"
	  strOverBelow = "Asennusvara palkin alla"
	  strOverAbove = "Asennusvara palkin päällä"
	  strOverSide = "Asennusvara palkin sivuilla"
	  strDistStud = "Palkim et. tolpan pinnasta"
  elseif s=="kor" then
	  strTitle = "상단 보크 설정"
	  strMat = "소재"
	  strThickness = "고정되지 않았을 경우 두께"
	  strHeight = "고정되지 않았을 경우 높이"
	  strDistTop = "요소 상단으로부터의 보크 거리 (상단 목재 두께)"
	  strNumPlanks = "추가할 골조의 수"
	  strOverBelow = "빔 아래 오버사이즈"
	  strOverAbove = "빔 위 오버사이즈"
	  strOverSide = "빔 측면 오버사이즈"
	  strDistStud = "스터드 표면으로부터의 빔 거리"
  elseif s=="pol" then
    strTitle = "Ustawienia górnej belki"
    strMat = "Materiał"
    strThickness = "Grubość, jeśli niestandardowa"
    strHeight = "Wysokość, jeśli niestandardowa"
    strDistTop = "Odległość belki od górnej krawędzi elementu (grubość górnej belki)"
    strNumPlanks = "Liczba belek do dodania"
    strOverBelow = "Nadwyżka pod belką"
    strOverAbove = "Nadwyżka nad belką"
    strOverSide = "Nadwyżka po bokach belki"
    strDistStud = "Odległość belki od powierzchni słupka"
	end
	-- Localized strings END
    
  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	=strMat
	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	=strThickness
	tblSettings[2].key		="thickness"
	tblSettings[2].defvalue	=0.050

	tblSettings[3]			={}
	tblSettings[3].cfgonly	=0
	tblSettings[3].type		=3
	tblSettings[3].prompt	=strHeight
	tblSettings[3].key		="height"
	tblSettings[3].defvalue	=0.100

	tblSettings[4]			={}
	tblSettings[4].cfgonly	=0
	tblSettings[4].type		=3
	tblSettings[4].prompt	=strDistTop
	tblSettings[4].key		="topoff"
	tblSettings[4].defvalue	=0.041
  
	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	=strNumPlanks
	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	=strOverBelow
	tblSettings[6].key		="overbelow"
	tblSettings[6].defvalue	=0

	tblSettings[7]			={}
	tblSettings[7].cfgonly	=0
	tblSettings[7].type		=3
	tblSettings[7].prompt	=strOverAbove
	tblSettings[7].key		="overabove"
	tblSettings[7].defvalue	=0

	tblSettings[8]			={}
	tblSettings[8].cfgonly	=0
	tblSettings[8].type		=3
	tblSettings[8].prompt	=strOverSide
	tblSettings[8].key		="overinside"
	tblSettings[8].defvalue	=0

	tblSettings[9]			={}
	tblSettings[9].cfgonly	=0
	tblSettings[9].type		=3
	tblSettings[9].prompt	=strDistStud
	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", strTitle, 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 = {}

EROTATION_VERTICAL  = 1
EROTATION_HORIZONTAL = 2

-- 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_rotation, rotation of the beam, vertical (default) or horizontal
-- 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 strBeamRotation = "Beam rotation"
  local strBeamRotationVal = "\"1:Vertical\",\"2:Horizontal\""
	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"
    strBeamRotation = "Palkkien kiertokulma"
    strBeamRotationVal = "\"1:Vertical\",\"2:Horizontal\""
		strTitle="Välipohjaliitoksen asetukset"
	elseif s=="kor" then
	  strTopMat="탑 플레이트 소재 ID"
    strTopNoChange="변경사항 없음- 원본 유지"
	  strSide="조인트 측면"
	  strSideVal="\"1:전면\",\"2:후면\""
	  strDepth="슬롯 깊이"
	  strHeight="슬롯 높이"
	  strBotThick="하단 수평 OSB 두께"
	  strBotOversize=" 하단 수평 OSB 오버사이즈 내부"
	  strVertThick="수직 OSB 두께 (0=없음)"
	  strVertHeight="수직 OSB 높이 (0=디폴트)"
	  strBeamMat="지지대 소재"
	  strBlockThick="고정되지 않았을 경우 두께"
	  strBlockHeight="고정되지 않았을 경우 높이"
	  strNumBeams="추가할 빔의 수"
	  strOverBelow="빔 아래 오버사이즈"
	  strOverSide="빔 측면 오버사이즈"
	  strBeamFromSurf="스터드 표면으로부터의 빔 거리"
    strBeamRotation = "빔 회전"
    strBeamRotationVal = "\"1:수직\",\"2:수평\""
	  strTitle="바닥 조인트 설정"
  elseif s=="pol" then
    strTopMat="ID materiału górnej płyty"
    strTopNoChange="Bez zmian - zachowaj oryginał"
    strSide="Strona złącza"
    strSideVal="\"1:Przód\",\"2:Tył\""
    strDepth="Głębokość wrębu"
    strHeight="Wysokość wrębu"
    strBotThick="Grubość dolnej poziomej płyty OSB"
    strBotOversize="Nadwyżka dolnej poziomej płyty OSB wewnątrz"
    strVertThick="Grubość pionowej płyty OSB (0=brak)"
    strVertHeight="Wysokość pionowej płyty OSB (0=domyślna)"
    strBeamMat="Materiał belki wspierającej"
    strBlockThick="Grubość belki, jeśli niestandardowa"
    strBlockHeight="Wysokość belki, jeśli niestandardowa"
    strNumBeams="Liczba belek do dodania"
    strOverBelow="Nadwyżka pod belką"
    strOverSide="Nadwyżka po bokach belki"
    strBeamFromSurf="Odległość belki od powierzchni słupka"
    strBeamRotation = "Obrót belki"
    strBeamRotationVal = "\"1:Pionowy\",\"2:Poziomy\""
    strTitle="Ustawienia połączenia ze stropem"
	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"

  tblSettings[16]         = {}
  tblSettings[16].cfgonly = 0
  tblSettings[16].type    = 1
  tblSettings[16].prompt  = strBeamRotation
  tblSettings[16].key     = "rotation"
  tblSettings[16].valuelist = strBeamRotationVal

  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
  tblSettings[16].value=g_rotation

  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

  g_rotation=tblSettings[16].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
-- rotation   Beam rotation vertical or horizontal
-- 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, rotation )
  local i, v, tblNew, nx, ny, len, dist, lastContour, i2, edgeNew, edgeOp, x, y, nPlank, height, 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

  height=tblMat.height
  if nMatHeight then
    if nMatHeight>0 then
      height=nMatHeight
    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

--ac_environment("tolog", string.format("g_side=%f, tblNew.zoff=%f, nZoff=%f", g_side, tblNew.zoff, nZoff))
          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

          if rotation==EROTATION_VERTICAL then
            tblNew.rotangle=90
            if g_side==2 then
              tblNew.zoff=tblNew.zoff-(nPlank-1)*thickness-distSurf
            else
              tblNew.zoff=tblNew.zoff+(nPlank-1)*thickness+distSurf
            end
          elseif rotation==EROTATION_HORIZONTAL then
            tblNew.rotangle=180
            if g_side==2 then
              tblNew.zoff=tblNew.zoff+thickness*0.5-distSurf
            else 
              tblNew.zoff=tblNew.zoff-thickness*0.5+height+distSurf
            end
            --ac_environment("tolog", dump(loopmax-nPlank))
            tblNew.y1=tblNew.y1-(loopmax-nPlank)*thickness-thickness*0.5
            tblNew.y2=tblNew.y2-(loopmax-nPlank)*thickness-thickness*0.5
          end
          -- 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

            if g_botThickness>0.0001 then
              tblPlywoods[#tblPlywoods+1]=tblNew
            end

            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.isbot=false
              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 )
    else
      local overL=0.0
      local overR=g_slotHeight-g_botThickness+1
      if g_side==2 then
        overL, overR=overR, overL
      end
      strXmlOp=string.format(
        "%s" ..
        "<groove target=\"vertical_y*|vertical_spacing|vertical_force\" operator=\"#%d\">\n" ..
        "  <groove overtop=\"0\" overbot=\"0\" overleft=\"%.5f\" overright=\"%.5f\" overlen=\"0.1\"></groove>\n" ..
        "</groove>\n",
        strXmlOp, gnPlanks+gnPlankCount, overL, overR)
    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\nrotation=%d", 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, g_rotation)
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  

  g_rotation=EROTATION_VERTICAL
  val = GetVal(sSettings, "rotation")
  if val then
    g_rotation=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
  g_rotation=EROTATION_VERTICAL
  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, g_rotation )
--ac_environment("tolog", string.format("res=%s", res))
  if gxmlOperations==nil then
    gxmlOperations=""
  end

  s=""
  -- Single groove for the deepest plank

  local overT=g_overBelow
  local overB=g_slotHeight
  local overR=thickness*(g_numPlanks-1)+g_distSurf+0.001
  local overL=g_overInside

  if g_rotation==EROTATION_VERTICAL and g_side==1 then
    overL, overR=overR, overL
  elseif g_rotation==EROTATION_HORIZONTAL then
    overL=g_slotHeight
    overR=thickness*(g_numPlanks-1)+0.001+g_overBelow
    overT=g_overInside
    overB=g_distSurf
    if g_side==1 then
      overT, overB=overB, overT
    end
  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, overT, overB, 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")
  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)
    elseif lang=="pol" then
      bot2=bot2 .. string.format("<opening line=\"0\" windowtext=\"Okno [width]x[height]\" doortext=\"Drzwi [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

	-- Localized strings BEG
  local strTitle = "Markings settings"
  local strLinesBot = "Lines bottom"
	local strStudIdBot = "Stud ID bottom"
	local strLinesTop = "Lines top"
	local strStudIdTop = "Stud ID top"
	local strStudIdBotPlace = "Stud ID bottom placement"
	local strStudIdTopPlace = "Stud ID top placement"
	local strIdPlace = "\"1:1 Left\",\"2:2 Right\",\"3:3 Calculate position not to be under any stud\",\"4:4 To center of the stud\""
	local strMarkOpening = "Mark opening pieces"
	local strMarkOpeningBot = "Mark openings to bottom"
	local strMarkNeigBot = "Mark neighbours to bottom"
	local strForceTop = "Force side top"
	local strValSide = "\"1:1 Automatic\",\"2:2 Top\",\"3:3 Front\",\"4:4 Bottom\",\"5:5 Back\""
	local strForceBot = "Force side bottom, opening and connecting"
	local strMarkConn = "Mark connecting pieces"
	local strMarkText = "Mark text size"
	
	
	s=af_request("aflang")
  if s=="fin" then
    strTitle = "Merkinnät asetukset"
    strLinesBot = "Viivat alas"
	  strStudIdBot = "Tolppien ID:t alas"
	  strLinesTop = "Viivat ylös"
	  strStudIdTop = "Tolppien ID:t ylös"
	  strStudIdBotPlace = "Tolppien ID ala paikka"
	  strStudIdTopPlace = "Tolppien ID ylä paikka"
	  strIdPlace = "\"1:1 Vasen\",\"2:2 Oikea\",\"3:3 Laske paikka, joka ei jää tolpan alle\",\"4:4 Keskelle tolppaa\""
	  strMarkOpening = "Merkitse aukkojen kappaleet"
	  strMarkOpeningBot = "Merkitse aukot alajuoksuun"
	  strMarkNeigBot = "Merkitse naapurielementit alajuoksuun"
	  strForceTop = "Pakota puoli ylä"
	  strValSide = "\"1:1 Automaattinen\",\"2:2 Ylä\",\"3:3 Etu\",\"4:4 Ala\",\"5:5 Taka\""
	  strForceBot = "Pakota puoli alajuoksi, aukot ja naapurit"
	  strMarkConn = "Merkitse jatkokset"
	  strMarkText = "Merkintätekstin koko"
  elseif s=="kor" then
    strTitle = "마킹 설정"
    strLinesBot = "선 하단"
	  strStudIdBot = "스터드 ID 하단"
	  strLinesTop = "선 상단"
	  strStudIdTop = "스터드 ID 상단"
	  strStudIdBotPlace = "스터드 ID 하단 배치"
	  strStudIdTopPlace = "스터드 ID 상단 배치"
	  strIdPlace = "\"1:1 좌\",\"2:2 우\",\"3:3 스터드 아래가 아닌 위치 계산\",\"4:4 스터드 중앙\""
	  strMarkOpening = "개구부 피스 마킹"
	  strMarkOpeningBot = "하단에 개구부 마킹"
	  strMarkNeigBot = "하단 근접에 마킹"
	  strForceTop = "측면 상단 강제 적용"
	  strValSide = "\"1:1 자동\",\"2:2 상단\",\"3:3 전면\",\"4:4 하단\",\"5:5 후면\""
	  strForceBot = "측면 하단 강제 적용, 개구부 및 연결부"
	  strMarkConn = "연결 피스 마킹"
	  strMarkText = "텍스트 사이즈 마킹"
  elseif s=="pol" then
    strTitle = "Ustawienia oznaczeń"
    strLinesBot = "Linie na dole"
    strStudIdBot = "ID słupków na dole"
    strLinesTop = "Linie na górze"
    strStudIdTop = "ID słupków na górze"
    strStudIdBotPlace = "Umiejscowienie ID słupków na dole"
    strStudIdTopPlace = "Umiejscowienie ID słupków na górze"
    strIdPlace = "\"1:1 Lewa\",\"2:2 Prawa\",\"3:3 Oblicz pozycję, aby nie była pod słupkiem\",\"4:4 Na środku słupka\""
    strMarkOpening = "Oznacz elementy otworów"
    strMarkOpeningBot = "Oznacz otwory na dolnej belce"
    strMarkNeigBot = "Oznacz sąsiednie elementy na dolnej belce"
    strForceTop = "Wymuś stronę górną"
    strValSide = "\"1:1 Automatyczna\",\"2:2 Górna\",\"3:3 Przednia\",\"4:4 Dolna\",\"5:5 Tylna\""
    strForceBot = "Wymuś stronę dolną, otwory i połączenia"
    strMarkConn = "Oznacz elementy połączeń"
    strMarkText = "Rozmiar tekstu oznaczeń"
	end
	-- Localized strings END

  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type   =2
  tblSettings[1].prompt =strLinesBot
  tblSettings[1].key    ="bottomlines"
  tblSettings[1].defvalue  =1

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type   =2
  tblSettings[2].prompt =strStudIdBot
  tblSettings[2].key    ="bottomstudids"
  tblSettings[2].defvalue  =0

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type   =2
  tblSettings[3].prompt =strLinesTop
  tblSettings[3].key    ="toplines"
  tblSettings[3].defvalue  =1

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type   =2
  tblSettings[4].prompt =strStudIdTop
  tblSettings[4].key    ="topstudids"
  tblSettings[4].defvalue  =0

	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	=strStudIdBotPlace
	tblSettings[5].key		="numplanks"
	tblSettings[5].valuelist=strIdPlace
	tblSettings[5].defvalue	=3

	tblSettings[6]			={}
	tblSettings[6].cfgonly	=0
	tblSettings[6].type		=1
	tblSettings[6].prompt	=strStudIdTopPlace
	tblSettings[6].key		="numplanks"
	tblSettings[6].valuelist=strIdPlace
	tblSettings[6].defvalue	=3

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type   =2
  tblSettings[7].prompt =strMarkOpening
  tblSettings[7].key    ="openplanks"
  tblSettings[7].defvalue  =0

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type   =2
  tblSettings[8].prompt =strMarkOpeningBot
  tblSettings[8].key    ="openings"
  tblSettings[8].defvalue  =0

  tblSettings[9]      ={}
  tblSettings[9].cfgonly  =0
  tblSettings[9].type   =2
  tblSettings[9].prompt =strMarkNeigBot
  tblSettings[9].key    ="neig"
  tblSettings[9].defvalue  =0
  
	tblSettings[10]			={}
	tblSettings[10].cfgonly	=0
	tblSettings[10].type		=1
	tblSettings[10].prompt	=strForceTop
	tblSettings[10].key		="topside"
	tblSettings[10].valuelist=strValSide
	tblSettings[10].defvalue	=1
  
	tblSettings[11]			={}
	tblSettings[11].cfgonly	=0
	tblSettings[11].type		=1
	tblSettings[11].prompt	=strForceBot
	tblSettings[11].key		="botside"
	tblSettings[11].valuelist=strValSide
	tblSettings[11].defvalue	=1

  tblSettings[12]      ={}
  tblSettings[12].cfgonly  =1
  tblSettings[12].type   =2
  tblSettings[12].prompt =strMarkConn
  tblSettings[12].key    ="connbot"
  tblSettings[12].defvalue  =0

  tblSettings[13]      ={}
  tblSettings[13].cfgonly  =1
  tblSettings[13].type   =3
  tblSettings[13].prompt =strMarkText
  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", strTitle, 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), openinghor_gro: For Space Factory having horizontal piece under the lintels
    xmlOp=xmlOp ..
    "<jointo target=\"vertical_y*|vertical_spacing*|vertical_force\" operator=\"vertical_x|openinghor_gro*" .. 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|openinghor_gro*" .. 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|openinghor_gro*|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|openinghor_gro*|contourtilted_opening|nogging\">\n"

    -- 10/2024: Changed mindisttoend=\"0.025\" to mindisttoend=\"0.010\" to support SF 38 mm studs (not sure why this condition was there=
    xmlOp = xmlOp .. string.format("<groove overtop=\"%.4f\" overbot=\"%.4f\" overside=\"%.4f\" forcedepth=\"%.4f\" force90=\"1\" conntype=\"linex\" mindisttoend=\"0.010\"></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" or string.match(s, "^openinghor_gro.*"))        -- 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|openinghor_gro*\">\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|openinghor_gro*\">\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|openinghor_gro*|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
	
	-- Localized strings BEG
	local strTitle = "Markings settings"
	local strGroDepth = "Grooves depth"
	local strGroOverTopBot = "Grooves oversize top&bottom"
	local strGroOverSides = "Grooves oversize sides"
	local strGroTop = "Grooves to top"
	local strGroBot = "Grooves to bottom"
	local strGroOpeningSides = "Grooves to opening pieces"
	local strNoggingsGap = "Noggings gap"
	local strGroToFloor = "Grooves to floors also"
	local strStraightStud = "Straight stud ends when connecting to angled parts"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Merkintäurat asetukset"
	  strGroDepth = "Urien syvyys"
	  strGroOverTopBot = "Urien asennusvara ylä ja ala"
	  strGroOverSides = "Urien asennusvara sivut"
	  strGroTop = "Urat yläjuoksuun"
	  strGroBot = "Urat alajuoksuun"
	  strGroOpeningSides = "Urat aukkojen kappaleisiin"
	  strNoggingsGap = "Nurjahduksenestokapuloiden asennusvara"
	  strGroToFloor = "Urat myös lattioihin"
	  strStraightStud = "Suorat tolppien päät vinon juoksun liitoksessa"
  elseif s=="kor" then
	  strTitle = "마킹 설정"
	  strGroDepth = "홈 깊이"
	  strGroOverTopBot = "홈 오버사이즈 상단&하단"
	  strGroOverSides = "홈 오버사이즈 측면"
	  strGroTop = "상단에 홈"
	  strGroBot = "하단에 홈"
	  strGroOpeningSides = "개구부 피스에 홈"
	  strNoggingsGap = "블록킹 간격"
	  strGroToFloor = "바닥에도 홈"
	  strStraightStud = "각진 부분에 연결시 스터드 끝부분 스트레이트"
  elseif s=="pol" then
    strTitle = "Ustawienia oznaczeń wycięć"
    strGroDepth = "Głębokość wycięć"
    strGroOverTopBot = "Nadwyżka wycięć góra i dół"
    strGroOverSides = "Nadwyżka wycięć po bokach"
    strGroTop = "Wycięcia w górnej belce"
    strGroBot = "Wycięcia w dolnej belce"
    strGroOpeningSides = "Wycięcia w elementach otworów"
    strNoggingsGap = "Odstęp dla poprzeczek przeciw wyboczeniu"
    strGroToFloor = "Wycięcia również w podłogach"
    strStraightStud = "Proste końce słupków przy połączeniu z ukośnymi elementami"
	end
	-- Localized strings END
	
  tblSettings={}
  tblSettings[1]      ={}
  tblSettings[1].cfgonly  =0
  tblSettings[1].type    =3
  tblSettings[1].prompt  =strGroDepth
  tblSettings[1].key    ="grodepth"
  tblSettings[1].defvalue  =0.005

  tblSettings[2]      ={}
  tblSettings[2].cfgonly  =0
  tblSettings[2].type    =3
  tblSettings[2].prompt  =strGroOverTopBot
  tblSettings[2].key    ="gro_over"
  tblSettings[2].defvalue  =0.001

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  =strGroOverSides
  tblSettings[3].key    ="gro_oversides"
  tblSettings[3].defvalue  =0.001

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type    =2
  tblSettings[4].prompt  =strGroTop
  tblSettings[4].key    ="gro_top"
  tblSettings[4].defvalue  =1

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type    =2
  tblSettings[5].prompt  =strGroBot
  tblSettings[5].key    ="gro_bot"
  tblSettings[5].defvalue  =1

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type    =2
  tblSettings[6].prompt  =strGroOpeningSides
  tblSettings[6].key    ="gro_opening"
  tblSettings[6].defvalue  =1

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type    =3
  tblSettings[7].prompt  =strNoggingsGap
  tblSettings[7].key    ="nogging_gap"
  tblSettings[7].defvalue  =0

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type    =2
  tblSettings[8].prompt  =strGroToFloor
  tblSettings[8].key    ="gro_floor"
  tblSettings[8].defvalue  =0

  tblSettings[9] = {}
  tblSettings[9].cfgonly = 0
  tblSettings[9].type    = 2
  tblSettings[9].prompt  = strStraightStud
  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", strTitle, 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
	
	-- Localized strings BEG
	local strTitle = "Side planks settings"
	local strMaterial = "Material"
	local strThickness = "Thickness if not fixed"
	local strHeight = "Height if not fixed"
	
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Laudat aukkojen sivuilla asetukset"
	  strMaterial = "Materiaali"
	  strThickness = "Paksuus jos ei vakio"
	  strHeight = "Korkeus jos ei vakio"
  elseif s=="kor" then
	  strTitle = "측면 골조 설정"
	  strMaterial = "요소"
	  strThickness = "고정되지 않았을 경우 두께"
	  strHeight = "고정되지 않았을 경우 높이"
  elseif s=="pol" then
    strTitle = "Ustawienia belek bocznych"
    strMaterial = "Materiał"
    strThickness = "Grubość, jeśli niestandardowa"
    strHeight = "Wysokość, jeśli niestandardowa"
	end
	-- Localized strings END

  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	=strMaterial
	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	=strThickness
	tblSettings[2].key		="thickness"
	tblSettings[2].defvalue	=0.050

	tblSettings[3]			={}
	tblSettings[3].cfgonly	=0
	tblSettings[3].type		=3
	tblSettings[3].prompt	=strHeight
	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", strTitle, 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
    
	-- Localized strings BEG
	local strTitle = "Double stud settings"
	local strMinWidth = "Minimum width to add double stud"
	local strNoNails = "No nailings to added studs"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Double stud settings"
	  strMinWidth = "Aukon minimileveys, että lisätään tolpat"
	  strNoNails = "Ei naulauksia lisäyttyihin tolppiin"
  elseif s=="kor" then
	  strTitle = "더블 스터드 설정"
	  strMinWidth = "더블 스터드 추가할 최소 너비"
	  strNoNails = "추가한 스터드에 못박기 없음"
  elseif s=="pol" then
    strTitle = "Ustawienia zdwojonych słupków"
    strMinWidth = "Minimalna szerokość, aby dodać zdwojony słupek"
    strNoNails = "Brak gwoździowania do dodanych słupków"
	end
	-- Localized strings END

	tblSettings={}

	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=3
	tblSettings[1].prompt	=strMinWidth
	tblSettings[1].key		="width"
	tblSettings[1].defvalue	=0.600

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=2
	tblSettings[2].prompt	=strNoNails
	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", strTitle, 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
    

	-- Localized strings BEG
	local strTitle = "Reinforce settings"
	local strMat = "Material"
	local strDistStud = "Distance from stud end"
	local strOverStudEnd = "Oversize towards stud end"
	local strOverStudIn = "Oversize towards stud in"
	local strOverSides = "Oversize sides"
	local strTopBack = "Top back"
	local strTopFront = "Top front"
	local strBotBack = "Bottom back"
	local strBotFront = "Bottom front"
	
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Asetukset"
	  strMat = "Materiaali"
	  strDistStud = "Etäisyys toplan päästä"
	  strOverStudEnd = "Asennusvara tolpan pään suuntaan"
	  strOverStudIn = "Aennusvara tolpan sisäpintaan päin"
	  strOverSides = "Aennusvara sivut"
	  strTopBack = "Ylä taka"
	  strTopFront = "Ylä etu"
	  strBotBack = "Ala taka"
	  strBotFront = "Ala etu"
  elseif s=="kor" then
	  strTitle = "보강 설정"
	  strMat = "소재"
	  strDistStud = "스터드 끝에서부터의 거리"
	  strOverStudEnd = "스터드 끝 방향으로 오버사이즈"
	  strOverStudIn = "스터드 안쪽 방향으로 오버사이즈"
	  strOverSides = "측면 오버사이즈"
	  strTopBack = "상단 후면"
	  strTopFront = "상단 전면"
	  strBotBack = "하단 후면"
	  strBotFront = "하단 전면"
  elseif s=="pol" then
    strTitle = "Ustawienia wzmocnień"
    strMat = "Materiał"
    strDistStud = "Odległość od końca słupka"
    strOverStudEnd = "Nadwyżka w kierunku końca słupka"
    strOverStudIn = "Nadwyżka w kierunku wewnętrznej strony słupka"
    strOverSides = "Nadwyżka po bokach"
    strTopBack = "Góra tył"
    strTopFront = "Góra przód"
    strBotBack = "Dół tył"
    strBotFront = "Dół przód"
	end
	-- Localized strings END

  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  =strMat
  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	=strDistStud
  tblSettings[2].key		="distend"
  tblSettings[2].defvalue	=g_reinforceDist

    tblSettings[3]      ={}
    tblSettings[3].cfgonly  =0
  tblSettings[3].type		=3
  tblSettings[3].prompt	=strOverStudEnd
  tblSettings[3].key		="overout"
  tblSettings[3].defvalue	=g_reinforceOverEnd
  
    tblSettings[4]      ={}
    tblSettings[4].cfgonly  =0
  tblSettings[4].type		=3
  tblSettings[4].prompt	=strOverStudIn
  tblSettings[4].key		="overin"
  tblSettings[4].defvalue	=g_reinforceOverIn

    tblSettings[5]      ={}
    tblSettings[5].cfgonly  =0
  tblSettings[5].type		=3
  tblSettings[5].prompt	=strOverSides
  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  =strTopBack
    tblSettings[6].key    ="topin"
    tblSettings[6].defvalue  =1

    tblSettings[7]      ={}
    tblSettings[7].cfgonly  =0
    tblSettings[7].type    =2
    tblSettings[7].prompt  =strTopFront
    tblSettings[7].key    ="topout"
    tblSettings[7].defvalue  =1
  
    tblSettings[8]      ={}
    tblSettings[8].cfgonly  =0
    tblSettings[8].type    =2
    tblSettings[8].prompt  =strBotBack
    tblSettings[8].key    ="botin"
    tblSettings[8].defvalue  =1

    tblSettings[9]      ={}
    tblSettings[9].cfgonly  =0
    tblSettings[9].type    =2
    tblSettings[9].prompt  =strBotFront
    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", strTitle, 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
	
	-- Localized strings BEG
	local strTitle = "Angled cuts for doors and windows"
	local strHeight = "Height of the cut"
	local strDepth = "Depth of the cut"
	local strCutWinBot = "Cut window bottom"
	local strCutDoorBot = "Cut door bottom"
	local strTargetSurf = "Target surface"
	local strTopBot = "\"1:Top\",\"3:Bottom\""
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Viiste ikkunan/oven alla"
	  strHeight = "Viisteen korkeus"
	  strDepth = "Viisteen syvyys"
	  strCutWinBot = "Lisää ikkunan alareunaan"
	  strCutDoorBot = "Lisää oven alareunaan"
	  strTargetSurf = "Kohdepinta kapulassa"
	  strTopBot = "\"1:Ylä\",\"3:Ala\""
  elseif s=="kor" then
	  strTitle = "문 및 창문 각도 절단"
	  strHeight = "절단의 높이"
	  strDepth = "절단의 깊이"
	  strCutWinBot = "창문 하단 절단"
	  strCutDoorBot = "문 하단 절단"
	  strTargetSurf = "대상 	표면"
	  strTopBot = "\"1:상단\",\"3:하단\""
  elseif s=="pol" then
    strTitle = "Skośne cięcia dla drzwi i okien"
    strHeight = "Wysokość cięcia"
    strDepth = "Głębokość cięcia"
    strCutWinBot = "Dodaj do dolnej krawędzi okna"
    strCutDoorBot = "Dodaj do dolnej krawędzi drzwi"
    strTargetSurf = "Powierzchnia docelowa elementu"
    strTopBot = "\"1:Góra\",\"3:Dół\""
	end
	-- Localized strings END

  tblSettings={}
	tblSettings[1]			={}
	tblSettings[1].cfgonly	=0
	tblSettings[1].type		=3
	tblSettings[1].prompt	=strHeight
	tblSettings[1].key		="cutheight"
	tblSettings[1].defvalue	=0.025

	tblSettings[2]			={}
	tblSettings[2].cfgonly	=0
	tblSettings[2].type		=3
	tblSettings[2].prompt	=strDepth
	tblSettings[2].key		="cutdepth"
	tblSettings[2].defvalue	=0.040

  tblSettings[3]			={}
  tblSettings[3].cfgonly	=0
  tblSettings[3].type		=2
  tblSettings[3].prompt	=strCutWinBot
  tblSettings[3].key		="dowin"
  tblSettings[3].defvalue	=1

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=2
  tblSettings[4].prompt	=strCutDoorBot
  tblSettings[4].key		="dodoor"
  tblSettings[4].defvalue	=1
  
	tblSettings[5]			={}
	tblSettings[5].cfgonly	=0
	tblSettings[5].type		=1
	tblSettings[5].prompt	=strTargetSurf
	tblSettings[5].key		="side"
	tblSettings[5].valuelist=strTopBot
	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", strTitle, 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
g_bot=nil               -- Add to bottom
g_top=nil               -- Add to top
g_everynth=nil          -- Put to every nth gap only
g_zoff=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
		g_everynth=1
		g_zoff=0
		g_bot=0
		g_top=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
	local boty2, topy1    -- Find the top of bottom plate and bottom of the top plate
	
	boty2=0
	topy1=infoElem.height
	
  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
	  local elemGroup

    ac_objectopen(string.format("#%d",i))
    t=ac_objectget("#af_elemdata")
		elemGroup=ac_objectget("iElemGroup")
    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
		
		if elemGroup then
		  -- Find top & bottom
			if string.match(elemGroup, "^bottom_.*") or string.match(elemGroup, "^2ndbottom_.*") then
			  if t.by2>boty2 then
				  boty2=t.by2
				end
			end
			if string.match(elemGroup, "^top_.*") or string.match(elemGroup, "^2ndtop_.*") then
			  if t.by1<topy1 then
				  topy1=t.by1
				end
			end
		end
  end
  
  table.sort( tblStuds,  function(p1, p2)
                            return p1.distmin<p2.distmin
                          end )
													
-- Define as function to be able to add top & bottom using the same code and get the environment
local function AddNoggingLine(currdist)
  local nogIndex

  nogIndex=0
  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
					
				-- Skip touching studs
				i2 = i1
        while i1<nstuds do
				  -- Skip gaps up to 13 mm (half inch)
					if tblStuds[i1].distmax + 0.0126 + 0.0001 < tblStuds[i1 + 1].distmin then
						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.zoff=t.zoff+g_zoff
                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
	                nogIndex=nogIndex+1
									if nogIndex==g_everynth then
										nogIndex=0
									else
										createPlank = false
									end
								end
									
                if createPlank then
                  gnPlankCount=gnPlankCount+1
                  gtblCreate[gnPlankCount]=t
                end
            end
            i1=i2
        end
    end
  end
end													
  
  -- Place noggings
	g_everynth=math.floor(g_everynth)
	if g_everynth<1.0 then
	  g_everynth=1.0
	end

  if g_spacing>0 then
    -- Spacing rule
    currdist=0
    repeat
      local   tblLines, x1, y1, x2, y2, kline, vline, i1, i2, dummy, d

      currdist=currdist+g_spacing
      AddNoggingLine(currdist)
    until currdist>maxdist or g_single==1
	end
	

  -- # Handle top and bottom
	local thickness = g_thickness
	
  if currMat and currMat.thickness>0 then
	  thickness=currMat.thickness
  end
	
	if g_bot==1 then
	  -- Add to bottom
	  AddNoggingLine(boty2 + thickness*0.5)
	end

	if g_top==1 then
	  -- Add to top
	  AddNoggingLine(topy1 - thickness*0.5)
	end
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\neverynth=%f\nbot=%f\ntop=%f\nzoff=%f\n", g_matid, g_thickness, g_height, g_rotdeg, g_front, g_stagger, g_spacing, g_single, g_noggingsGap, g_everynth, g_bot, g_top, g_zoff)
end

-- Returns optional number setting or default if not existing
function GetOptNum(sSettings, key, defval)
  local s

  s=GetVal(sSettings, key)
  if s then
    s=tonumber(s)
		if s then
		  defval=s
		end
  end
	return defval
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"))
  
	g_noggingsGap=GetOptNum(sSettings, "noggap", g_noggingsGap)
  g_everynth=GetOptNum(sSettings, "everynth", g_everynth)
  g_zoff=GetOptNum(sSettings, "zoff", g_zoff)
  g_bot=GetOptNum(sSettings, "bot", g_bot)
  g_top=GetOptNum(sSettings, "top", g_top)
	
  -- 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

	-- Localized strings BEG
	local strTitle = "Noggings"
	local strMat = "Material"
	local strThickness = "Thickness if not fixed"
	local strHeight = "Height if not fixed"
	local strRotNog = "Rotate nogging 0/90 degrees"
	local strNogSide = "Noggings to front side (or back)"
	local strStaggering = "Staggering value, 0=no"
	local strSpacing = "Spacing or distance from bottom (negative=no)"
	local strSingleLine = "Just single nogging line"
	local strBot = "Add to bottom"
	local strTop = "Add to top"
	local strGap = "Noggings gap"
	local strNth = "Put only to every nth gap (2=every second etc)"
	local strZoff = "Move in element's watching direction"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Nurjahduksenestokapulat"
	  strMat = "Materiaali"
	  strThickness = "Paksuus jos ei vakio"
	  strHeight = "Korkeus jos ei vakio"
	  strRotNog = "Kierrä 0/90 astetta"
	  strNogSide = "Lisää etupuolelle (tai takapuolelle)"
	  strStaggering = "Vierekkäisten siirtomitta ylös/alas, 0=ei"
	  strSpacing = "Välistys tai et. alareunasta (neg=ei lisätä)"
	  strSingleLine = "Vain yksi lisäyslinja"
	  strBot = "Lisää alareunaan"
	  strTop = "Lisää yläreunaan"
	  strGap = "Asennusvara"
	  strNth = "Laita vain joka n:teen väliin (2=joka toiseen jne)"
	  strZoff = "Siirrä elementin katselusuunnassa"
  elseif s=="kor" then
	  strTitle = "블록킹"
	  strMat = "소재"
	  strThickness = "고정되지 않았을 경우 두께"
	  strHeight = "고정되지 않았을 경우 높이"
	  strRotNog = "블록킹 0/90 도 회전"
	  strNogSide = "전면부 (또는 후면부) 블록킹"
	  strStaggering = "지그재그 값, 0=적용 안함"
	  strSpacing = "간격 또는 하단으로부터 거리 (음수 값=적용 안함)"
	  strSingleLine = "단일 블록킹 선"
	  strBot = "하단에 추가"
	  strTop = "상단에 추가"
	  strGap = "블록킹 간격"
	  strNth = "n번째 간격에만 추가 (예시: 2=2번째 간격마다 추가)"
	  strZoff = "요소가 보는 방향으로 이동"
  elseif s=="pol" then
    strTitle = "Poprzeczki przeciw wyboczeniu"
    strMat = "Materiał"
    strThickness = "Grubość, jeśli niestandardowa"
    strHeight = "Wysokość, jeśli niestandardowa"
    strRotNog = "Obróć poprzeczkę 0/90 stopni"
    strNogSide = "Dodaj poprzeczki na przednią stronę (lub tylną)"
    strStaggering = "Przesunięcie w górę/dół sąsiednich poprzeczek, 0=brak"
    strSpacing = "Odstęp lub odległość od dołu (wartość ujemna=brak"
    strSingleLine = "Tylko jedna linia poprzeczek"
    strBot = "Dodaj na dole"
    strTop = "Dodaj na górze"
    strGap = "Odstęp poprzeczek"
    strNth = "Dodaj tylko co n-ty odstęp (2=co drugi, itd.)"
    strZoff = "Przesuń w kierunku patrzenia elementu"
	end
	-- Localized strings END

  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  =strMat
  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  =strThickness
  tblSettings[2].key    ="thickness"
  tblSettings[2].defvalue  =g_thickness

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  =strHeight
  tblSettings[3].key    ="height"
  tblSettings[3].defvalue  =g_height

  tblSettings[4]      ={}
  tblSettings[4].cfgonly  =0
  tblSettings[4].type    =4
  tblSettings[4].prompt  =strRotNog
  tblSettings[4].key    ="rot"
  tblSettings[4].defvalue  =g_rotdeg

  tblSettings[5]      ={}
  tblSettings[5].cfgonly  =0
  tblSettings[5].type    =2
  tblSettings[5].prompt  =strNogSide
  tblSettings[5].key    ="front"
  tblSettings[5].defvalue  =g_front

  tblSettings[6]      ={}
  tblSettings[6].cfgonly  =0
  tblSettings[6].type    =3
  tblSettings[6].prompt  =strStaggering
  tblSettings[6].key    ="stagger"
  tblSettings[6].defvalue  =g_stagger

  tblSettings[7]      ={}
  tblSettings[7].cfgonly  =0
  tblSettings[7].type    =3
  tblSettings[7].prompt  =strSpacing
  tblSettings[7].key    ="spacing"
  tblSettings[7].defvalue  =g_spacing

  tblSettings[8]      ={}
  tblSettings[8].cfgonly  =0
  tblSettings[8].type    =2
  tblSettings[8].prompt  =strSingleLine
  tblSettings[8].key    ="single"
  tblSettings[8].defvalue  =g_single
  
  tblSettings[9]      ={}
  tblSettings[9].cfgonly  =0
  tblSettings[9].type    =2
  tblSettings[9].prompt  =strBot
  tblSettings[9].key    ="bot"
  tblSettings[9].defvalue  =g_bot
  
  tblSettings[10]      ={}
  tblSettings[10].cfgonly  =0
  tblSettings[10].type    =2
  tblSettings[10].prompt  =strTop
  tblSettings[10].key    ="top"
  tblSettings[10].defvalue  =g_top
  
  tblSettings[11]      ={}
  tblSettings[11].cfgonly  =0
  tblSettings[11].type    =3
  tblSettings[11].prompt  =strGap
  tblSettings[11].key    ="nogging_gap"
  tblSettings[11].defvalue  =0

  tblSettings[12]      ={}
  tblSettings[12].cfgonly  =0
  tblSettings[12].type    =4
  tblSettings[12].prompt  =strNth
  tblSettings[12].key    ="everynth"
  tblSettings[12].defvalue  =1

  tblSettings[13]      ={}
  tblSettings[13].cfgonly  =0
  tblSettings[13].type    =3
  tblSettings[13].prompt  =strZoff
  tblSettings[13].key    ="zoff"
  tblSettings[13].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_bot
  tblSettings[10].value   =g_top
  tblSettings[11].value   =g_noggingsGap
  tblSettings[12].value   =g_everynth
  tblSettings[13].value   =g_zoff
 
  bRes,sErr=ac_optiondlg("LDNO", strTitle, 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_bot=tblSettings[9].value
  g_top=tblSettings[10].value
  g_noggingsGap=tblSettings[11].value
	
  g_everynth=tonumber(tblSettings[12].value)
	if not g_everynth then
	  g_everynth=1
	end
  g_zoff=tblSettings[13].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

	-- Localized strings BEG
	local strTitle = "Override element settings"
	local strSpacing = "Spacing:"
	local strStackingOff = "Stacking offset:"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Muutokset elementtiasetuksiin"
	  strSpacing = "Välistys (spacing):"
	  strStackingOff = "Aloituspaikan siirto (stacking offset):"
  elseif s=="kor" then
	  strTitle = "요소 설정"
	  strSpacing = "간격:"
	  strStackingOff = "시작점에 오프셋:"
  elseif s=="pol" then
    strTitle = "Nadpisanie ustawień elementu"
    strSpacing = "Odstęp:"
    strStackingOff = "Przesunięcie punktu początkowego (stacking offset):"
	end
	-- Localized strings END

  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	=strSpacing
  tblSettings[1].key		="spacing"
  tblSettings[1].value	=gSpacing

  tblSettings[2]			={}
  tblSettings[2].cfgonly	=0
  tblSettings[2].type		=3
  tblSettings[2].prompt	=strStackingOff
  tblSettings[2].key		="stackingoffset"
  tblSettings[2].value	=gStacking

  gHelpAnchor="afdlgelemsettings"
  bRes,sErr=ac_optiondlg("LDES", strTitle, 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


-- Collects planks with group name vertical_spacing_split, ignore cuts made from the elemdata.bx1 of these planks
-- Returns table of the split studs
function GetAutoSplitStuds()
  local tblSplitPlanks, t, i, s
  
  tblSplitPlanks={}
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
		s=ac_objectget("iElemGroup")
		if s and string.match(s, "^vertical_spacing_split.*") then
      t={}
      t.elemdata=ac_objectget("#af_elemdata")
      t.info=af_request("plankinfo")
			tblSplitPlanks[#tblSplitPlanks+1]=t
		end
    ac_objectclose()
  end
  
--DumpTbl(tblSplitPlanks)
  return tblSplitPlanks
end


-- Returns: true=given xc is on Automatic split element position, false=nope
function IsAutoSplitXc(tblSplitPlanks, xc)
  local i, v
  
  for i,v in ipairs(tblSplitPlanks) do
    if math.abs(xc - v.elemdata.bx1)<0.001 then
      return true
    end
  end

--ac_environment("tolog", string.format("IsAutoSplitXc xc=%f false", xc))
  return false
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, distToStud)
  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 - distToStud
    local bx2 = tblStud.elemdata.bx2
    local by2 = tblStud.elemdata.by2 + distToStud

    -- 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")

      -- 3/2024: Added rotangle 180 to support non-vertical elements (floors and roofs): AF turns the plank to have a small rotation value
      if not rotAngleLimit or math.abs(plank.elemdata.rotangle) < 1 or math.abs(math.abs(plank.elemdata.rotangle) - 180) < 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)
-- distToStud Distance from top/bottom plate to a stud: Nonzero if double top/bottom and handling case further from the stud
-- No return value
function DoRow(currPlank, bStartLong, tblStuds, nStuds, tblPrev, tblSplit, tx1, ty1, tx2, ty2, isBot, distToStud)
  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 then
      while i1 >= 1 do
        -- Current stud & current force
        local tblStud = tblStuds[i1]

        local ax1 = tblStud.elemdata.bx1
        local ay1 = tblStud.elemdata.by1 - distToStud
        local ax2 = tblStud.elemdata.bx2
        local ay2 = tblStud.elemdata.by2 + distToStud

        local bx1 = currPlank.elemdata.bx1
        local by1 = currPlank.elemdata.by1
        local bx2 = currPlank.elemdata.bx2
        local by2 = currPlank.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, currPlank, i1, startPos, tx1, ty1, tx2, ty2, distToStud)
            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 then
      cut = dy + ( (dy2-dy) / 2 )
    end
    
    tblSplit[#tblSplit + 1] = tx1 + 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 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)

      -- 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
			  studA, studB = studB, studA
			end
			
      x1 = studA.elemdata.x1 + studA.plankinfo.width / 2
      x2 = studB.elemdata.x1 - studB.plankinfo.width / 2

      -- Support also angled parts, calculate line to the middle of the reinforcement, yAdjust is distance to the right from the currPlank
      local yAdjust = currPlank.plankinfo.width / 2.0 + tblReinforcementMat.thickness / 2.0 + distToStud
      if isBot then
        yAdjust = -yAdjust
      end
			
			local rx1, ry2, rx2, ry2
			local dx, dy
			
			dx = (currPlank.elemdata.y2 - currPlank.elemdata.y1) / currPlank.plankinfo.len * yAdjust
			dy = -(currPlank.elemdata.x2 - currPlank.elemdata.x1) / currPlank.plankinfo.len * yAdjust
			rx1 = currPlank.elemdata.x1 + dx
			ry1 = currPlank.elemdata.y1 + dy
			rx2 = currPlank.elemdata.x2 + dx
			ry2 = currPlank.elemdata.y2 + dy

--ac_environment("tolog", string.format("rx1, ry1, rx2, ry2: %f %f %f %f", rx1, ry1, rx2, ry2))

			-- Then find intersection of the stud sides and the reinforcement line
			local plankX1, plankY1, plankX2, plankY2
			
			plankX1, plankY1 = ac_geo("linex", rx1, ry1, rx2, ry2, x1, 0, x1, 1)
			plankX2, plankY2 = ac_geo("linex", rx1, ry1, rx2, ry2, x2, 0, x2, 1)
			
			-- Shorten by the angle to have straight cuts for the reinforcement
			local tanAngle = math.tan(math.abs(math.atan2(ry2 - ry1, rx2 - rx1)))
			
			dx = tanAngle * (currPlank.elemdata.x2 - currPlank.elemdata.x1) / currPlank.plankinfo.len * tblReinforcementMat.thickness / 2.0
			dy = tanAngle * (currPlank.elemdata.y2 - currPlank.elemdata.y1) / currPlank.plankinfo.len * tblReinforcementMat.thickness / 2.0
			plankX1 = plankX1 + dx
			plankY1 = plankY1 + dy
			plankX2 = plankX2 - dx
			plankY2 = plankY2 - dy

--ac_environment("tolog", string.format("plankX1, plankY1, plankX2, plankY2: %f %f %f %f", plankX1, plankY1, plankX2, plankY2))
			
      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 = {}
	local indFurther = -1   -- Index for the further row
	
  i2=0
  if isBot then
    if #gtblTop>0 then
      i2=i2+1
      tblTargetRows[i2]=gtblTop
    end
    if #gtbl2ndTop>0 then
		  indFurther=i2
      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
		  indFurther=i2
    end
  end

  local i3, tblPrev, tblSplit
	local height2ndTop = 0
	
	for i3 = 1, #gtbl2ndTop do
	  if gtbl2ndTop[i3].plankinfo.width > height2ndTop then
		  height2ndTop = gtbl2ndTop[i3].plankinfo.width
	  end
	end

  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
			local distToStud = 0
			
		  if i1==indFurther then
			  distToStud = height2ndTop
      end

      DoRow(tblTargetRows[i1][i3], bStartLong, tblStuds, nStuds, tblPrev, tblSplit, x1, y1, x2, y2, isBot, distToStud)
    end
    tblPrev = tblSplit
--DumpTbl(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 IsAutoSplitXc(gAutoCutStuds, tblPlanks[i].elemdata.bx1) and 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
  
  gAutoCutStuds = GetAutoSplitStuds()     -- Global since used in DoJoin() which is called many times
  
  -- 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()


	-- Localized strings BEG
	local strTitle = "Automatic cutting settings"
	local strMaxLen = "Max length (0=use plank's maximum length):"
	local strMinLen = "Min length:"
	local strMinOverlap = "Min overlap:"
	local strMinDistStud = "Min distance from stud (0=cut from center):"
	local strCutTop = "Cut top:"
	local strCutBot = "Cut bottom:"
	local strReinforceCut = "Reinforcement to the cut:"
	local strReinforceMatid = "Reinforcement material ID:"
	local strReinforceMinLen = "Reinforcement minimum length:"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Katko ylä- ja alajuoksu automaattisesti asetukset"
	  strMaxLen = "Maksimipituus (0=käytä kapulan omaa maksimipituutta):"
	  strMinLen = "Minimipituus:"
	  strMinOverlap = "Minimi limitys:"
	  strMinDistStud = "Minimietäisyys tolpasta (0=katkaise tolpan keskelle):"
	  strCutTop = "Katko yläjuoksut:"
	  strCutBot = "Katko alajuoksut:"
	  strReinforceCut = "Vahvike jatkokseen:"
	  strReinforceMatid = "Vahvikkeen materiaali-ID:"
	  strReinforceMinLen = "Vahvikkeen minimipituus:"
  elseif s=="kor" then
	  strTitle = "자동 절단 설정"
	  strMaxLen = "최대 길이 (0=플랭크의 최대 길이 사용):"
	  strMinLen = "최소 길이:"
	  strMinOverlap = "최소 겹침:"
	  strMinDistStud = "스터드로부터의 최소 거리 (0=중앙에서부터 절단):"
	  strCutTop = "상단 절단:"
	  strCutBot = "하단 절단:"
	  strReinforceCut = "절단에 보강재:"
	  strReinforceMatid = "보강재 소재 ID:"
	  strReinforceMinLen = "보강재 최소 길이:"
  elseif s=="pol" then
    strTitle = "Ustawienia automatycznego cięcia górnych i dolnych belek"
    strMaxLen = "Maksymalna długość (0=użyj maksymalnej długości elementu):"
    strMinLen = "Minimalna długość:"
    strMinOverlap = "Minimalna zakładka:"
    strMinDistStud = "Minimalna odległość od słupka (0=przytnij na środku):"
    strCutTop = "Przytnij górne belki:"
    strCutBot = "Przytnij dolne belki:"
    strReinforceCut = "Wzmocnienia do cięć:"
    strReinforceMatid = "ID materiału wzmocnienia:"
    strReinforceMinLen = "Minimalna długość wzmocnienia:"
	end
	-- Localized strings END
  
  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	=strMaxLen
  tblSettings[i].key		="maxlen"
  tblSettings[i].value	=gdMaxLen
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	=strMinLen
  tblSettings[i].key		="minlen"
  tblSettings[i].value  =gdMinLen
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	=strMinOverlap
  tblSettings[i].key		="minoverlap"
  tblSettings[i].value  =gdMinOverlap
  i = i + 1

  tblSettings[i]			={}
  tblSettings[i].cfgonly	=0
  tblSettings[i].type		=3
  tblSettings[i].prompt	=strMinDistStud
  tblSettings[i].key		="minstud"
  tblSettings[i].value  =gdMinDistStud
  i = i + 1

  tblSettings[i]          = {}
  tblSettings[i].cfgonly  = 0
  tblSettings[i].type     = 2
  tblSettings[i].prompt   = strCutTop
  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   = strCutBot
  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   = strReinforceCut
  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   = strReinforceMatid
  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   = strReinforceMinLen
  tblSettings[i].key		  = "reinforcement_min_length"
  tblSettings[i].value    = gdReinforcementMinLength
  i = i + 1

  bRes,sErr=ac_optiondlg("LDAC", strTitle, 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
gGap=0.0


-- 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
  t.gap=gGap
  
  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


-- Collects planks with group name vertical_spacing_split, ignore cuts made from the elemdata.bx1 of these planks
-- Returns table of the split studs
function GetAutoSplitStuds()
  local tblSplitPlanks, t, i, s
  
  tblSplitPlanks={}
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
		s=ac_objectget("iElemGroup")
		if s and string.match(s, "^vertical_spacing_split.*") then
      t={}
      t.elemdata=ac_objectget("#af_elemdata")
      t.info=af_request("plankinfo")
			tblSplitPlanks[#tblSplitPlanks+1]=t
		end
    ac_objectclose()
  end
  
--DumpTbl(tblSplitPlanks)
  return tblSplitPlanks
end


-- Returns: true=given xc is on Automatic split element position, false=nope
function IsAutoSplitXc(tblSplitPlanks, xc)
  local i, v
  
  for i,v in ipairs(tblSplitPlanks) do
    if math.abs(xc - v.elemdata.bx1)<0.001 then
      return true
    end
  end

--ac_environment("tolog", string.format("IsAutoSplitXc xc=%f false", xc))
  return 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
	
	local tblSplitPlanks = GetAutoSplitStuds()
  
  -- Check if there are parallel planks having the same end points
  tblPlanks={}
  res=0
  for i=1,gnPlanks do
    local s

    ac_objectopen(string.format("#%d",i))
    elemdata = ac_objectget("#af_elemdata")
    info = af_request("plankinfo")
    s = ac_objectget("iElemGroup")
    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={}
    -- 5/2024 AutoSpplitElem cuts only top & bottom - mark here
    if string.match(s, "^bottom_force.*") or string.match(s, "^2ndbottom_force.*") or string.match(s, "^top_force.*") or string.match(s, "^2ndtop_force.*") or string.match(s, "^contourtilted.*") then
      t.topbot = true
    end
    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) and (not IsAutoSplitXc(tblSplitPlanks, t.elemdata.x1) or not t.topbot) 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

	-- Localized strings BEG
	local strTitle = "Automatic stud cutting"
	local strMaxLen = "Max length (0=use plank's maximum length)"
	local strMinLen = "Min length"
	local strMinOverlap = "Min overlap"
	local strMinOverlapMaxDist = "Min overlap rule applied max dist"
	local strGap = "Gap when cut (not affecting previous settings)"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Katko koolaus asetukset"
	  strMaxLen = "Maksimipituus (0=käytä kapulan omaa maksimipituutta)"
	  strMinLen = "Minimipituus"
	  strMinOverlap = "Minimi limitys"
	  strMinOverlapMaxDist = "Maksimietäisyys, johon minimi limitys -sääntö vaikuttaa"
	  strGap = "Katkon välys (ei vaikuta edellisiin asetuksiin)"
  elseif s=="kor" then
	  strTitle = "자동 스터드 절단"
	  strMaxLen = "최대 길이 (0=플랭크의 최대 길이 사용)"
	  strMinLen = "최소 길이"
	  strMinOverlap = "최소 겹침"
	  strMinOverlapMaxDist = "최소 겹침 규칙 적용 최대 거리"
	  strGap = "절단 시 간격 (이전 설정에 영향을 주지 않음)"
  elseif s=="pol" then
    strTitle = "Ustawienia automatycznego cięcia słupków"
    strMaxLen = "Maksymalna długość (0=użyj maksymalnej długości elementu)"
    strMinLen = "Minimalna długość"
    strMinOverlap = "Minimalna zakładka"
    strMinOverlapMaxDist = "Maksymalna odległość zastosowania reguły minimalnej zakładki"
    strGap = "Przerwa przy cięciu (nie wpływa na poprzednie ustawienia)"
	end
	-- Localized strings END

  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	=strMaxLen
  tblSettings[1].key		="maxlen"
  tblSettings[1].value	=gdMaxLen

  tblSettings[2]			={}
  tblSettings[2].cfgonly	=0
  tblSettings[2].type		=3
  tblSettings[2].prompt	=strMinLen
  tblSettings[2].key		="minlen"
  tblSettings[2].value  =gdMinLen

  tblSettings[3]			={}
  tblSettings[3].cfgonly	=0
  tblSettings[3].type		=3
  tblSettings[3].prompt	=strMinOverlap
  tblSettings[3].key		="minoverlap"
  tblSettings[3].value  =gdMinOverlap

  tblSettings[4]			={}
  tblSettings[4].cfgonly	=0
  tblSettings[4].type		=3
  tblSettings[4].prompt	=strMinOverlapMaxDist
  tblSettings[4].key		="minoverlaprule"
  tblSettings[4].value  =gOverlapRuleDist
  
  tblSettings[5]			={}
  tblSettings[5].cfgonly	=0
  tblSettings[5].type		=3
  tblSettings[5].prompt	=strGap
  tblSettings[5].key		="gap"
  tblSettings[5].value  =gGap

  bRes,sErr=ac_optiondlg("LDAS", strTitle, tblSettings)
  if not bRes then
    return false
  end

  gdMaxLen=tblSettings[1].value
  gdMinLen=tblSettings[2].value
  gdMinOverlap=tblSettings[3].value
  gOverlapRuleDist=tblSettings[4].value
  gGap=tblSettings[5].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"))
  
  gGap=0
  s=GetVal(sSettings, "gap")
  if s then
    gGap=tonumber(s)
  end

  -- Will cause error if bad syntax
  s = string.format("maxlen=%0.5f\nminlen=%0.5f\nminoverlap=%0.5f\noverlapruledist=%0.5f\ngap=%0.5f", gdMaxLen, gdMinLen, gdMinOverlap, gOverlapRuleDist, gGap )
end


-- Finds nice material
function GetDefaults()
  gdMaxLen=0
  gdMinLen=1.200
  gdMinOverlap=1.200
  gOverlapRuleDist=1.2
  gGap=0
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\ngap=%0.5f", gdMaxLen, gdMinLen, gdMinOverlap, gOverlapRuleDist, gGap )
  return sSettings
end
]]>
        </script>


				<script id="autosplitelem">
					<![CDATA[
EPS = 0.0001
gdMaxLen=7.200
gGroupName = "vertical_spacing_split"   -- We process only vertical_spacing and produce vertical_spacing_split

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


function LineInPolyFull(x1, y1, x2, y2, polyListElem)
  local res, v
	
  res = ac_geo("linepolyx", x1, y1, x2, y2, polyListElem)
	if not res or #res ~= 1 then
	  return false
	end

	v = res[1]
	return math.abs(x1 - v.x1) < EPS and math.abs(y1 - v.y1) < EPS and math.abs(x2 - v.x2) < EPS and math.abs(y2 - v.y2) < EPS
end


-- Checks that the stud can be moved half of its width left and duplicated to the right without collision
-- polyListElem 1-based polygon list from "getpoly" (.poly)
function IsSpaceToDuplicate(tblStud, tblAll, polyListElem)
  local i, v, width
	local x1, x2


  -- Calc x1 and x2 of double stud
	width = tblStud.elemdata.bx2 - tblStud.elemdata.bx1
	x1 = tblStud.elemdata.bx1 - width / 2
	x2 = tblStud.elemdata.bx2 + width / 2
	
	for i=1,#tblAll do
	  v=tblAll[i]
		
		if v.info.ptr ~= tblStud.info.ptr then
  		-- Say it is ok if the tested one v goes through tblStud - it could be top/bottom plate or a beam
      -- Test if collision after
      if v.elemdata.bx1 + EPS > x1 and v.elemdata.bx1 < x2 - EPS then
--ac_environment("tolog", string.format("IsSpaceToDuplicate: Discarded after bx1=%f by1=%f bx2=%f by2=%f", tblStud.elemdata.bx1, tblStud.elemdata.by1, tblStud.elemdata.bx2, tblStud.elemdata.by2))
		    return false
      end

      -- Test if collision before
      if v.elemdata.bx2 - EPS < x2 and v.elemdata.bx2 > x1 + EPS then
--ac_environment("tolog", string.format("IsSpaceToDuplicate: Discarded before bx1=%f by1=%f bx2=%f by2=%f", tblStud.elemdata.bx1, tblStud.elemdata.by1, tblStud.elemdata.bx2, tblStud.elemdata.by2))
		    return false
      end
		end
	end

  -- Test: left side of original, middle, right, mid of dup and right of dup
  for i=1,5 do
	  if not LineInPolyFull(x1, tblStud.elemdata.y1, x1, tblStud.elemdata.y2, polyListElem) then
--ac_environment("tolog", string.format("IsSpaceToDuplicate: Discarded x1=%f y1=%f x2=%f y2=%f", tblStud.elemdata.x1, tblStud.elemdata.y1, tblStud.elemdata.x2, tblStud.elemdata.y2))
		  return false
	  end
    x1 = x1 + width * 0.5
	end

--ac_environment("tolog", string.format("IsSpaceToDuplicate: Took"))
	return true
end


-- Checks if (slightly extended) stud connects to given array of top/bottom plates
function ConnectsInt(tblStud, tblTopsBots)
  local i, v, tblPolys, res
  
  -- "linepolyx" takes poly list and we have just one, make it an array
  tblPolys = {}
  
  for i,v in ipairs(tblTopsBots) do
    tblPolys[1] = v.elemdata.poly
    res = ac_geo("linepolyx", tblStud.elemdata.x1, tblStud.elemdata.y1 - 0.001, tblStud.elemdata.x2, tblStud.elemdata.y2 + 0.001, tblPolys)
    if res then
      return true
    end
  end

  return false
end


-- Checks if given tblStud is connected to both bottom and top plate
-- polyListElem unused for now
function ConnectsBotTop(tblStud, tblBots, tblTops, polyListElem)
  if not ConnectsInt(tblStud, tblBots) or not ConnectsInt(tblStud, tblTops) then
--ac_environment("tolog", string.format("ConnectsBotTop not connected: bx1=%f by1=%f bx2=%f by2=%f", tblStud.elemdata.bx1, tblStud.elemdata.by1, tblStud.elemdata.bx2, tblStud.elemdata.by2))
    return false
  end

  return true
end


-- Finds spacing studs (vertical_spacing) that are touching top or bottom plates (or the element) and are not rotated
-- Returns the table sorted by stud xc and maximum x-coord for all planks
function FindFullStuds()
  local i, s, tblStuds, tblAll, t, maxx
  local tblBots, tblTops
	
	tblStuds = {}
	tblAll = {}
	tblBots = {}
	tblTops = {}
	
--ac_environment("tolog", string.format("FindFullStuds gnPlanks=%d", gnPlanks))
	maxx = -100
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d", i))
    s = ac_objectget("iElemGroup")
		
		-- Fill info to be added to either stud or some other table (in future?)
		t = {}
  	t.info = af_request("plankinfo")
		t.elemdata = ac_objectget("#af_elemdata")
    t.elemgroup = s
		t.index = i
    
    if t.elemdata.bx2 > maxx then
      maxx = t.elemdata.bx2
    end

    -- Require exact match    
    if s == "vertical_spacing" then    
		  -- We rely simply on this and suppose that it is in the spacing distance from the previous
			if math.abs(t.elemdata.rotangle) < EPS and math.abs(t.elemdata.x2 - t.elemdata.x1) < EPS then
			  tblStuds[#tblStuds + 1] = t
--ac_environment("tolog", string.format("FindFullStuds : s=%s bx1=%f by1=%f bx2=%f by2=%f", s, t.elemdata.bx1, t.elemdata.by1, t.elemdata.bx2, t.elemdata.by2))
			end
    elseif string.match(s, "^bottom_force.*") or string.match(s, "^2ndbottom_force.*") then
      tblBots[#tblBots + 1] = t
      t = nil
    elseif string.match(s, "^top_force.*") or string.match(s, "^2ndtop_force.*") or string.match(s, "^contourtilted.*") then
      tblTops[#tblTops + 1] = t
      t = nil
		end
		
    if t then
		  -- Collect all including studs to be able to check if the duplicate will fit after current stud without collision
		  tblAll[#tblAll + 1] = t
    end
    
    ac_objectclose()
  end
	
	function CmpElemX1(a, b)
	  return a.elemdata.x1 < b.elemdata.x1
	end
	
	table.sort(tblStuds, CmpElemX1)
	table.sort(tblAll, CmpElemX1)
	
--DumpTbl(tblStuds)
--DumpTbl(tblAll)
	
	-- Filter out all studs that do not have space at the right side
	local tblStuds2 = {}
	local polyListElem
	
	t = {}
	t.givelist = 1    -- Future proof
	polyListElem = af_request ("getpoly", t, gGuidElem)
	
	for i=1,#tblStuds do
    local tblStud = tblStuds[i]
--ac_environment("tolog", string.format("FindFullStuds: bx1=%f by1=%f bx2=%f by2=%f #tblAll=%d", tblStud.elemdata.bx1, tblStud.elemdata.by1, tblStud.elemdata.bx2, tblStud.elemdata.by2, #tblAll))
	  if IsSpaceToDuplicate(tblStud, tblAll, polyListElem.poly) then
    	-- Then filter out all studs that are not touching the top or bottom plate
      if ConnectsBotTop(tblStud, tblBots, tblTops, polyListElem) then
  	    tblStuds2[#tblStuds2 + 1] = tblStud
--ac_environment("tolog", "FindFullStuds: Took")
      end
	  end
	end
	tblStuds=tblStuds2
  
  return tblStuds, maxx
end


-- Moves current to left width/2 and duplicates it to the right from current one
function DuplicateStud( tblStud )
  local plank, width
  
  width = tblStud.info.width
  plank={}
  plank.guidsettings=tblStud.info.ptr
  plank.copyops=1
  plank.group=gGroupName
  --plank.id="42x173"
  --plank.thickness=0.042
  --plank.height=0.173

  plank.x1 = tblStud.elemdata.x1 + width * 0.5
  plank.y1 = tblStud.elemdata.y1
  plank.x2 = plank.x1
  plank.y2 = tblStud.elemdata.y2
  plank.extendtoelem = 1
  --plank.xmlsettings=string.format("<s><objparam name=\"iNailOffsetBehind\">%d</objparam></s>", g_nonails)
              
  gtblCreate[#gtblCreate + 1] = plank
  
  -- Do not set for the original one
  --ac_objectopen( tblStud.info.ptr )
  --ac_objectset( "iElemGroup", gGroupName )
  --ac_objectclose()
	
	-- Move original to left
	local tblEdit = {}

  tblEdit.guid = tblStud.info.ptr
	tblStud.elemdata.x1 = tblStud.elemdata.x1 - width / 2
	tblStud.elemdata.x2 = tblStud.elemdata.x2 - width / 2
	tblEdit.elemdata = tblStud.elemdata
	af_request("editplank", tblEdit)
end


-- Gives plane equation ax+bx+cx+dx=0 from normal vector and a point on the plane x1,y1,z1
-- Please note td different sign than in Wykobi
-- in:
--	pnx, pny, pnz	Normal vector, calculated to unit one here
--	x1,y1,z1		Point on the plane
-- out:
--	pa, pb, pc, pd	Plane equation (pa,pb,pc=pnx,pny,pnz as unit vector)
function MakePlaneNormal(pnx, pny, pnz, 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, pa, pb, pc, pd

	-- Tässä hypätään suoraan vakion laskentaan
	mul=1/math.sqrt(pnx*pnx+pny*pny+pnz*pnz)
	pa=pnx*mul
	pb=pny*mul
	pc=pnz*mul
	pd=-(pa*x1+pb*y1+pc*z1)
	return pa, pb, pc, pd
end


-- Cuts all non vertical planks intersecting vertical line at given xc
function CutNonVertical( xc )
  local i, elemdata, x, y, infoElem

  -- Get geo for the element to be used when calculating the cutting plane
  infoElem = af_request( "plankinfo", gGuidElem )
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d", i))
		elemdata = ac_objectget("#af_elemdata")
    
    x,y = ac_geo( "linex", xc, -100, xc, 100, elemdata.x1, elemdata.y1, elemdata.x2, elemdata.y2)
    if x then
      -- Infinite lines have intersection, check if intersection in the target
      local dist, fromBeg, len
      
      dist, fromBeg, len = ac_geo( "linedist", elemdata.x1, elemdata.y1, elemdata.x2, elemdata.y2, x, y)
      if fromBeg > EPS and fromBeg + EPS < len then
        local tblPlane, x3, y3, z3
        
        -- Move x,y to 3D world
        x3 = infoElem.begc.x + x * infoElem.vecx.x
        y3 = infoElem.begc.y + x * infoElem.vecx.y
        z3 = infoElem.begc.z + x * infoElem.vecx.z
        
        tblPlane = {}
        tblPlane.pa, tblPlane.pb, tblPlane.pc, tblPlane.pd = MakePlaneNormal(infoElem.vecx.x, infoElem.vecx.y, infoElem.vecx.z, x3, y3, z3)
        af_request( "cutplank", tblPlane )
      end
    end
    ac_objectclose()
  end
end


function DoSplit()
  local x1 = 0

  -- Loop to handle multiple cuts
  while true do
    gtblCreate = {}

    local tblStuds, maxx

    -- Find all splitting candidates
    tblStuds, maxx = FindFullStuds()
    
    if #tblStuds == 0 or maxx - x1 - EPS < gdMaxLen then
      break
    end
    
    -- Find the last stud which is under max length
    local i
    local cutIndex = nil

    i = #tblStuds
    while i > 0 do
      if tblStuds[i].elemdata.bx1 > x1 + EPS and tblStuds[i].elemdata.bx2 + tblStuds[i].info.width * 0.5 - x1 - EPS < gdMaxLen then   -- Moved half width to the left
        cutIndex = i
        break
      end
      i = i - 1
    end
    
    if not cutIndex then
      ac_environment("tolog", string.format("Automatic split element ID=%s: Could not split element completely", ac_getobjparam(gGuidElem, "#id")))
      break
    end

--ac_environment("tolog", string.format("tblStuds[cutIndex].elemdata.bx1=%f", tblStuds[cutIndex].elemdata.bx1))
    DuplicateStud( tblStuds[cutIndex] )
    CutNonVertical( tblStuds[cutIndex].elemdata.bx2 - tblStuds[cutIndex].info.width * 0.5 )

    gxmlOperations = nil
    if #gtblCreate > 0 then
      -- Cannot use #num for the new plank since "cutplank" creates the split planks before we add the new ones.
      gxmlOperations = "<ops>"
      gxmlOperations = gxmlOperations .. string.format( "<jointo target=\"%s\" operator=\"top*|2ndtop*|bottom*|2ndbottom*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\"></cut></jointo>", gGroupName)
      gxmlOperations = gxmlOperations .. string.format( "<jointo target=\"#%d\" operator=\"top*|2ndtop*|bottom*|2ndbottom*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\"></cut></jointo>", tblStuds[cutIndex].index)
      gxmlOperations = gxmlOperations .. "</ops>"
--ac_environment("tolog", gxmlOperations)
      af_request("elem_createplanks")
    end

    -- The part next will start from here
    x1 = tblStuds[cutIndex].elemdata.bx2
    af_request("elem_getpoly")        -- Recreate environment (needed to process the split top&bottom plates correctly)
  end

end


-- Returns: -1=Not known/no planks, 0=nope, 1=has
function Has()
  return ResetInt(true)
end


function Set(sSettings)
  local res, errStr, t

  GetDefaults()
  if sSettings~=nil then
    res, errStr=pcall(ParseSettings, sSettings)
    if not res then
      GetDefaults()
    end
  end

  DoSplit()
end



function Reset()
  return ResetInt(false)
end


-- Check if this cut is from the split stud
function IsCutInSplitStud(xsplit, tblSplitPlanks)
	local isplit, vsplit
			
  for ksplit,vsplit in ipairs(tblSplitPlanks) do
		if math.abs(vsplit.elemdata.bx1 - xsplit) < EPS then
			return true
		end
	end
	return false
end


function ResetInt(justCheck)
  local i, tblSplitPlanks, elemdata, info, t, s
  
  res=0
  af_request("elem_getpoly")
  if gnPlanks==0 then
    return -1
  end
  
  -- Check if there are planks with group name vertical_spacing_split
  tblSplitPlanks={}
  for i=1,gnPlanks do
    t=nil
    ac_objectopen(string.format("#%d",i))
		s=ac_objectget("iElemGroup")
		if s and s == gGroupName then
      t={}
      t.elemdata=ac_objectget("#af_elemdata")
      t.info=af_request("plankinfo")
		end
    ac_objectclose()
		
		if t then
		  res=1
			tblSplitPlanks[#tblSplitPlanks+1]=t
		end
  end
  
	-- Any existing?
	if #tblSplitPlanks==0 then
	  return 0
	end
	
  if justCheck then
    return 1
  end

  -- Remove existing doubles used for splir
  for i=1,#tblSplitPlanks do
    t = tblSplitPlanks[i]
    ac_objectopen(t.info.ptr)
    af_request( "delplank" )
    ac_objectclose()
  end
	
	-- Move any stud to the right from its current pos if it is just left from the duplicated split stud
  -- Also collect indexes of moved studs to match those to top & bottom
  local strIndexes = ""
  
  for i=1,gnPlanks do
    local elemdata, isplit, vsplit
    
    ac_objectopen(string.format("#%d",i))
    elemdata=ac_objectget("#af_elemdata")
    
    for isplit, vsplit in ipairs(tblSplitPlanks) do
      if math.abs(vsplit.elemdata.bx1 - elemdata.bx2) < EPS and string.match(ac_objectget("iElemGroup"), "^vertical_spacing.*") then
        local info, tblEdit

	      -- Move original to right
        info = af_request("plankinfo")
        
	      tblEdit = {}
        tblEdit.guid = info.ptr
	      elemdata.x1 = elemdata.x1 + info.width / 2
	      elemdata.x2 = elemdata.x2 + info.width / 2
	      tblEdit.elemdata = elemdata
	      af_request("editplank", tblEdit)
        
        if #strIndexes>0 then
          strIndexes = strIndexes .. ","
        end
        strIndexes = string.format("%s%d", strIndexes, i)
      end
    end
  
    ac_objectclose()
  end
  
  gxmlOperations = "<ops>"
  gxmlOperations = gxmlOperations .. string.format( "<jointo target=\"#%s\" operator=\"top*|2ndtop*|bottom*|2ndbottom*|contourtilted\"><cut jointgap=\"0.000\" endshape=\"angleddelfirst\"></cut></jointo>", strIndexes)
  gxmlOperations = gxmlOperations .. "</ops>"
--ac_environment("tolog", gxmlOperations)
  af_request("elem_createplanks")
  	  
  -- Join any non vertical plank if cut from left of the split duplicate, collect to a table having key as iElemGroup and have planks under that in 1-based array
  local tblTopBots = {}
  
  for i=1,gnPlanks do
    ac_objectopen(string.format("#%d",i))
		s = ac_objectget("iElemGroup")
		if s then
      local tblGroup
      
      tblGroup = tblTopBots[s]
      if not tblGroup then
        tblGroup = {}
        tblTopBots[s] =tblGroup
      end
        
      t={}
      t.elemdata=ac_objectget("#af_elemdata")
      t.info=af_request("plankinfo")
      
      tblGroup[#tblGroup+1] = t
		end
    ac_objectclose()
  end
  
  local k, v
  
  for k,v in pairs(tblTopBots) do
    -- Sort the group by x-coord
    table.sort(v, function (n1, n2)
                    return n1.elemdata.x1 < n2.elemdata.x1
	                end
    )
    
    -- Then join if cut from the split stud x1
    i = 1
    while i < #v do
      local i2, x2
      
      i2 = i + 1
      x2 = v[i].elemdata.bx2

--ac_environment("tolog", string.format("k=%s v[i].elemdata.x2=%f v[i2].elemdata.x1=%f", k, v[i].elemdata.bx2, v[i2].elemdata.bx1))
      while i2 <= #v and math.abs(v[i2].elemdata.bx1 - x2) < EPS and IsCutInSplitStud(x2, tblSplitPlanks) do
        if not af_request( "joinplanks", v[i].info.ptr, v[i2].info.ptr) then
          break
        end
        
        x2 = v[i2].elemdata.bx2
        i2 = i2 + 1
      end
      
      i = i2   
    end
  end

  return 1
end


-------------------------
-- OPTIONS


function SettingsDlg(sSettings)
  local  tblSettings, bRes, sErr


	-- Localized strings BEG
	local strTitle = "Automatic split element"
	local strMaxLen = "Max elem length:"
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Katko elementti automaattisesti"
	  strMaxLen = "Elementin maksimipituus:"
  elseif s=="kor" then
	  strTitle = "자동 스플릿 요소"
	  strMaxLen = "최대 요소 길이:"
  elseif s=="pol" then
    strTitle = "Automatyczny podział elementu"
    strMaxLen = "Maksymalna długość elementu:"
	end
	-- Localized strings END

  GetDefaults()
--ac_environment("tolog", string.format("settings=%s", sSettings))
  if sSettings~=nil and sSettings~="" then
    pcall(ParseSettings, sSettings)
  end
  
  tblSettings={}
  tblSettings[1]			={}
  tblSettings[1].cfgonly	=0
  tblSettings[1].type		=3
  tblSettings[1].prompt	=strMaxLen
  tblSettings[1].key		="maxlen"
  tblSettings[1].value	=gdMaxLen

  bRes,sErr=ac_optiondlg("LDSE", strTitle, tblSettings)
  if not bRes then
    return false
  end

  gdMaxLen=tblSettings[1].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)
  
  gdMaxLen=tonumber(GetVal(sSettings, "maxlen"))
  gdMinLen=tonumber(GetVal(sSettings, "minlen"))
  gdMinOverlap=tonumber(GetVal(sSettings, "minoverlap"))
  gOverlapRuleDist=tonumber(GetVal(sSettings, "overlapruledist"))
  
  --gGap=0
  --s=GetVal(sSettings, "gap")
  --if s then
  --  gGap=tonumber(s)
  --end

  -- Will cause error if bad syntax
	MakeSettingsStr()
end


function MakeSettingsStr()
  return string.format("maxlen=%0.5f\n", gdMaxLen)
end


-- Finds nice material
function GetDefaults()
  gdMaxLen=7.200
end


-- Return: nil=canceled, ""=clear settings/use defaults, str=settings str
function Settings(sSettings)
  if not SettingsDlg(sSettings) then
    return
  end

  return MakeSettingsStr()
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


-- Gives plane equation ax+bx+cx+dx=0 from normal vector and a point on the plane x1,y1,z1
-- Please note td different sign than in Wykobi
-- in:
--	pnx, pny, pnz	Normal vector, calculated to unit one here
--	x1,y1,z1		Point on the plane
-- out:
--	pa, pb, pc, pd	Plane equation (pa,pb,pc=pnx,pny,pnz as unit vector)
function MakePlaneNormal(pnx, pny, pnz, 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, pa, pb, pc, pd

	-- Tässä hypätään suoraan vakion laskentaan
	mul=1/math.sqrt(pnx*pnx+pny*pny+pnz*pnz)
	pa=pnx*mul
	pb=pny*mul
	pc=pnz*mul
	pd=-(pa*x1+pb*y1+pc*z1)
	return pa, pb, pc, pd
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

-- Localized strings BEG
	local strTitle = "Floor side pieces"
	local strMat = "Material"
	local strThickness = "Thickness (if not fixed)"
	local strHeight = "Height (if not fixed)"
	local strPos = "Position of new pieces relative to the selection"
	local strLeftRight = "\"1: To left\",\"2: To right\""
	
	s=af_request("aflang")
  if s=="fin" then
	  strTitle = "Lattian reunakappaleet"
	  strMat = "Materiaali"
	  strThickness = "Paksuus jos ei vakio"
	  strHeight = "Korkeus jos ei vakio"
	  strPos = "Uusien kappaleiden sijainti suhteessa valintaan"
	  strLeftRight = "\"1: Vasemmalle\",\"2: Oikealle\""
  elseif s=="kor" then
	  strTitle = "바닥 측면 피스"
	  strMat = "소재"
	  strThickness = "두께 (고정되지 않았을 경우)"
	  strHeight = "높이 (고정되지 않았을 경우)"
	  strPos = "선택된 항목 대비 새로운 피스의 위치"
	  strLeftRight = "\"1: 좌측\",\"2: 우측\""
  elseif s=="pol" then
    strTitle = "Boczne elementy podłogi"
    strMat = "Materiał"
    strThickness = "Grubość, jeśli niestandardowa"
    strHeight = "Wysokość, jeśli niestandardowa"
    strPos = "Pozycja nowych elementów względem zaznaczenia"
    strLeftRight = "\"1: W lewo\",\"2: W prawo\""
	end
	-- Localized strings END

  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  =strMat
  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  =strThickness
  tblSettings[2].key    ="thickness"
  tblSettings[2].defvalue  =g_thickness

  tblSettings[3]      ={}
  tblSettings[3].cfgonly  =0
  tblSettings[3].type    =3
  tblSettings[3].prompt  =strHeight
  tblSettings[3].key    ="height"
  tblSettings[3].defvalue  =g_height

  tblSettings[4]      ={}
  tblSettings[4].cfgonly =0
  tblSettings[4].type    =1
  tblSettings[4].prompt  =strPos
  tblSettings[4].key    ="side"
  tblSettings[4].valuelist=strLeftRight
  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", strTitle, 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("tolog", "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()
  return af_request("aflang")
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
  elseif lang=="kor" then    
    if string.match(typetag, "^finish_int.*") then
      name="패널"
    elseif string.match(typetag, "^intstud.*") then
      name="스터드"
    elseif string.match(typetag, "^boarding_int.*") then
      name="보드"
    elseif string.match(typetag, "^core.*") then
      name="코어"
    elseif string.match(typetag, "^boarding_ext.*") then
      name="보드"
    elseif string.match(typetag, "^extstud.*") then
      name="스터드"
    elseif string.match(typetag, "^finish_ext.*") then
      name="외장재"
    end
  elseif lang=="pol" then    
    if string.match(typetag, "^finish_int.*") then
      name="PANEL"
    elseif string.match(typetag, "^intstud.*") then
      name="SŁUPEK"
    elseif string.match(typetag, "^boarding_int.*") then
      name="PŁYTA"
    elseif string.match(typetag, "^core.*") then
      name="RDZEŃ"
    elseif string.match(typetag, "^boarding_ext.*") then
      name="PŁYTA"
    elseif string.match(typetag, "^extstud.*") then
      name="SŁUPEK"
    elseif string.match(typetag, "^finish_ext.*") then
      name="OKŁADZINA"
    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" templatename_kor="보딩" templatename_pol="Płytowanie" id="[id]">
        <settings>
          <newelemboard>
            <layer>[layer;type=layer;default=AF Board]</layer>
			<elemparam name="pen">[elempen;prompt=Pen (empty=default);default=]</elemparam>
			<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]" openings="[add_openings;type=real;default=1]">
            <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" templatename_kor="마감재" templatename_pol="Panele" 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" templatename_kor="환기 수직" templatename_pol="Pionowe listwy wentylacyjne" 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" templatename_kor="환기 수평" templatename_pol="Poziome listwy wentylacyjne" 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>

						<!-- 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]">
							</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="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" templatename_kor="각진 부분이 있는 환기 수평" templatename_pol="Poziome listwy wentylacyjne z ukośnymi elementami" 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" templatename_kor="프레이밍" templatename_pol="Rama" 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" templatename_kor="프레이밍 메탈" templatename_pol="Rama metalowa" 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" templatename_kor="프레이밍 수평" templatename_pol="Rama poziomo" 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_bot;default=@zoff]" 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_top;default=@zoff]" 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ä" templatename_kor="프레이밍 수평 장변" templatename_pol="Rama pozioma długa" 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ä" templatename_kor="프레이밍 수평 장변 개구부 측면 절단" templatename_pol="Rama pozioma długa, boki otworów jako krótkie elementy" 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" templatename_kor="프레이밍 I-빔" templatename_pol="Rama z belek typu I" 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" templatename_kor="바닥/지붕 측면 포함" templatename_pol="Podłoga/dach z obrzeżami" 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" templatename_kor="바닥/지붕 측면 없음" templatename_pol="Podłoga/dach bez obrzeży" 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" templatename_kor="바닥/지붕 측면 없음 스터드 단변" templatename_pol="Podłoga/dach bez obrzeży, tylko krótkie elementy" 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" templatename_kor="바닥/지붕 수평 측면 없음" templatename_pol="Podłoga/dach poziomo bez obrzeży" 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ä" templatename_kor="바닥/지붕 측면 없음 장선 장변" templatename_pol="Podłoga/dach bez obrzeży belki długie" 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" templatename_kor="개구부 주변 골조" templatename_pol="Deski wokół otworów" 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ä" templatename_kor="수직 골조 고정 간격" templatename_pol="Deski pionowo stały odstęp" >
        <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ä" templatename_kor="수평 골조 고정 간격" templatename_pol="Deski poziomo stały odstęp" >
        <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" templatename_kor="프레이밍만, 절단 리스트에 가공 포함 v 1.0" templatename_pol="Tylko Rama i lista cięć z obróbkami v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="프레이밍만, 가공 포함 절단 리스트, 보는 방향 반대" templatename_pol="Tylko rama, lista cięć z obróbkami, odwrócony kierunek widoku" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="벽 프레임 + 외장재 밖에서 안으로 가공 포함 절단 리스트 v 1.0" id="[id]" templatename_pol="Rama ściany + okładziny zewnętrzne i wewnętrzne i lista cięć z obróbkami" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" content_kor="코어 밖에서" content_pol="RDZEŃ OD ZEWNĄTRZ" 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" templatename_kor="프레이밍만 바닥 + 지붕 가공 포함 절단 리스트 v 1.0" templatename_pol="Tylko rama podłoga+dach z listą cięć i obróbkami v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="멀티시트 외벽 밖에서 안으로 v 1.0" id="[id]" templatename_pol="Wielowarstwowa ściana zewnętrzna od zewnątrz do wewnątrz v 1.0" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" content_kor="코어 밖에서" content_pol="RDZEŃ OD ZEWNĄTRZ" 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" content_kor="윈드실드 보드 밖에서" content_pol="DESKI WIATROCHRONNE OD ZEWNĄTRZ" 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" content_kor="외장재 밖에서" content_pol="OKŁADZINY OD ZEWNĄTRZ" 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Ä" content_kor="단열재 밖에서" content_pol="IZOLACJA OD WEWNĄTRZ" 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Ä" content_kor="내부 스터딩 안쪽" content_pol="SŁUPKI WEWNĘTRZNE OD WEWNĄTRZ" 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" templatename_kor="멀티시트 안 밖 보드+스터드+프레임+보드+보드 1.0" templatename_pol="Struktura wielowarstwowa od wewnątrz do zewnątrz Płyty+Słupki+Rama+Płyty+Płyty 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="보드+프레임+보드에 절단 리스트 포함 1.0" templatename_pol="Płyty+Rama+Płyty z listą cięć 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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 -->


      <elemtemplate class="composite" templateid="frame_boardonly10" templatename="Just boarding/CLT cutlist having machinings v 1.0" templatename_fin="Vain levyt/CLT katkaisulista kolouksin v 1.0" templatename_kor="보딩만/CLT 절단 리스트 가공 포함 v 1.0" templatename_pol="Płyty/CLT z lictą cięć i obróbkami v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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>

        <!-- 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="common_boardonly_front"></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>


      <!-- 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" templatename_kor="멀티시트 안 밖 보드+보드+스터드 H+보드+프레임+보드+스터드+보드 1.0" templatename_pol="Struktura wielowarstwowa od wewnątrz na zewnątrz Płyty+Płyty+Słupki Poziomo+Płyty+Rama+Płyty+Słupki Poziomo+Płyty 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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]" cnc_wupsettings="[cnc_wupsettings]">
        <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" content_kor="코어 밖에서" content_pol="RDZEŃ OD ZEWNĄTRZ" 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" content_kor="윈드실드 보드 밖에서" content_pol="DESKI WIATROCHRONNE OD ZEWNĄTRZ" 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" content_kor="외장재 밖에서" content_pol="OKŁADZINY OD ZEWNĄTRZ" 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Ä" content_kor="보드1 밖에서" content_pol="PŁYTY1 OD WEWNĄTRZ" 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Ä" content_kor="보드2 밖에서" content_pol="PŁYTY2 OD WEWNĄTRZ" 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>



			<!-- Added 2024_09 BEG -->
			<elemtemplate class="composite" templateid="outin_bbbcbbb" templatename="Looked from out to in B+S+B+B+Core+S+B+B+B v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
				<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">

						<!-- ### LEFT COLUMN FROM INSIDE  -->
						<group layout="vertical">

							<!-- # Main frame only -->
							<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_text;default=CORE FROM OUTSIDE]" anchor="1" x="1" y="-0.5">
									<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,1,2,0.5" exclude="[core_exclude;default=intstud*,extstud*,finish*]" boardpanels="[core_boardpanels;default=core]">
									<dimlines>
										<dimline ref="an_framing_groupstuds"></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>
									<!-- Show ID for (insulation) boards -->
									<projplanksettings type="core" objtype="4">
										<objparam name="iShowID2D">1</objparam>
									</projplanksettings>
								</projection>

								<projection type="top" layoutmargins="1,1,0,0.5" boardpanels="[core_boardpanelstop;default=*]">
									<dimlines>
										<dimline ref="wall_top_groupstuds"></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 layout="horizontal">
									<cutlist layoutmargins="1,0.5,0.1,0.1" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="2">
										<luasettings>
											[lua_cutlist_coreall (empty or gListSettings.addmc=0);default=]
										</luasettings>
									</cutlist>
									<cutlist layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation" elemid="0" layoutminheight="2" create="[core_cutlist_insulation;default=0]">
									</cutlist>
								</group>
							</group>

							<!-- # Boarding ext 1 -->
							<group layout="vertical" create="[extboard1_create;default=1]">
								<text content="[extboard1_text;default=BOARD1 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[extboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard1_boardpanels;default=boarding_ext,boarding_ext2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards2" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding ext 2 -->
							<group layout="vertical" create="[extboard2_create;default=1]">
								<text content="[extboard2_text;default=BOARD2 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[extboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard2_boardpanels;default=boarding_ext3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards3" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Studding ext 1 -->
							<group layout="vertical" create="[extstud1_create;default=0]">
								<text content="[extstud1_text;default=STUDDING1 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[extstud1_exclude;default=intstud*,finish*]" boardpanels="[extstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_extstud1;prompt=dimline_extstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extstuds1" elemid="0" layoutminheight="2"></cutlist>
							</group>


							<!-- # Boarding ext 3 -->
							<group layout="vertical" create="[extboard3_create;default=1]">
								<text content="[extboard3_text;default=BOARD3 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[extboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard3_boardpanels;default=boarding_ext4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards4" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>


						<!-- ### RIGHT COLUMN FROM INSIDE -->
						<group>
							<!-- # Studding int 1 -->
							<group layout="vertical" create="[intstud1_create;default=0]">
								<text content="[intstud1_text;default=STUDDING1 FROM INSIDE]" anchor="1" x="1" y="-0.5">
									<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="1,1,1,0.5" exclude="[intstud1_exclude;default=extstud*,finish*]" boardpanels="[intstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_intstud1;prompt=dimline_intstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intstuds" elemid="0" layoutminheight="2"></cutlist>
							</group>


							<!-- # Boarding int 1 -->
							<group layout="vertical" create="[intboard1_create;default=1]">
								<text content="[intboard1_text;default=BOARD1 FROM INSIDE]" anchor="1" x="1" y="-0.5">
									<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="1,1,1,0.5" exclude="[intboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard1_boardpanels;default=boarding_int,boarding_int2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards2" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding int 2 -->
							<group layout="vertical" create="[intboard2_create;default=1]">
								<text content="[intboard2_text;default=BOARD2 FROM INSIDE]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[intboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard2_boardpanels;default=boarding_int3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards3" elemid="0" layoutminheight="2"></cutlist>
							</group>


							<!-- # Boarding int 3 -->
							<group layout="vertical" create="[intboard3_create;default=1]">
								<text content="[intboard3_text;default=BOARD3 FROM INSIDE]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[intboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard3_boardpanels;default=boarding_int4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards4" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>
					</group>
				</projections>
			</elemtemplate>
			
			<elemtemplate class="composite" templateid="inout_bbbcbbb" templatename="Looked from in to out B+B+B+S+Core+B+B+S+B v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
				<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">

						<!-- ### LEFT COLUMN FROM INSIDE  -->
						<group layout="vertical">

							<!-- # Main frame only -->
							<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_text;default=CORE FROM INSIDE]" anchor="1" x="1" y="-0.5">
									<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,1,2,0.5" exclude="[core_exclude;default=intstud*,extstud*,finish*]" boardpanels="[core_boardpanels;default=core]">
									<dimlines>
										<dimline ref="an_framing_groupstuds"></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>
									<!-- Show ID for (insulation) boards -->
									<projplanksettings type="core" objtype="4">
										<objparam name="iShowID2D">1</objparam>
									</projplanksettings>
								</projection>

								<projection type="top" layoutmargins="1,1,0,0.5" boardpanels="[core_boardpanelstop;default=*]">
									<dimlines>
										<dimline ref="wall_top_groupstuds"></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 layout="horizontal">
									<cutlist layoutmargins="1,0.5,0.1,0.1" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="2">
										<luasettings>
											[lua_cutlist_coreall (empty or gListSettings.addmc=0);default=]
										</luasettings>
									</cutlist>
									<cutlist layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation" elemid="0" layoutminheight="2" create="[core_cutlist_insulation;default=0]">
									</cutlist>
								</group>
							</group>

							<!-- # Studding int 1 -->
							<group layout="vertical" create="[intstud1_create;default=0]">
								<text content="[intstud1_text;default=STUDDING1 FROM INSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intstud1_exclude;default=extstud*,finish*]" boardpanels="[intstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_intstud1;prompt=dimline_intstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intstuds" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding int 1 -->
							<group layout="vertical" create="[intboard1_create;default=1]">
								<text content="[intboard1_text;default=BOARD1 FROM INSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard1_boardpanels;default=boarding_int,boarding_int2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards2" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding int 2 -->
							<group layout="vertical" create="[intboard2_create;default=1]">
								<text content="[intboard2_text;default=BOARD2 FROM INSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard2_boardpanels;default=boarding_int3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards3" elemid="0" layoutminheight="2"></cutlist>
							</group>


							<!-- # Boarding int 3 -->
							<group layout="vertical" create="[intboard3_create;default=1]">
								<text content="[intboard3_text;default=BOARD3 FROM INSIDE]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard3_boardpanels;default=boarding_int4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intboards4" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>


						<!-- ### RIGHT COLUMN FROM OUTSIDE -->
						<group>
							<!-- # Boarding ext 1 -->
							<group layout="vertical" create="[extboard1_create;default=1]">
								<text content="[extboard1_text;default=BOARD1 FROM OUTSIDE]" anchor="1" x="1" y="-0.5">
									<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="1,1,1,0.5" exclude="[extboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard1_boardpanels;default=boarding_ext,boarding_ext2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards2" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding ext 2 -->
							<group layout="vertical" create="[extboard2_create;default=1]">
								<text content="[extboard2_text;default=BOARD2 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard2_boardpanels;default=boarding_ext3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards3" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Studding ext 1 -->
							<group layout="vertical" create="[extstud1_create;default=0]">
								<text content="[extstud1_text;default=STUDDING1 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extstud1_exclude;default=intstud*,finish*]" boardpanels="[extstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_extstud1;prompt=dimline_extstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extstuds1" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding ext 3 -->
							<group layout="vertical" create="[extboard3_create;default=1]">
								<text content="[extboard3_text;default=BOARD3 FROM OUTSIDE]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard3_boardpanels;default=boarding_ext4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards4" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>
					</group>
				</projections>
			</elemtemplate>


			<elemtemplate class="composite" templateid="fromtop_bbbcbbb" templatename="Roofs/Floors looked from above B+B+B+S+Core+B+B+S+B v 1.0" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
				<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">

						<!-- ### LEFT COLUMN FROM INSIDE  -->
						<group layout="vertical">

							<!-- # Main frame only -->
							<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_text;default=CORE FROM TOP]" anchor="1" x="1" y="-0.5">
									<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,1,2,0.5" exclude="[core_exclude;default=intstud*,extstud*,finish*]" boardpanels="[core_boardpanels;default=core]">
									<dimlines>
										<dimline ref="an_framing_groupstuds"></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>
									<!-- Show ID for (insulation) boards -->
									<projplanksettings type="core" objtype="4">
										<objparam name="iShowID2D">1</objparam>
									</projplanksettings>
								</projection>

								<projection type="bottom" layoutmargins="1,1,0,0.5" boardpanels="[core_boardpanelstop;default=*]">
									<dimlines>
										<dimline ref="wall_top_groupstuds"></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 layout="horizontal">
									<cutlist layoutmargins="1,0.5,0.1,0.1" settingsref="cutlist_table_coreall" elemid="0" layoutminheight="2">
										<luasettings>
											[lua_cutlist_coreall (empty or gListSettings.addmc=0);default=]
										</luasettings>
									</cutlist>
									<cutlist layoutmargins="0,0.1,0.1,0.1" settingsref="cutlist_table_insulation" elemid="0" layoutminheight="2" create="[core_cutlist_insulation;default=0]">
									</cutlist>
								</group>
							</group>

							<!-- # Studding top 1 -->
							<group layout="vertical" create="[intstud1_create;default=0]">
								<text content="[intstud1_text;default=STUDDING1 FROM TOP]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intstud1_exclude;default=extstud*,finish*]" boardpanels="[intstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_intstud1;prompt=dimline_intstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_intstuds" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding TOP 1 -->
							<group layout="vertical" create="[intboard1_create;default=1]">
								<text content="[intboard1_text;default=BOARD1 FROM TOP]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard1_boardpanels;default=boarding_int,boarding_int2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[intboard1_cutlist;default=cutlist_table_intboards2]" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding int 2 -->
							<group layout="vertical" create="[intboard2_create;default=1]">
								<text content="[intboard2_text;default=BOARD2 FROM TOP]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard2_boardpanels;default=boarding_int3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[intboard2_cutlist;default=cutlist_table_intboards3]" elemid="0" layoutminheight="2"></cutlist>
							</group>


							<!-- # Boarding int 3 -->
							<group layout="vertical" create="[intboard3_create;default=1]">
								<text content="[intboard3_text;default=BOARD3 FROM TOP]" anchor="1" x="1" y="0">
									<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,1,0.5,0.5" exclude="[intboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[intboard3_boardpanels;default=boarding_int4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[intboard3_cutlist;default=cutlist_table_intboards4]" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>


						<!-- ### RIGHT COLUMN FROM BOTTOM -->
						<group>
							<!-- # Boarding ext 1 -->
							<group layout="vertical" create="[extboard1_create;default=1]">
								<text content="[extboard1_text;default=BOARD1 FROM BOTTOM]" anchor="1" x="1" y="-0.5">
									<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="1,1,1,0.5" exclude="[extboard1_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard1_boardpanels;default=boarding_ext,boarding_ext2]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[extboard1_cutlist;default=cutlist_table_extboards2]" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding ext 2 -->
							<group layout="vertical" create="[extboard2_create;default=1]">
								<text content="[extboard2_text;default=BOARD2 FROM BOTTOM]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extboard2_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard2_boardpanels;default=boarding_ext3]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[extboard2_cutlist;default=cutlist_table_extboards3]" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Studding ext 1 -->
							<group layout="vertical" create="[extstud1_create;default=0]">
								<text content="[extstud1_text;default=STUDDING1 FROM BOTTOM]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extstud1_exclude;default=intstud*,finish*]" boardpanels="[extstud1_boardpanels;default=]">
									<dimlines>
										<dimline ref="[dimline_extstud1;prompt=dimline_extstud1, framing_stud or horframing_stud;default=framing_stud]"></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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="[extstud1_cutlist;default=cutlist_table_extstuds1]" elemid="0" layoutminheight="2"></cutlist>
							</group>

							<!-- # Boarding ext 3 -->
							<group layout="vertical" create="[extboard3_create;default=1]">
								<text content="[extboard3_text;default=BOARD3 FROM BOTTOM]" anchor="1" x="1" y="0">
									<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="1,1,0.5,0.5" exclude="[extboard3_exclude;default=intstud*,extstud*,finish*]" boardpanels="[extboard3_boardpanels;default=boarding_ext4]">
									<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>
									</projplanksettings>
								</projection>
								<cutlist layoutmargins="1,0.5,0.1,0.1" layoutminwidth="2.50" settingsref="cutlist_table_extboards4" elemid="0" layoutminheight="2"></cutlist>
							</group>
						</group>
					</group>
				</projections>
			</elemtemplate>
			<!-- Added 2024_09 END -->


			<elemtemplate class="composite" templateid="composite_outin" templatename="Looked from out to in" templatename_fin="Katselusuunta ulkoa sisälle" templatename_kor="밖에서 안으로 보기" id="[id]" templatename_pol="Widziane od zewnątrz do wewnątrz" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="안에서 밖으로 보기"  templatename_pol="Widziane od wewnątrz do zewnątrz" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="밖에서 안으로 보기 싱글 프로젝션" templatename_pol="Widziane od zewnątrz do wewnątrz na jednym widoku" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="안에서 밖으로 보기 싱글 프로젝션" templatename_pol="Widziane od wewnątrz do zewnątrz na jednym widoku" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="바닥/지붕 위에서 보기" templatename_pol="Podłoga/dach widziane od góry" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" templatename_kor="프로젝션 없음" templatename_pol="bez widoków" id="[id]" idstamp="[idstamp]" cnc_elemtype="[cnc_elemtype]" cnc_wupsettings="[cnc_wupsettings]">
        <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" name_kor="상단 및 하단" name_pol="Góra i dół"/>
        <optiongroup id="mark" name="Markings" name_fin="Merkinnät" name_nor="Markings" name_por="Marcas" name_kor="마킹" name_pol="Oznaczenia"/>
        <optiongroup id="vert" name="Studding" name_fin="Tolpitus" name_nor="Studding" name_por="Studding" name_kor="스터딩" name_pol="Słupki"/>
        <optiongroup id="hor" name="Horizontal" name_fin="Vaakarakenteet" name_nor="Horizontal" name_por="Horizontal" name_kor="수평" name_pol="Poziomo"/>
        <optiongroup id="settings" name="Settings" name_fin="Asetukset" name_nor="Settings" name_por="Definições" name_kor="설정" name_pol="Ustawienia"/>
      </optiongroups>

			<!-- ordernum: Want to do before autosplitelem -->
			<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" name_kor="더블 탑" name_pol="`Zdwojona góra" ordernum="90">
        <!-- 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>

			<!-- ordernum: Want to do before autosplitelem -->
			<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" name_kor="더블 바텀" name_pol="Zdwojony dół" ordernum="90">
        <!-- 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" name_kor="상단 보크 후면" name_pol="Górna belka tył">
        <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" name_kor="상단 보크 전면" name_pol="Górna belka przód">
        <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" name_kor="하단 보크 후면" name_pol="Dolna belka tył" 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" name_kor="하단 보크 전면" name_pol="Dolna belka przód" 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" name_kor="전체 보강" name_pol="Wzmocnij wszystkie" 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" name_kor="벽 to 바닥 조인트 상단" name_pol="Połączenie górne ściany z podłogą" 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)" name_kor="스플릿 하단" name_pol="Dolna belka z dwóch elementów" 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" name_kor="홈 하단 2mm" name_pol="Wcięcia u dołu 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" name_kor="홈 상단 2mm" name_pol="Wcięcia u góry 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" name_kor="마킹 홈" name_pol="Oznaczenie wcięciami" 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" name_kor="마킹 선" name_pol="Oznaczenie liniami" 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" name_kor="개구부 측면에 골조" name_pol="Deski po bokach otworu" 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" name_kor="개구부 측면에 더블 스터딩" name_pol="Zdwojone słupki po bokach otworu" 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" name_kor="좌우로 더블 스터딩" name_pol="Zdwojone słupki na lewej i prawej krawędzi" 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)" name_kor="헤더 하중 없음 (활성화만 가능)" name_pol="Nadproże nieobciążone (tylko ustawienie)">
        <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)" name_kor="헤더 하중 있음 (활성화만 가능)" name_pol="Nadproże obciążone (tylko ustawienie)">
        <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" name_kor="헤더 선택된 피스에 맞춤" name_pol="Nadproża niestandardowe dla wybranych elementów" 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" name_kor="창문/문 틀 절단" name_pol="Przytnij próg/parapet Okna/Drzwi">
        <script ref="openingsbotcut">
        </script>
      </option>

			<!-- ordernum: Want to do after double top/bottom -->
      <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" name_kor="상단 및 하단 자동 절단" name_pol="Automatyczne cięcie górnych i dolnych słupków" ordernum="110">
        <reapply id="markingslines"></reapply>
        <reapply id="markings"></reapply> <!-- For Birkeland -->
        <reapply id="markingsgro"></reapply>
        <script ref="autocuttopbot">
        </script>
      </option>

			<option groupid="topbot" id="autosplitelem" name="Automatic split element" name_fin="Katko elementti automaattisesti" name_kor="자동 스플릿 요소" name_pol="Automatycznie przetnij element">
				<reapply id="markingslines"></reapply>
				<reapply id="markings"></reapply>
				<reapply id="markingsgro"></reapply>
				<reapply id="autocuttopbot"></reapply>
				<script ref="autosplitelem">
				</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" name_kor="개구부 지지대" name_pol="Słupki do krawędzi poziomej belki otworu">
        <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" name_kor="자동 절단 스터딩" name_pol="Automatyczne cięcie słupków">
        <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" name_kor="바닥 측면 피스" name_pol="Boczne belki podłogi" 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" name_kor="블록킹" name_pol="Poprzeczki przeciw wyboczeniu">
        <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" name_kor="보드 가장자리 지지대 전면" name_pol="Wspornik łączenia płyt z przodu" 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" name_kor="보드 가장자리 지지대 후면" name_pol="Wspornik łączenia płyt z tyłu" 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" name_kor="자동 개구부 모듈 ID" name_pol="Automatyczne ID modułów otworów">
        <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"  name_kor="요소 설정" name_pol="Ustawienia elementu">
        <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" name_kor="장변" name_pol="Długi1" 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" name_kor="장변2" name_pol="Długi2" 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" name_kor="장변3" name_pol="Długi3" 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_kor="장변 L 좌" name_pol="Długi L Lewy" 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" name_kor="장변 L 우" name_pol="Długi L Prawy">
        <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" name_kor="장변 L 좌 레이어드" name_pol="Długi L Lewy warstwowy">
        <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" name_kor="장변 L 우 레이어드" name_pol="Długi L Prawy warstwowy">
        <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" name_kor="장변 L 좌 레이어드 3" name_pol="Długi L Lewy warstwowy 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" name_kor="장변 L 우 레이어드 3" name_pol="Długi L Prawy warstwowy 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" name_kor="단변" name_pol="Krótki" 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"  name_kor="단변 3" name_pol="Krótki 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"  name_kor="직선"  name_pol="Prosty" 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"  name_kor="상단 및 하단 예시 1" name_pol="Góra i dół przykład 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"  name_kor="상단 및 하단 예시 2" name_pol="Góra i dół przykład 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"  name_kor="패널링 수직 밖에서 안으로" name_pol="Panele pionowo od zewnątrz do wewnątrz">
        <panel thickness="0.025" height="0.125" y1="0.025" y2="0.050" x1="0.000" x2="0.125">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_kor="패널링 수평 밖에서 안으로 23x145/135" name_pol="Panele poziomo od zewnątrz do wewnątrz 23x145/135"> 
        <panel id="PANEL 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_kor="패널링 수직 안에서 밖으로" name_pol="Panele pionowo od wewnątrz do zewnątrz">
        <panel thickness="0.1250" height="0.0250" x1="0.0000" x2="0.1250" y1="0.0000" y2="0.0250">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_kor="패널링 수평 안에서 밖으로 23x145/135" name_pol="Panele poziomo od wewnątrz do zewnątrz 23x145/135">
        <panel id="PANEL 23x135" thickness="0.023" height="0.145" y1="0.000" y2="0.023" x1="0.000" x2="0.135">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_kor="패널 홈 23x145/135" name_pol="Panele z wrębem od zewnątrz do wewnątrz 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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_kor="패널 홈 23x145/135 안 밖" name_pol="Panele z wrębem od wewnątrz do zewnątrz 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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele od zewnątrz do wewnątrz 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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele od wewnątrz do zewnątrz 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">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele od zewnątrz do wewnątrz 22x120/105">
        <panel id="Panel 22x120/105" thickness="0.022" height="0.120" y1="0.000" y2="0.022" x1="0.000" x2="0.105">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele od wewnątrz do zewnątrz 22x120/105">
        <panel id="Panel 22x120/105" thickness="0.022" height="0.120" y1="0.000" y2="0.022" x1="0.000" x2="0.105">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele bez wcięcia 15x120/110">
        <panel id="Panel 15x120/110" thickness="0.015" height="0.120" y1="0.000" y2="0.015" x1="0.000" x2="0.110">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="Panele bez wcięcia 14x120/110">
        <panel id="Panel 14x120/110" thickness="0.014" height="0.120" y1="0.000" y2="0.014" x1="0.000" x2="0.110">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="19x148/130 od zewnątrz do wewnątrz">
        <panel id="Panel 19x148/130" thickness="0.019" height="0.148" y1="0.000" y2="0.019" x1="0.000" x2="0.130">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="19x148/130 od wewnątrz do zewnątrz">
        <panel id="Panel 19x148/130" thickness="0.019" height="0.148" y1="0.000" y2="0.019" x1="0.000" x2="0.130">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="19x70/52 od zewnątrz do wewnątrz">
        <panel id="Panel 19x70/52" thickness="0.019" height="0.070" y1="0.000" y2="0.019" x1="0.000" x2="0.052">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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" name_pol="19x70/52 od wewnątrz do zewnątrz">
        <panel id="Panel 19x70/52" thickness="0.019" height="0.070" y1="0.000" y2="0.019" x1="0.000" x2="0.052">
					<!--settings>
						<objparam name="iMaxLen">3.800</objparam>
					</settings-->
					<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>
