JimAndi Toolbox: Difference between revisions

From SDK
Jump to navigation Jump to search
Tag: Manual revert
 
(308 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:SDK]]
[[Category:SDK]]
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
==Table and Array Tools==
==Table and Array Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


===ArrayClear===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
ArrayClear - Clears the data from a data array.
local tbl = {1, 2, 5, 6}


===ArrayClear===
tbl = ArrayClear(tbl)
<nowiki> ArrayClear - Clears the data from a data array.
a = {1, 2, 5, 6}
Words = ArrayClear(a) -- returns a = {}


  function ArrayClear(arrayName)
returns tbl = {}
  <nowiki> function ArrayClear(arrayName)
   for _,v in ipairs(arrayName) do
   for _,v in ipairs(arrayName) do
     table.remove(arrayName, i)
     table.remove(arrayName, i)
Line 15: Line 19:
   return true
   return true
   end -- function end </nowiki>
   end -- function end </nowiki>
----


===NameCheck===
===NameCheck===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Checks if Name is in the list of it is default name.


<nowiki> Checks if Name is in the list of it is default name.
a = {1, 2, 5, 6}
a = {1, 2, 5, 6}
 
Words = NameCheck(a, 5) -- returns true
Words = NameCheck(a, 5) -- returns true
function NameCheck(Name, Defalt, ListName)
  <nowiki> function NameCheck(Name, Defalt, ListName)
     if Name ~= Defalt then
     if Name ~= Defalt then
       for i=1, ListName do
       for i=1, ListName do
Line 33: Line 41:
     end
     end
   end -- function end </nowiki>
   end -- function end </nowiki>
----


===RemoveDuplicates===
===RemoveDuplicates===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns table of unique items in "A" acending or "D" decending
local tbl = {1, 2, 5, 3, 5, 6, 4}


<nowiki> Returns table of unique items in "A" acending or "D" decending
tbl = ArrayClear(tbl, "A")


  function RemoveDuplicates(tab, order)
returns tbl = {1, 2, 3, 4, 5, 6}
  <nowiki> function RemoveDuplicates(tab, order)
     local hashSet = {}
     local hashSet = {}
     local new = {}
     local new = {}
Line 57: Line 72:
   end -- function end </nowiki>
   end -- function end </nowiki>


===RemoveTableItem===
----
 
===RemoveTableItem===  
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns table with item removed.
 
local tbl = {1, 2, 3, 4, 5, 6}


  <nowiki> function RemoveTableItem(tabName, tabItem)
tbl = RemoveTableItem(tbl, 4)
 
returns tbl = {1, 2, 3, 5, 6}
 
  <nowiki> function RemoveTableItem(tabName, tabItem)
     for x = 1 in ipairs(tabName) do
     for x = 1 in ipairs(tabName) do
       if tabName[x] == tabItem then
       if tabName[x] == tabItem then
Line 67: Line 92:
     return true
     return true
   end -- function end </nowiki>
   end -- function end </nowiki>
----


===TableLength===
===TableLength===


  <nowiki> function TableLength(tbl)                               -- tbl returns table count
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
 
  <nowiki> Returns table item count
local tbl = {1, 2, 3, 4, 5, 6}
tbl = TableLength(tbl)
 
returns tbl = 6
-- =====================================================]]
  function TableLength(tbl)
     -- tbl = {7, 6, 5, 4, 3, 2, 1}
     -- tbl = {7, 6, 5, 4, 3, 2, 1}
     local count = 0
     local count = 0
Line 78: Line 112:
     return count
     return count
   end -- function end </nowiki>
   end -- function end </nowiki>
----


===FindDups===
===FindDups===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Find all duplicate items and returns two tables the dup and clean tables
Returns table item count


  <nowiki> Find all duplicate items and returns both dup and clean tables
local tbl = {1, 2, 2, 4, 4, 6}
  function FindDups(checktbl, duptbl, cleantbl)           --
 
local tbl1 = {}
 
local tbl2 = {}
 
tbl1, tbl2 = TableLength(tbl)
 
returns tbl1, tbl2 = 6
  <nowiki> function FindDups(checktbl, duptbl, cleantbl)
     function tLength(tbl) -- tLength returns table count
     function tLength(tbl) -- tLength returns table count
       local count = 0
       local count = 0
Line 105: Line 153:
       trip = false
       trip = false
     end
     end
     return table.sort(duptbl), table.sort(cleantbl) -- returns both dup and clean table
     return table.sort(duptbl), table.sort(cleantbl)
   end -- function end </nowiki>
   end -- function end </nowiki>
----


===ReverseTable===
===ReverseTable===


  <nowiki> function ReverseTable(tbl)                             -- Reverse table order
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
 
Returns a reversed table
 
local tbl = {1, 2, 3, 4, 5, 6}
 
tbl = ReverseTable(tbl)
 
returns tbl = {6, 5, 4, 3, 2, 1}
 
  <nowiki> function ReverseTable(tbl)
     --tbl = {7, 6, 7, A, 5, 4, 3, A, 2, 1}
     --tbl = {7, 6, 7, A, 5, 4, 3, A, 2, 1}
     local n = #tbl
     local n = #tbl
Line 121: Line 181:
     return tbl
     return tbl
   end -- function end </nowiki>
   end -- function end </nowiki>
----


==Conversion Tools==
==Conversion Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This collection of functions that assist in the conversion activities.
 
===Bool2Str===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> bool2Str - Converts true or false as a string.
local x = true
tbl = bool2Str(x)
-- =====================================================]]
returns "true"
  function Bool2Str(x)
    if x then
      return "true"
    else
      return "false"
    end
  end --function end </nowiki>
 
----


<nowiki>
===D2S8===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  D2S8 - Converts a Number (Double) to a String with 8 places
   
   
  <nowiki>function D2S8(d)                              -- Converts a Number (Double) to a String with 8 places
-- local x =12.2351
-- returns "12.23510000"
-- =====================================================]]
-- =====================================================]]
╔═╗╔═╗╔╗╔╦  ╦╔═╗╦═╗╔╦╗╦╔═╗╔╗╔  ╔╦╗╔═╗╔═╗╦  ╔═╗
    return string.format("%.8f", d)
║  ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ ║║ ║║║║   ║ ║ ║║ ║║  ╚═╗
   end -- end function </nowiki>
╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ╩╚═╝╝╚╝  ╩ ╚═╝╚═╝╩═╝╚═╝
 
function ConvertingTools()
----
-- ====================================================]]
 
function bool2S(x)                                     -- Converts true or false to text
===D2S4===
   if x then
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    return "true"
<nowiki> D2S4 - Converts a Number (Double) to a String with 4 places
  else
local x =12.23
    return "false"
   = D2S4(x)
  end
 
end --function end
returns x = "12.2300"
-- =====================================================]]
-- =====================================================]]
function D2S8(d)                                       --  Converts a Number (Double) to a String with 8 places
  function D2S4(d)  
  return string.format("%.8f", d)
    return string.format("%.4f", d)
end -- function end
  end -- end function </nowiki>
-- =====================================================]]
 
function D2S4(d)                                        -- Converts a Number (Double) to a String with 4 places
----
   return string.format("%.4f", d)
 
end -- function end
===Toint===
-- =====================================================]]
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
function toint(number)
<nowiki> Toint - Converts a Double Number to a intiger
  return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
local x = 12.23
end
   = toint(x)
 
returns x = 12
  function toint(number)
    return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
  end -- end function </nowiki>
 
----
 
===Rounder===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
 
  return tonumber(string.format("%." .. (idp or 0) .. "f", n
<nowiki>
-- =====================================================]]
-- =====================================================]]
function Rounder(num, idp)                              --  Rounds a Number (Double) up or down
function Rounder(num, idp)                              --  Rounds a Number (Double) up or down
   return tonumber(string.format("%." .. (idp or 0) .. "f", num))
   return tonumber(string.format("%." .. (idp or 0) .. "f", num))
end -- end function
end -- end function </nowiki>
 
----
 
===RUsame===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki>
-- =====================================================]]
-- =====================================================]]
function RUsame(num, comp)                              --  Rounds a Number (Double) up or down
function RUsame(num, comp)                              --  Rounds a Number (Double) up or down
Line 174: Line 278:
     return false
     return false
   end -- if end
   end -- if end
end -- end function
end -- end function </nowiki>
-- =====================================================]]
 
function WithIn(Num, Mat, Tol)                         --  Retuns true if number is within tolerance with match
===WithIn===
  if ((Num >= (Mat - Tol)) and (Num <= (Mat + Tol))) then
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    return true
Retuns true if number is within tolerance with match
  end -- if end
 
  return false
 
end -- end function
<nowiki> function WithIn(Num, Mat, Tol)
-- =====================================================]]
    if ((Num >= (Mat - Tol)) and (Num <= (Mat + Tol))) then
function Double2Fraction(Num)                          --  Converts a Measurement (Double) to a Fractional String
      return true
    end -- if end
    return false
  end -- end function </nowiki>
 
----
 
===Double2Fraction===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Converts a Measurement (Double) to a Fractional String
 
local txt = Double2Fraction(1.25)
 
returns txt ="1-1/4"
<nowiki> function Double2Fraction(Num)
   local Frac = "Error"
   local Frac = "Error"
   if Num then
   if Num then
Line 355: Line 473:
   end
   end
   return Frac
   return Frac
end -- function end
end -- end function </nowiki>
-- =====================================================]]
end -- Convert Tools end


</nowiki>
----


==Time and Date Tools==
==Time and Date Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This collection of functions are utilized in the date and time calculations.
 
===StartDateTime===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
StartDateTime - Returns the Date and Time.
 
local dt= StartDateTime(true)
 
returns tbl = "10/02/23"


  <nowiki>  
  <nowiki>  function StartDateTime(LongShort)
-- =====================================================]]
╔╦╗╦╔╦╗╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║ ║║║║║╣    ║ ║ ║║ ║║  ╚═╗
╩ ╩╩ ╩╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DateTimeTools()
-- =====================================================]]
   function StartDateTime(LongShort)
--[[ Date Value Codes
--[[ Date Value Codes
--  |   %a  abbreviated weekday name (e.g., Wed)
--  |   %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %b  abbreviated month name (e.g., Sep)
Line 397: Line 514:
       return os.date("%Y%m%d%H%M")
       return os.date("%Y%m%d%H%M")
     end
     end
   end
   end </nowiki>
-- =====================================================]]
 
   function StartDate(LongShort)
----
 
===StartDate===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
StartDate - Returns the Date and Time.
 
local dt= StartDate(true)
 
returns tbl = "10/02/23"
   <nowiki> function StartDate(LongShort)
--[[ Date Value Codes
--[[ Date Value Codes
--  |   %a  abbreviated weekday name (e.g., Wed)
--  |   %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %b  abbreviated month name (e.g., Sep)
Line 425: Line 551:
       return os.date("%Y%m%d")    -- "20220901"
       return os.date("%Y%m%d")    -- "20220901"
     end
     end
   end
   end </nowiki>
-- ====================================================]]
 
function Wait(time)
----
 
===Wait===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Wait - Waits for a duration.
 
local dt = Wait(true)
 
returns tbl = "10/02/23"
 
  <nowiki> function Wait(time)
     local duration = os.time() + time
     local duration = os.time() + time
     while os.time() < duration do end
     while os.time() < duration do end
end
    end
-- =====================================================]]
end -- function end </nowiki>
end -- Date Time Tools function end


</nowiki>
----


==Debugging Tools==
==Debugging Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This collection of functions assist in the debugging of code.
 
===DMark - places a circle and notation to assist in geometry debugging===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Draws a circle and marks on the drawing for debugging purposes.
 
call = DebugMarkPoint("Note: Hi", Pt1)


  <nowiki>  
  <nowiki> function DMark(Note, Pt)
-- =====================================================]]
   -- ==== Sub Function
╔╦╗╔═╗╔╗ ╦ ╦╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╣ ╠╩╗║ ║║ ╦  ║ ║ ║║ ║║  ╚═╗
═╩╝╚═╝╚═╝╚═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DebugTools()
-- =====================================================]]
  function DMark(Note, Pt)
   --[[-- ==MarkPoint==
    | Code sourced from Vectric Lua Interface for Gadgets, version 2.05, published September 12, 2018. by Vectric Ltd.
    | Draws mark on the drawing
    | call = DebugMarkPoint("Note: Hi", Pt1)
    ]]
     local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
     local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
  --[[ draws a circle based on user inputs
    | job - current validated job unique ID
    | Cpt - (2Dpoint) center of the circle
    | CircleRadius - radius of the circle
    | Layer - layer name to draw circle (make layer if not exist)
    ]]
       local pa  = Polar2D(Cpt, 180.0, CircleRadius)
       local pa  = Polar2D(Cpt, 180.0, CircleRadius)
       local pb  = Polar2D(Cpt,  0.0, CircleRadius)
       local pb  = Polar2D(Cpt,  0.0, CircleRadius)
Line 467: Line 592:
       return true
       return true
     end -- function end
     end -- function end
   -- ====]]
   -- ====
     local BubbleSize = 1.25
     local BubbleSize = 1.25
     if not Project.DebugAngle then
     if not Project.DebugAngle then
Line 495: Line 620:
     end
     end
     return true
     return true
   end -- function end
   end -- function end </nowiki>
-- =====================================================]]
 
function StatusMessage(Type, Header, Question, ErrorNumber)
----
  --[[
 
  Useage:          type    Header Info              Question or Message                                 Err No.
===StatusMessage===
    StatusMessage("Error", "Base Cabinet Settings", "Face Frame Bottom Rail Width - value cannot be 0.", "(9000)")
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    Note: if the debug flag is on (true) a message box shows the message length, dialog size and error number
Useage: (Type of Message, Dialog Header, Question or Message, Err No.)
  ]]
 
StatusMessage("Error", "Base Cabinet Settings", "Face Frame Bottom Rail Width - value cannot be 0.", "(9000)")
 
Note: if the debug flag is on (true) a message box shows the message length, dialog size and error number
<nowiki>function StatusMessage(Type, Header, Question, ErrorNumber)
 
   local dialog
   local dialog
   local X = 460
   local X = 460
Line 549: Line 679:
   end
   end
   return true
   return true
end
end </nowiki>
-- =====================================================]]
 
  function DebugMarkPoint(Note, Pt, Size, LayerName)
----
  --[[-- ==MarkPoint==
 
  | Code sourced from Vectric Lua Interface for Gadgets, version 2.05, published September 12, 2018. by Vectric Ltd.
 
  | Draws mark on the drawing
===DebugMarkPoint===
  | call = DebugMarkPoint("Note: Hi", Pt1, 0.125, "Jim")
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  ]]
Used in debugging drawing issues - Draws a Circle and Text at the provided point(x,y)  
 
call = DebugMarkPoint("Note: Hi", Pt1, 0.125, "Jim")
<nowiki>function DebugMarkPoint(Note, Pt, Size, LayerName)
     if Size == nil then
     if Size == nil then
       Size = 0.125
       Size = 0.125
Line 563: Line 696:
       LayerName = "Debug"
       LayerName = "Debug"
     end
     end
  -- ==== Sub Function
     local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
     local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
  -- | draws a circle based on user inputs
  -- | job - current validated job unique ID
  -- | Cpt - (2Dpoint) center of the circle
  -- | CircleRadius - radius of the circle
  -- | Layer - layer name to draw circle (make layer if not exist)
       local pa = Polar2D(Cpt, 180.0, CircleRadius)
       local pa = Polar2D(Cpt, 180.0, CircleRadius)
       local pb = Polar2D(Cpt,  0.0, CircleRadius)
       local pb = Polar2D(Cpt,  0.0, CircleRadius)
Line 576: Line 705:
       layer:AddObject(CreateCadContour(line), true)
       layer:AddObject(CreateCadContour(line), true)
       return true
       return true
     end -- function end
     end -- sub function end
   -- ====]]
   -- ====
     local job = VectricJob()
     local job = VectricJob()
     local Pt1 = Polar2D(Pt, Project.DebugAngle, Size * 2.0)
     local Pt1 = Polar2D(Pt, Project.DebugAngle, Size * 2.0)
Line 591: Line 720:
     DrawCircle(job, Pt, Size, LayerName)
     DrawCircle(job, Pt, Size, LayerName)
     return true
     return true
   end -- function end
   end -- function end </nowiki>
-- =====================================================]]
 
  function ShowDialogSize()                            -- Returns Dialog X and Y size
----
 
===ShowDialogSize===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function ShowDialogSize()
     DisplayMessageBox(tostring(dialog.WindowWidth) .. " x " ..  tostring(dialog.WindowHeight))
     DisplayMessageBox(tostring(dialog.WindowWidth) .. " x " ..  tostring(dialog.WindowHeight))
   end -- function end
   end -- function end</nowiki>
-- =====================================================]]
end -- End Debug


</nowiki>
----


==Dialog and Menu Tools==
==Dialog and Menu Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document.


<nowiki>
===DialogSize===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
-- =====================================================]]
Returns Dialog size in a message box showing the X and Y vaalues.
╔╦╗╦╔═╗╦  ╔═╗╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
  <nowiki> function DialogSize(Str)                                -- Returns the X and Y value of the dialogue
  ║║║╠═╣║  ║ ║║ ╦  ║ ║ ║║ ║║  ╚═╗
═╩╝╩╩ ╩╩═╝╚═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DialogTools()
-- =====================================================]]
function DialogSize(Str)                                -- Returns the X and Y value of the dialogue
   local InText = string.find(string.upper(Str) , "X")
   local InText = string.find(string.upper(Str) , "X")
   local DialogX = All_Trim(string.sub(Str, 1, InText - 1))
   local DialogX = All_Trim(string.sub(Str, 1, InText - 1))
   local DialogY = All_Trim(string.sub(Str, InText + 1))
   local DialogY = All_Trim(string.sub(Str, InText + 1))
   return tonumber(DialogX), tonumber(DialogY)
   return tonumber(DialogX), tonumber(DialogY)
end -- end function
end -- function end</nowiki>
-- =====================================================]]
 
function ProgressBarAmount(TotalRecords, Record)        -- Calculates the percent amount of progression based on total process
----
 
===ProgressBarAmount===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function ProgressBarAmount(TotalRecords, Record)        -- Calculates the percent amount of progression based on total process
   --[[
   --[[
   local MyProgressBar
   local MyProgressBar
Line 629: Line 762:
     MyProgressBar:Finished()                                                  -- Close Progress Bar
     MyProgressBar:Finished()                                                  -- Close Progress Bar
   ]]
   ]]
  local X1 = (100.0 / TotalRecords)
    local X1 = (100.0 / TotalRecords)
  local X2 = X1 * Record
    local X2 = X1 * Record
  local X3 = math.abs(X2)
    local X3 = math.abs(X2)
  local X4 = (math.floor(X3))
    local X4 = (math.floor(X3))
  return (math.floor(math.abs((100.0 / TotalRecords) * Record)))
    return (math.floor(math.abs((100.0 / TotalRecords) * Record)))
end -- function end
  end -- function end</nowiki>
-- =====================================================]]
 
function OnLuaButton_InquiryGearCalulate(dialog)
----
 
===OnLuaButton_InquiryGearCalulate===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function OnLuaButton_InquiryGearCalulate(dialog)
   Gear.Addendum        = dialog:GetDoubleField("Gear.Addendum")
   Gear.Addendum        = dialog:GetDoubleField("Gear.Addendum")
   Gear.Dedendum        = dialog:GetDoubleField("Gear.Dedendum")
   Gear.Dedendum        = dialog:GetDoubleField("Gear.Dedendum")
Line 662: Line 800:


   return true
   return true
end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function InquiryDropList(Header, Quest, DX, DY, DList)
----
 
===InquiryDropList===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryDropList(Header, Quest, DX, DY, DList)
--[[
--[[
     Drop list foe user input
     Drop list foe user input
Line 687: Line 830:
       return dialog:GetDropDownListValue("ListBox")
       return dialog:GetDropDownListValue("ListBox")
     end
     end
end
end -- function end</nowiki>
-- =====================================================]]
 
function InquiryFileBox(Header, Quest, DefaltPath)
----
 
===InquiryFileBox===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryFileBox(Header, Quest, DefaltPath)
--[[
--[[
     Dialog Box for user to pick a file
     Dialog Box for user to pick a file
Line 725: Line 873:
       return dialog:GetTextField("ReadFile")
       return dialog:GetTextField("ReadFile")
     end -- if end
     end -- if end
end -- function end
  end -- function end</nowiki>
-- =====================================================]]
 
function InquiryPathBox(Header, Quest, DefaltPath)
----
 
===InquiryPathBox===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryPathBox(Header, Quest, DefaltPath)
--[[
--[[
     Number Box for user input with default value
     Number Box for user input with default value
Line 763: Line 916:
       return dialog:GetTextField("DInput")
       return dialog:GetTextField("DInput")
     end -- if end
     end -- if end
  end -- function end
  end -- function end</nowiki>
-- =====================================================]]
 
function InquiryAreYouSureYesNo(Header, Question1, Question2)
----
 
===InquiryAreYouSureYesNo===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryAreYouSureYesNo(Header, Question1, Question2)
  --[[
  --[[
     Drop list for user to input project info
     Drop list for user to input project info
Line 785: Line 943:
       return true
       return true
     end
     end
  end
  end -- function end</nowiki>
-- =====================================================]]
 
function InquiryDoubleBox(Header, Quest, DefaltN)
----
 
===InquiryDoubleBox===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryDoubleBox(Header, Quest, DefaltN)
--[[
--[[
-- nquiryNumberBox for user input with default number value
-- nquiryNumberBox for user input with default number value
Line 805: Line 968:
     return dialog:GetDoubleField("NumberInput")
     return dialog:GetDoubleField("NumberInput")
   end
   end
end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function InquiryIntegerBox(Header, Quest, DefaltI)
----
 
===InquiryIntegerBox===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryIntegerBox(Header, Quest, DefaltI)
--[[
--[[
-- InquiryIntegerBox for user input with default number value
-- InquiryIntegerBox for user input with default number value
Line 825: Line 993:
     return dialog:GetIntegerField("IntegerInput")
     return dialog:GetIntegerField("IntegerInput")
   end
   end
end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function InquiryTextgBox(Header, Quest, DefaltS)
----
 
===InquiryTextgBox===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function InquiryTextgBox(Header, Quest, DefaltS)
--[[
--[[
-- InquiryStringBox for user input with default number value
-- InquiryStringBox for user input with default number value
Line 845: Line 1,018:
     return dialog:GetTextField("NumberInput")
     return dialog:GetTextField("NumberInput")
   end
   end
end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function OnLuaButton_InquiryError(Message)
----
 
===OnLuaButton_InquiryError===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function OnLuaButton_InquiryError(Message)
     --[[
     --[[
     Provides user information on an Error
     Provides user information on an Error
Line 864: Line 1,042:
   WriteRegistry()
   WriteRegistry()
   return  true
   return  true
end
end -- function end</nowiki>
-- =====================================================]]
 
function PresentMessage(Header, Type, Line)
----
 
===PresentMessage===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function PresentMessage(Header, Type, Line)
     --[[
     --[[
     Provides user information on an Error
     Provides user information on an Error
Line 883: Line 1,066:
   dialog:ShowDialog()
   dialog:ShowDialog()
   return  true
   return  true
end
end -- function end</nowiki>
-- =====================================================]]
 
function OnLuaButton_InquiryAbout()
===OnLuaButton_InquiryAbout===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function OnLuaButton_InquiryAbout()
local myHtml = [[<html><head><title>About</title>]] .. DialogWindow.Style ..[[</head><body text = "#000000"><table width="680" border="0" cellpadding="0"> <tr> <td align="center" nowrap="nowrap" class="header1-c" id="SysName">Easy Cabinet Maker</td> </tr> <tr> <td align="center" nowrap="nowrap" id="Version" class="ver-c">Version</td> </tr> <tr> <td align="center" nowrap="nowrap"><hr></td> </tr> <tr> <td align="center" nowrap="nowrap" class="header2-c">Disclaimer</td> </tr> <tr> <td align="center" class="p1-l"><p class="p1-l">The ]] .. Dovetail.AppName .. [[ Gadget is a plugin for Vectric software, V-Carve Pro and Aspire.<br> Gadgets are an entirely optional add-in to Vectric's core software products.<br> They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.<br> In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.<br> <br> Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:<br> 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.<br> * If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.<br> 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.<br> 3. This notice may not be removed or altered from any source distribution.<br> <br>The author heavily utilized the SDK documentation and supplied code samples in addition to the outstanding user community on the Vectric User forum.</p></td> </tr> <tr> <td align="center"><a href="https://forum.vectric.com" class="webLink-c">Vectric User Forum</a></td> </tr> <tr> <td align="center"><span class="header2-c">JimAndi</span></td> </tr> <tr> <td align="center"><span class="h1-c">Houston, TX.</span></td> </tr> <tr> <td><hr></td> </tr> <tr> <td width="30%" align="center" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td> </tr></table></body></html>]]
local myHtml = [[<html><head><title>About</title>]] .. DialogWindow.Style ..[[</head><body text = "#000000"><table width="680" border="0" cellpadding="0"> <tr> <td align="center" nowrap="nowrap" class="header1-c" id="SysName">Easy Cabinet Maker</td> </tr> <tr> <td align="center" nowrap="nowrap" id="Version" class="ver-c">Version</td> </tr> <tr> <td align="center" nowrap="nowrap"><hr></td> </tr> <tr> <td align="center" nowrap="nowrap" class="header2-c">Disclaimer</td> </tr> <tr> <td align="center" class="p1-l"><p class="p1-l">The ]] .. Dovetail.AppName .. [[ Gadget is a plugin for Vectric software, V-Carve Pro and Aspire.<br> Gadgets are an entirely optional add-in to Vectric's core software products.<br> They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.<br> In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.<br> <br> Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:<br> 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.<br> * If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.<br> 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.<br> 3. This notice may not be removed or altered from any source distribution.<br> <br>The author heavily utilized the SDK documentation and supplied code samples in addition to the outstanding user community on the Vectric User forum.</p></td> </tr> <tr> <td align="center"><a href="https://forum.vectric.com" class="webLink-c">Vectric User Forum</a></td> </tr> <tr> <td align="center"><span class="header2-c">JimAndi</span></td> </tr> <tr> <td align="center"><span class="h1-c">Houston, TX.</span></td> </tr> <tr> <td><hr></td> </tr> <tr> <td width="30%" align="center" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td> </tr></table></body></html>]]
   local dialog = HTML_Dialog(true, myHtml, 720, 468, "About")
   local dialog = HTML_Dialog(true, myHtml, 720, 468, "About")
Line 893: Line 1,079:
   Project.AboutXY = tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight)
   Project.AboutXY = tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight)
   return  true
   return  true
end
end -- function end</nowiki>
-- =====================================================]]
 
function Color_HTML ()
----
 
 
===Color_HTML ===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function Color_HTML ()
   MessageBox(" X = " .. tostring(dialog.WindowWidth) ..
   MessageBox(" X = " .. tostring(dialog.WindowWidth) ..
             " Y = " .. tostring(dialog.WindowHeight)
             " Y = " .. tostring(dialog.WindowHeight)
Line 933: Line 1,125:
</table>
</table>
]] -- end HTML
]] -- end HTML
end -- HTML Function end
end -- function end</nowiki>
-- =====================================================]]
 
function Style ()
----
 
 
===Style===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function Style()
-- =====================================================]]
-- =====================================================]]
DialogWindow.Style = [[ <style>
DialogWindow.Style = [[ <style>
Line 1,226: Line 1,424:
}
}
</style>]]
</style>]]
end
end -- function end</nowiki>
-- =====================================================]]
 
function Orgin ()                                      -- Anchor Point
----
 
===Orgin===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function Orgin()                                      -- Anchor Point
-- ================================
-- ================================
   DialogWindow.Orgin = [[<table><tr><td colspan="2" class="h2-l">Anchor Point</td></tr><tr class="MyLeft"><td class="MyLeft"><table class="MyCenter"><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V1"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V2"></td></tr><tr><td class="auto-style9">|</td><td><input type="radio" name="DrawingOrigin" checked="checked" value="V3"></td><td valign="top">|</td></tr><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V4"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V5"></td></tr></table></td><td width="81%"><table><tr class="MyLeft"><td>X</td><td><input name="OriginX0" type="text" id="OriginX" size="8" maxlength="8"></td></tr><tr class="MyLeft"><td>Y</td><td><input name="OriginY0" type="text" id="OriginY" size="8" maxlength="8"></td></tr></table></td></tr></table>]]
   DialogWindow.Orgin = [[<table><tr><td colspan="2" class="h2-l">Anchor Point</td></tr><tr class="MyLeft"><td class="MyLeft"><table class="MyCenter"><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V1"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V2"></td></tr><tr><td class="auto-style9">|</td><td><input type="radio" name="DrawingOrigin" checked="checked" value="V3"></td><td valign="top">|</td></tr><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V4"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V5"></td></tr></table></td><td width="81%"><table><tr class="MyLeft"><td>X</td><td><input name="OriginX0" type="text" id="OriginX" size="8" maxlength="8"></td></tr><tr class="MyLeft"><td>Y</td><td><input name="OriginY0" type="text" id="OriginY" size="8" maxlength="8"></td></tr></table></td></tr></table>]]
end -- HTML Function end
end -- function end</nowiki>
-- =====================================================]]
 
function GetColor(str)                                  -- returns the RGB value for the standard color names
----
 
 
===GetColor===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function GetColor(str)                                  -- returns the RGB value for the standard color names
-- str = "Purple"
-- str = "Purple"
-- returns = 128 0 128
-- returns = 128 0 128
Line 1,263: Line 1,472:
     end
     end
     return Red, Green, Blue
     return Red, Green, Blue
  end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function StatusMessage(Type, Header, Question, length) -- Standardize messaging dialogues
----
 
 
===StatusMessage===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y vaalues.
<nowiki> function StatusMessage(Type, Header, Question, length) -- Standardize messaging dialogues
   -- StatusMessage("Alert",    "Alert Test",    "This is a test of Alert",    165)
   -- StatusMessage("Alert",    "Alert Test",    "This is a test of Alert",    165)
   -- StatusMessage("Question", "Question Test",  "This is a test of Question", 165)
   -- StatusMessage("Question", "Question Test",  "This is a test of Question", 165)
Line 1,298: Line 1,513:
   dialog:ShowDialog()
   dialog:ShowDialog()
   return true
   return true
end
end -- function end </nowiki>
-- =====================================================]]
end -- Dialog Tools function end


===DialogStringChecks===
<nowiki>function DialogStringChecks()
  local MyTrue = false
  if Milling.LNBottomProfile == "" then
    MessageBox("Error: Bottom Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSideProfile  == "" then
    MessageBox("Error: Side Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSidePocket  == "" then
    MessageBox("Error: Side Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontProfile == "" then
    MessageBox("Error: Front Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontPocket  == "" then
    MessageBox("Error: Front Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackProfile  == "" then
    MessageBox("Error: Back Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackPocket == "" then
    MessageBox("Error: Back Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNDrawNotes == "" then
    MessageBox("Error: Draw Notes layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNPartLabels == "" then
    MessageBox("Error: Part Lables layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBlume == "" then
    MessageBox("Error: Blume layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Project.ProjectName == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactEmail  == "" then
    MessageBox("Error: Contact Email cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactName == "" then
    MessageBox("Error: Contact Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactPhoneNumber == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.DrawerID == "" then
    MessageBox("Error: Contact Phone Number cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ProjectPath == "" then
    MessageBox("Error: Project Path cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  else
    MyTrue = true
  end -- if end
  return MyTrue
end -- function end</nowiki>
----
==Directory and File Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document.


</nowiki>
----
 
==Directory and File Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
-- =====================================================]]
╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╠╦╝║╣ ║  ║ ║ ║╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function DirectoryTools()
-- =====================================================]]
  function MakeFolder(xPath)
    os.execute( "mkdir  " .. xPath)
    return true
  end -- function end
-- =====================================================]]
  function PathFix(xPath)
    return string.gsub(xPath, "\\", "/")
  end -- function end
-- =====================================================]]
  function FileExists(name)
-- FileExists(name
-- DisplayMessageBox(name)
    local f=io.open(name,"r")
    if f~=nil then
      io.close(f)
      return true
    else
      return false
    end
  end -- function end
-- =====================================================]]
  function DirectoryProcessor(job, dir_name, filter, do_sub_dirs, function_ptr)
      local num_files_processed = 0
      local directory_reader = DirectoryReader()
      local cur_dir_reader = DirectoryReader()
      directory_reader:BuildDirectoryList(dir_name, do_sub_dirs)
      directory_reader:SortDirs()
      local number_of_directories = directory_reader:NumberOfDirs()
      for i = 1, number_of_directories do
        local cur_directory = directory_reader:DirAtIndex(i)
        -- get contents of current directory
        -- dont include sub dirs, use passed filter
        cur_dir_reader:BuildDirectoryList(cur_directory.Name, false)
        cur_dir_reader:GetFiles(filter, true, false)
        -- call passed method for each file:
        local num_files_in_dir = cur_dir_reader:NumberOfFiles()
        for j=1, num_files_in_dir  do
          local file_info = cur_dir_reader:FileAtIndex(j)
          if not function_ptr(job, file_info.Name) then
            return true
          end -- if end
          num_files_processed = num_files_processed + 1
        end -- for end
        -- empty out our directory object ready for next go
        cur_dir_reader:ClearDirs()
        cur_dir_reader:ClearFiles()
      end -- for end
      return num_files_processed
  end -- function end
-- =====================================================]]
end -- Directory Tools end
 


</nowiki>
===MakeFolder()===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Returns Dialog size in a message box showing the X and Y values.
<nowiki> function MakeFolder(xPath)
    os.execute( "mkdir  " .. xPath)
    return true
  end -- function end</nowiki>


==Drawing Tools==
----
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


 
===PathFix()===
  <nowiki> </nowiki>
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
-- =====================================================]]
  <nowiki> function PathFix(xPath)              -- Returns path with /
╔╦╗╦═╗╔═╗╦ ╦╦╔╗╔╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
    return string.gsub(xPath, "\\", "/")
<nowiki> </nowiki>║║╠╦╝╠═╣║║║║║║║║ ╦  ║ ║ ║║ ║║  ╚═╗
  end -- function end</nowiki>
═╩╝╩╚═╩ ╩╚╩╝╩╝╚╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
 
function DrawTools()
----
<nowiki> </nowiki> -- =====================================================]]
 
  <nowiki> </nowiki> function LayerClear(LayerName)
===IsDir()===
<nowiki> </nowiki> local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
 
<nowiki> </nowiki>    if Mylayer.IsEmpty then
Validates a directory path
<nowiki> </nowiki>       Milling.job.LayerManager:RemoveLayer(Mylayer)
 
<nowiki> </nowiki>    end -- if end
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki> return true
<nowiki>function IsDir(path)                    -- Returns true if path is found
end -- function end
    local function exists(file)
      local ok, err, code = os.rename(file, file)
  <nowiki> </nowiki> -- ====================================================]]
      if not ok then
  <nowiki> </nowiki> function Scale(Num)
        if code == 13 then
<nowiki> </nowiki> local mtl_block = MaterialBlock()
          return true
<nowiki> </nowiki> if mtl_block.InMM then
        end -- if end
<nowiki> </nowiki>   return Num * 25.4
      end -- if end
<nowiki> </nowiki> else
      return ok, err
<nowiki> </nowiki>  return Num
    end -- function end
<nowiki> </nowiki> end
    return exists(path.."/")
end -- end function
  end -- function end</nowiki>
 
<nowiki> </nowiki> -- =====================================================]]
 
<nowiki> </nowiki> function AssyHoler(pt1, pt2, PartName)                 -- Draws Assy Holes in a stight line
----
<nowiki> </nowiki> local Ang1 = GetPolarDirection(pt1, pt2)
 
<nowiki> </nowiki> local Ang2 = GetPolarDirection(pt2, pt1)
===FileExists()===
<nowiki> </nowiki> pt1 = Polar2D(pt1, Ang1, Milling.AssemblyHoleStartEnd)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  <nowiki> </nowiki> DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
Returns Dialog size in a message box showing the X and Y values.
<nowiki> </nowiki> pt2 = Polar2D(pt2, Ang2, Milling.AssemblyHoleStartEnd)
<nowiki> function FileExists(name)
<nowiki> </nowiki> DrawCircle(pt2, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
-- FileExists(name
<nowiki> </nowiki> local Dist = GetDistance(pt1, pt2)
-- DisplayMessageBox(name)
<nowiki> </nowiki> if Project.Debugger then
    local f=io.open(name,"r")
<nowiki> </nowiki>  DMark("pt1", pt1)
    if f~=nil then
<nowiki> </nowiki>  DMark("pt2", pt2)
      io.close(f)
<nowiki> </nowiki> end
      return true
<nowiki> </nowiki> BaseScrew(2)
    else
<nowiki> </nowiki> Milling.AssemblyHoleSpace = ((Milling.AssemblyHoleMaxSpace + Milling.AssemblyHoleMinSpace) * 0.5)
      return false
<nowiki> </nowiki> HoleCount = Round(math.floor(Dist / Milling.AssemblyHoleSpace))
    end
<nowiki> </nowiki> HoleSpacing = (Dist / HoleCount)
  end -- function end</nowiki>
<nowiki> </nowiki> HoleCount = (Dist / HoleSpacing)
 
<nowiki> </nowiki> if (Dist > (HoleSpacing * 2.0)) then
----
<nowiki> </nowiki>  for i = HoleCount, 1, -1 do
 
<nowiki> </nowiki>     pt1 = Polar2D(pt1, Ang1, HoleSpacing)
===DirectoryProcessor()===
<nowiki> </nowiki>     DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>     if Project.Debugger then
 
<nowiki> </nowiki>      DMark("pt1w", pt1)
Returns number of files that were processed by an operation.
<nowiki> </nowiki>     end
 
<nowiki> </nowiki>     BaseScrew(1)
  <nowiki> function DirectoryProcessor(job, dir_name, filter, do_sub_dirs, function_ptr)
<nowiki> </nowiki>  end -- for end
      local num_files_processed = 0
<nowiki> </nowiki> elseif (Dist > HoleSpacing) then
      local directory_reader = DirectoryReader()
<nowiki> </nowiki>  ptC = Polar2D(pt1, Ang1, Dist / 2.0)
      local cur_dir_reader = DirectoryReader()
<nowiki> </nowiki>  if Project.Debugger then
       directory_reader:BuildDirectoryList(dir_name, do_sub_dirs)
<nowiki> </nowiki>    DMark("ptC", ptC)
      directory_reader:SortDirs()
<nowiki> </nowiki>  end
      local number_of_directories = directory_reader:NumberOfDirs()
<nowiki> </nowiki>  DrawCircle(ptC, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
      for i = 1, number_of_directories do
<nowiki> </nowiki> else
        local cur_directory = directory_reader:DirAtIndex(i)
<nowiki> </nowiki>  -- Done No Holes
        -- get contents of current directory
<nowiki> </nowiki> end
        -- dont include sub dirs, use passed filter
<nowiki> </nowiki> return true
        cur_dir_reader:BuildDirectoryList(cur_directory.Name, false)
end -- end AssyHoler function
        cur_dir_reader:GetFiles(filter, true, false)
<nowiki> </nowiki> -- =====================================================]]
        -- call passed method for each file:
  <nowiki> </nowiki> function DrawBoneCenter2Pts(pt1, pt2, SlotWidth, BitRadius)
        local num_files_in_dir = cur_dir_reader:NumberOfFiles()
<nowiki> </nowiki>  Local Project = {}
        for j=1, num_files_in_dir do
<nowiki> </nowiki>  Project.job   = VectricJob()
          local file_info = cur_dir_reader:FileAtIndex(j)
<nowiki> </nowiki>  Project.ang  = GetPolarDirection(pt1, pt2)
          if not function_ptr(job, file_info.Name) then
<nowiki> </nowiki>  Project.dis  = H(SlotWidth)
            return true
<nowiki> </nowiki>  Project.bit  = math.sin(math.rad(45.0)) * BitRadius
          end -- if end
<nowiki> </nowiki>  Project.ptA  = Polar2D(pt1, Project.ang +  90.0, Project.dis)
          num_files_processed = num_files_processed + 1
<nowiki> </nowiki>  Project.ptAa  = Polar2D(Project.ptA, Project.ang, Project.bit)
        end -- for end
<nowiki> </nowiki>  Project.ptAb  = Polar2D(Project.ptA, Project.ang + 270.0, Project.bit)
        -- empty out our directory object ready for next go
<nowiki> </nowiki>  Project.ptB  = Polar2D(pt1, Project.ang + 270.0, Project.dis)
        cur_dir_reader:ClearDirs()
<nowiki> </nowiki>  Project.ptBa  = Polar2D(Project.ptB, Project.ang +  90.0, Project.bit)
        cur_dir_reader:ClearFiles()
<nowiki> </nowiki>  Project.ptBb  = Polar2D(Project.ptB, Project.ang, Project.bit)
      end -- for end
<nowiki> </nowiki>  Project.ptC  = Polar2D(pt2, Project.ang + 270.0, Project.dis)
      return num_files_processed
<nowiki> </nowiki>  Project.ptCa  = Polar2D(Project.ptC, Project.ang +  90.0, Project.bit)
  end -- function end </nowiki>
<nowiki> </nowiki>  Project.ptCb  = Polar2D(Project.ptC, Project.ang - 180.0, Project.bit)
----
<nowiki> </nowiki>  Project.ptD  = Polar2D(pt2, Project.ang +  90.0, Project.dis)
 
<nowiki> </nowiki>  Project.ptDa  = Polar2D(Project.ptD, Project.ang - 180.0, Project.bit)
==Drawing Tools==
<nowiki> </nowiki>  Project.ptDb  = Polar2D(Project.ptD, Project.ang + 270.0, Project.bit)
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
<nowiki> </nowiki>  Project.line  = Contour(0.0)
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
<nowiki> </nowiki>  Project.layer = Project.job.LayerManager:GetLayerWithName("DogBone")
 
<nowiki> </nowiki>  Project.line:AppendPoint(Project.ptAa)
----
<nowiki> </nowiki>  Project.line:ArcTo(Project.ptAb, 1.0)
 
<nowiki> </nowiki>  Project.line:LineTo(Project.ptBa)
===DrawArrowLineArrow===
<nowiki> </nowiki>  Project.line:ArcTo(Project.ptBb, 1.0)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>  Project.line:LineTo(Project.ptCb)
Draws a dimension line with arrow heads and extension leaders
<nowiki> </nowiki>  Project.line:ArcTo(Project.ptCa, 1.0)
  <nowiki>function DrawArrowLineArrow(Pt1, Ext1, Pt2, Ext2, Off, Str, Layer, scale)
<nowiki> </nowiki>  Project.line:LineTo(Project.ptDb)
  -- DrawArrowLineArrow(pt1, true, pt3, true, 2.5, "122.5", "TestLayer", 6.0) -- both
<nowiki> </nowiki>  Project.line:ArcTo(Project.ptDa, 1.0)
  -- DrawArrowLineArrow(pt1, true, pt3, false, 2.5, "122.5", "TestLayer", 6.0) -- first leader only
<nowiki> </nowiki>  Project.line:LineTo(Project.ptAa)
   -- DrawArrowLineArrow(pt1, false, pt3, true, 2.5, "122.5", "TestLayer", 6.0) -- second leader only
<nowiki> </nowiki>  Project.layer:AddObject(CreateCadContour(Project.line), true)
  -- -----------------------------------------------------]]
<nowiki> </nowiki>  return true
    local job = VectricJob()
<nowiki> </nowiki> end -- function end
    if not job.Exists then
<nowiki> </nowiki> -- =====================================================]]
      DisplayMessageBox("Error: No job loaded")
<nowiki> </nowiki> function InsideCornerNipper(AngPlung, BitRadius, CornerPt)
      return false
<nowiki> </nowiki> local NipLength = math.sin(math.rad(45.0)) * ((BitRadius + 0.04) * 2.0)
    end -- if end
<nowiki> </nowiki> local Pt1, Pt2 = Point2D()
    local DimArrow1Angle = GetPolarDirection(Pt1, Pt2, Polar2D(Pt2, 0.0, 1.0))
<nowiki> </nowiki> if Material.Orientation == "V" then
    local DimArrow2Angle = DimArrow1Angle + 180.0
<nowiki> </nowiki>  Pt1 = Polar2D(CornerPt, (AngPlung + 90.0) - 45.0, NipLength)
    local LederAng      = DimArrow1Angle + 90.0
<nowiki> </nowiki>  Pt2 = Polar2D(CornerPt, (AngPlung + 90.0) + 45.0, NipLength)
    local LedDrop        = LederAng + 180.0
<nowiki> </nowiki> else
    local TxtCenter      = GetDistance(Pt1, Pt2) * 0.5
<nowiki> </nowiki>  Pt1 = Polar2D(CornerPt, (AngPlung + 180.0) - 45.0, NipLength)
    local ArrowLen      = 0.125 * scale
<nowiki> </nowiki>  Pt2 = Polar2D(CornerPt, (AngPlung + 180.0) + 45.0, NipLength)
    local StrSet        = (string.len(Str) * ArrowLen) * 0.5
<nowiki> </nowiki> end
    local PT01A          = Polar2D(Pt1, LederAng, ArrowLen * 2.0)
<nowiki> </nowiki> return Pt1, Pt2
    local PT02A          = Polar2D(PT01A, LederAng, Off)
end
    local PT03A          = Polar2D(PT02A, LederAng, ArrowLen)
<nowiki> </nowiki> -- =====================================================]]
    local PT01B          = Polar2D(Pt2, LederAng, ArrowLen * 2.0)
<nowiki> </nowiki> function AddGroupToJob(job, group, layer_name)
    local PT02B          = Polar2D(PT01B, LederAng, Off)
<nowiki> </nowiki>    --<nowiki>[[  --------------- AddGroupToJob --------------------------------------------------|
    local PT03B          = Polar2D(PT02B, LederAng, ArrowLen)
  |  Add passed group to the job - returns object created
    local Apt1          = Polar2D(PT02A, DimArrow1Angle + 15.0, ArrowLen)
  |  Parameters:
    local Apt2          = Polar2D(PT02A, DimArrow1Angle - 15.0, ArrowLen)
  |    job              -- job we are working with
    local TxtPt1        = Polar2D(Polar2D(PT02A, DimArrow1Angle, TxtCenter), DimArrow1Angle + 90.0, ArrowLen)
  |    group            -- group of contours to  add to document
    local TxtPt          = Polar2D(TxtPt1, DimArrow2Angle, StrSet)
  |    layer_name      -- name of layer group will be created on|
    local ArrowHead      = (ArrowLen * 0.333)
  |  Return Values:
    local line1          = Contour(0.0)
  |    object created to represent group in document
    local layer1        = job.LayerManager:GetLayerWithName(Layer)
  ]]</nowiki>
    line1:AppendPoint(Apt1)
<nowiki> </nowiki>    --  create a CadObject to represent the  group
    line1:LineTo(PT02A)
<nowiki> </nowiki>  local cad_object = CreateCadGroup(group);
    line1:LineTo(Apt2)
<nowiki> </nowiki>    -- create a layer with passed name if it doesnt already exist
    line1:LineTo(Apt1)
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(layer_name)
    layer1:AddObject(CreateCadContour(line1), true)
<nowiki> </nowiki>    -- and add our object to it
     local Apt3 = Polar2D(PT02B, DimArrow2Angle + 15.0, ArrowLen)
<nowiki> </nowiki>  layer:AddObject(cad_object, true)
     local Apt4 = Polar2D(PT02B, DimArrow2Angle - 15.0, ArrowLen)
<nowiki> </nowiki>  return cad_object
     local line2 = Contour(0.0)
<nowiki> </nowiki> end
    local layer2 = job.LayerManager:GetLayerWithName(Layer)
     line2:AppendPoint(Apt3)
<nowiki> </nowiki> -- =====================================================]]
     line2:LineTo(PT02B)
<nowiki> </nowiki> function DrawArc(PtS, PtE, ArcRadius, Layer)
    line2:LineTo(Apt4)
<nowiki> </nowiki> --<nowiki>[[Draw Arc
    line2:LineTo(Apt3)
  function main(script_path)
    layer2:AddObject(CreateCadContour(line2), true)
  local MyPt1 = Point2D(3.5,3.8)
    if Ext1 then
  local MyPt2 = Point2D(3.5,6.8)
      local lineA = Contour(0.0)
  local layer = "My Arc"
      local layerA = job.LayerManager:GetLayerWithName(Layer)
  DrawArc(MyPt1, MyPt2, -0.456, Layer)
      lineA:AppendPoint(PT01A)
  return true
      lineA:LineTo(PT03A)
  end -- function end
      layerA:AddObject(CreateCadContour(lineA), true)
  -- -----------------------------------------------------]]</nowiki>
    end -- if end
<nowiki> </nowiki>    local job = VectricJob()
    if Ext2 then
<nowiki> </nowiki>    if not job.Exists then
      local lineB = Contour(0.0)
<nowiki> </nowiki>      DisplayMessageBox("Error: No job loaded")
      local layerB = job.LayerManager:GetLayerWithName(Layer)
<nowiki> </nowiki>      return false
      lineB:AppendPoint(PT01B)
<nowiki> </nowiki>    end
      lineB:LineTo(PT03B)
<nowiki> </nowiki>    local line = Contour(0.0)
      layerB:AddObject(CreateCadContour(lineB), true)
<nowiki> </nowiki>    local layer = job.LayerManager:GetLayerWithName(Layer)
    end -- if end
<nowiki> </nowiki>    line:AppendPoint(PtS)
    local lineC = Contour(0.0)
<nowiki> </nowiki>    line:ArcTo(PtE,1);
    local layerC = job.LayerManager:GetLayerWithName(Layer)
<nowiki> </nowiki>    layer:AddObject(CreateCadContour(line), true)
    lineC:AppendPoint(PT02A)
<nowiki> </nowiki>    return true
    lineC:LineTo(PT02B)
<nowiki> </nowiki>  end -- function end
    layerC:AddObject(CreateCadContour(lineC), true)
    DrawWriter(Double2Fraction(Str), TxtPt, ArrowLen, Layer, DimArrow1Angle)
<nowiki> </nowiki> -- =====================================================]]
    return true
<nowiki> </nowiki> function DrawEllipse(CenterPt, LongAxe, ShortAxe, Layer)
  end -- function end</nowiki>
<nowiki> </nowiki>  local LongAngle = 90.0
 
<nowiki> </nowiki>  local ValueAB = (LongAxe - ShortAxe) * 0.50
----
<nowiki> </nowiki>  local ValueAC = ValueAB * math.cos(math.rad(LongAngle))
 
<nowiki> </nowiki>  local job = VectricJob()
===LayerClear===
<nowiki> </nowiki>  local LRad = LongAxe * 0.50
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>  local ptT = Polar2D(CenterPt, LongAngle, LRad)
Deletes Layer if empty.
<nowiki> </nowiki>  local X = 0.0
 
<nowiki> </nowiki>  local pty = Point2D(0.0,0.0)
  <nowiki>function LayerClear(LayerName)
<nowiki> </nowiki>  local ptx  = Point2D(0.0,0.0)
  local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
<nowiki> </nowiki>  local mylayer = job.LayerManager:GetLayerWithName(Layer)
  if Mylayer.IsEmpty then
<nowiki> </nowiki>  local line = Contour(0.0)
    Milling.job.LayerManager:RemoveLayer(Mylayer)
<nowiki> </nowiki>        line:AppendPoint(ptT)
   end -- if end
<nowiki> </nowiki>  while (X < 360.0) do
<nowiki> </nowiki>    pty = Polar2D(CenterPt, LongAngle + X, LRad)
<nowiki> </nowiki>    ValueAC = ValueAB * math.cos(math.rad(LongAngle + X))
<nowiki> </nowiki>    if ((LongAngle + X) >= 90.0) then
<nowiki> </nowiki>      ptx = Polar2D(pty, 180.0, ValueAC)
<nowiki> </nowiki>    else
<nowiki> </nowiki>      ptx = Polar2D(pty,  0.0, ValueAC)
<nowiki> </nowiki>    end
<nowiki> </nowiki>    line:LineTo(ptx)
<nowiki> </nowiki>    X = X + 1
<nowiki> </nowiki>  end -- while end
<nowiki> </nowiki>    line:LineTo(ptT)
<nowiki> </nowiki>  mylayer:AddObject(CreateCadContour(line), true)
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end -- function end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawEllipse1(DrawEllipse_CenterPt, DrawEllipse_LongAxe, DrawEllipse_ShortAxe, DrawEllipse_LongAxeAngle, DrawEllipse_Layer)
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki>  function H(x)                                        -- Returns half the value
<nowiki> </nowiki>    return x * 0.5
<nowiki> </nowiki>  end -- function end
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki>  function Polar2D(pt, ang, dis)                        -- Calculate a new point based on reference point, angle and distance.
<nowiki> </nowiki>  -- Returns a 2Dpoint(x, y)
<nowiki> </nowiki>    return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
<nowiki> </nowiki>  end -- End Function
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki>  function GetDistance(objA, objB)
<nowiki> </nowiki>    local xDist = objB.x - objA.x
<nowiki> </nowiki>    local yDist = objB.y - objA.y
<nowiki> </nowiki>    return math.sqrt((xDist ^ 2) + (yDist ^ 2))
<nowiki> </nowiki>  end -- function end
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki>  function Radius2Bulge (p1, p2, Rad)
<nowiki> </nowiki>    local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
<nowiki> </nowiki>    local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
<nowiki> </nowiki>    local bulge = (2 * seg) / chord
<nowiki> </nowiki>    return bulge
<nowiki> </nowiki>  end -- function end
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki> function GetPolarAngle(Start, Corner, End)
<nowiki> </nowiki>  local function GetPolarDirection(point1, point2)              --
<nowiki> </nowiki>    local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
<nowiki> </nowiki>    if point1.X < point2.X then
<nowiki> </nowiki>      if point1.Y < point2.Y then
<nowiki> </nowiki>        ang = ang + 0.0
<nowiki> </nowiki>      else
<nowiki> </nowiki>        ang = 360.0 - ang
<nowiki> </nowiki>      end -- if end
<nowiki> </nowiki>    else
<nowiki> </nowiki>      if point1.Y < point2.Y then
<nowiki> </nowiki>        ang = 180.0 - ang
<nowiki> </nowiki>      else
<nowiki> </nowiki>        ang = ang + 180.0
<nowiki> </nowiki>      end -- if end
<nowiki> </nowiki>    end -- if end
<nowiki> </nowiki>    if ang >=360 then
<nowiki> </nowiki>      ang = ang -360.0
<nowiki> </nowiki>    end -- if end
<nowiki> </nowiki>    return ang
<nowiki> </nowiki>  end -- function end
<nowiki> </nowiki>  return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
<nowiki> </nowiki> end -- function end
<nowiki> </nowiki>  -- ---------------------------------------------------]]
<nowiki> </nowiki>  -- Call = DrawEllipse(2DPoint(20.0, 20.0), 20.0, 10.0, 0.0, "Jim")
<nowiki> </nowiki>  local job = VectricJob()
<nowiki> </nowiki>  local EndRadius = 0.0
<nowiki> </nowiki>  local TopRadius = 0.0
<nowiki> </nowiki>  local ptT = Polar2D(DrawEllipse_CenterPt,  (90.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
<nowiki> </nowiki>  local ptB = Polar2D(DrawEllipse_CenterPt, (270.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
<nowiki> </nowiki>  local ptR = Polar2D(DrawEllipse_CenterPt,  (0.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
<nowiki> </nowiki>  local ptL = Polar2D(DrawEllipse_CenterPt, (180.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
<nowiki> </nowiki>  local ptC = DrawEllipse_CenterPt
<nowiki> </nowiki>  --<nowiki>[[
      DMark("ptC", ptC)
      DMark("ptT", ptT)
      DMark("ptB", ptB)
      DMark("ptL", ptL)
      DMark("ptR", ptR)
  ]]</nowiki>
<nowiki> </nowiki>  local C_Offset = H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe)
<nowiki> </nowiki>  local LT_SlopeDist = H(GetDistance(ptL, ptT) - H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe))
<nowiki> </nowiki>  local LT_Dist  = GetDistance(ptL, ptT)
<nowiki> </nowiki>  local LT_Angle = math.abs(90.0 - GetAngle(ptT, ptL, ptC))
<nowiki> </nowiki>  local pt_a = Polar2D(ptL, LT_Angle + DrawEllipse_LongAxeAngle, LT_SlopeDist)
<nowiki> </nowiki>  local aT_Dist  = GetDistance(pt_a, ptT)
<nowiki> </nowiki>  local aC_Dist = aT_Dist / (math.tan(math.rad(LT_Angle)))
<nowiki> </nowiki>  local Tc_Dist = math.sqrt(aT_Dist^2 + aC_Dist^2)
<nowiki> </nowiki>  local pt_c = Polar2D(ptT, (270.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
<nowiki> </nowiki>  local cC_Dist  = GetDistance(pt_c, ptC)
<nowiki> </nowiki>  local b_Dist = math.tan(math.rad(LT_Angle)) * cC_Dist
<nowiki> </nowiki>  local pt_b = Polar2D(ptC, (180.0 + DrawEllipse_LongAxeAngle), b_Dist)
<nowiki> </nowiki>  local pt_d = Polar2D(ptB,  (90.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
<nowiki> </nowiki>  local pt_e = Polar2D(ptC,  (0.0 + DrawEllipse_LongAxeAngle), b_Dist)
<nowiki> </nowiki>  local pt1  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
<nowiki> </nowiki>  local pt2  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
<nowiki> </nowiki>  local pt3  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
<nowiki> </nowiki>  local pt4  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
<nowiki> </nowiki>  --<nowiki>[[
      DMark("pt1", pt1)
      DMark("pt2", pt2)
      DMark("pt3", pt3)
      DMark("pt4", pt4)
      local line = Contour(0.0)
      local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
      line:AppendPoint(pt1)
      line:LineTo(pt2)
      line:LineTo(pt3)
      line:LineTo(pt4)
      line:LineTo(pt1)
      layer:AddObject(CreateCadContour(line), true)
  ]]</nowiki>
<nowiki> </nowiki>  local T_Sec  = GetDistance(ptC, ptT) - H(GetDistance(pt1, pt4))
<nowiki> </nowiki>  local R_Sec  = GetDistance(ptC, ptR) - H(GetDistance(pt1, pt2))
<nowiki> </nowiki>  local T_Chor  = GetDistance(pt1, pt2)
<nowiki> </nowiki>  local R_Chor  = GetDistance(pt1, pt4)
<nowiki> </nowiki>  local T_Bulge = Radius2Bulge (pt1, pt2, Tc_Dist)
<nowiki> </nowiki>  local L_Bulge = Radius2Bulge (pt1, pt4, GetDistance(ptL, pt_b))
<nowiki> </nowiki>  local line = Contour(0.0)
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
<nowiki> </nowiki>  line:AppendPoint(pt1)
<nowiki> </nowiki>  line:ArcTo(pt2, T_Bulge)
<nowiki> </nowiki>  line:ArcTo(pt3, L_Bulge)
<nowiki> </nowiki>  line:ArcTo(pt4, T_Bulge)
<nowiki> </nowiki>  line:ArcTo(pt1, L_Bulge)
<nowiki> </nowiki>  layer:AddObject(CreateCadContour(line), true)
<nowiki> </nowiki>  job:Refresh2DView()
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end -- Draw Ellipse function end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawBox(p1, p2, p3, p4, Layer)
<nowiki> </nowiki>  --<nowiki>[[ Draw Box
    function main(script_path)
    local MyPt1 = Point2D(1.0,1.0)
    local MyPt2 = Point2D(1.0,3.0)
    local MyPt3 = Point2D(3.0,1.0)
    local MyPt4 = Point2D(3.0,3.0)
    local layer = "My Box"
    DrawBox(MyPt1 ,MyPt2, MyPt3, MyPt4, Layer)
    return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
<nowiki> </nowiki>    local job = VectricJob()
<nowiki> </nowiki>    if not job.Exists then
<nowiki> </nowiki>      DisplayMessageBox("Error: No job loaded")
<nowiki> </nowiki>      return false
<nowiki> </nowiki>    end -- if end
<nowiki> </nowiki>    local line = Contour(0.0)
<nowiki> </nowiki>    local layer = job.LayerManager:GetLayerWithName(Layer)
<nowiki> </nowiki>    line:AppendPoint(p1)
<nowiki> </nowiki>    line:LineTo(p2)
<nowiki> </nowiki>    line:LineTo(p3)
<nowiki> </nowiki>    line:LineTo(p4)
<nowiki> </nowiki>    line:LineTo(p1)
<nowiki> </nowiki>    layer:AddObject(CreateCadContour(line), true)
<nowiki> </nowiki>    return true
<nowiki> </nowiki>  end -- function end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawCircle(Pt1, CenterRadius, Layer)
<nowiki> </nowiki>  --<nowiki>[[ ==Draw Circle==
    function main(script_path)
    local MyPt1 = Point2D(1.0,1.0)
    local MyRad = 3.0
    local layer = "My Box"
    DrawCircle(MyPt1, MyRad, Layer)
    return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
<nowiki> </nowiki>  local job = VectricJob()
<nowiki> </nowiki>  if not job.Exists then
<nowiki> </nowiki>    DisplayMessageBox("Error: No job loaded")
<nowiki> </nowiki>    return false
<nowiki> </nowiki>  end -- if end
<nowiki> </nowiki>  local pa = Polar2D(Pt1,  180.0, CenterRadius)
<nowiki> </nowiki>  local pb = Polar2D(Pt1,    0.0, CenterRadius)
<nowiki> </nowiki>  local Contour = Contour(0.0)
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(Layer)
<nowiki> </nowiki>  Contour:AppendPoint(pa)
<nowiki> </nowiki>  Contour:ArcTo(pb, 1)
<nowiki> </nowiki>  Contour:ArcTo(pa, 1)
<nowiki> </nowiki>  layer:AddObject(CreateCadContour(Contour), true)
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end -- function end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawLine(Pt1, Pt2, Layer)
<nowiki> </nowiki> --<nowiki>[[Draws a line from Pt1 to Pt2 on the layer name.
  function main(script_path)
  local MyPt1 = Point2D(3.5,3.8)
  local MyPt2 = Point2D(3.5,6.8)
   local layer = "My Line"
  DrawLine(MyPt1 , MyPt2, MyPt3, Layer)
   return true
   return true
  end -- function end
end -- function end</nowiki>
  -- -----------------------------------------------------]]</nowiki>
 
<nowiki> </nowiki>  local job = VectricJob()
----
<nowiki> </nowiki>  if not job.Exists then
 
<nowiki> </nowiki>    DisplayMessageBox("Error: No job loaded")
===LeaderLine===
<nowiki> </nowiki>     return false
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>  end
<nowiki>function DrawLeader(Pt1, Pt2, Pt3, Str, Layer, scale)  --Draws a leader with text
<nowiki> </nowiki>  local line = Contour(0.0)
  --[[
  <nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(Layer)
  DrawLeader(pt1, pt2, "122.5", "TestLayer", 6.0)
<nowiki> </nowiki>  line:AppendPoint(Pt1)
  --]]
<nowiki> </nowiki>  line:LineTo(Pt2)
    local job = VectricJob()
<nowiki> </nowiki>  layer:AddObject(CreateCadContour(line), true)
    if not job.Exists then
<nowiki> </nowiki>  return true
      DisplayMessageBox("Error: No job loaded")
<nowiki> </nowiki> end -- function end
      return false
<nowiki> </nowiki> -- =====================================================]]
     end -- if end
<nowiki> </nowiki> function DrawStar(pt1, InRadius ,OutRadius, layer)     --This draw function requires the center point, inter star radius, outer star radius and layer name.
    local ArrowLen      = 0.125 * scale
<nowiki> </nowiki> --<nowiki>[[
    local DimArrowAngle = GetPolarDirection(Pt1, Pt2, Polar2D(Pt2, 0.0, 1.0))
    function main(script_path)
    local TxtAngle      = GetPolarDirection(Pt2, Pt3, Polar2D(Pt3, 0.0, 1.0))
      local MyPt = Point2D(3.5,3.8)
    local TxtPt          = Polar2D(Polar2D(Pt3, TxtAngle, ArrowLen), TxtAngle-45, H(ArrowLen))
      local InRadius = 9.0
    local Apt1          = Polar2D(Pt1, DimArrowAngle + 15.0, ArrowLen)
      local OutRadius= 20.0
    local Apt2          = Polar2D(Pt1, DimArrowAngle - 15.0, ArrowLen)
      local layer = "My Star"
    local ArrowHead      = ArrowLen * 0.333
      DrawStar(MyPt , InRadius ,OutRadius, layer)
    local line1          = Contour(0.0)
      return true
    local layer1        = job.LayerManager:GetLayerWithName(Layer)
    end -- function end
    line1:AppendPoint(Pt1)
  -- -----------------------------------------------------]]</nowiki>
    line1:LineTo(Apt2) ;  line1:LineTo(Apt1) ; line1:LineTo(Pt1)
<nowiki> </nowiki>  local job = VectricJob()
    layer1:AddObject(CreateCadContour(line1), true)
<nowiki> </nowiki>  if not job.Exists then
    local lineC = Contour(0.0)
<nowiki> </nowiki>    DisplayMessageBox("Error: No job loaded")
    local layerC = job.LayerManager:GetLayerWithName(Layer)
<nowiki> </nowiki>    return false
    lineC:AppendPoint(Pt1)
<nowiki> </nowiki>  end
    lineC:LineTo(Pt2)
<nowiki> </nowiki>  local p1 = Polar2D(pt1, 18.0, OutRadius)
    lineC:LineTo(Pt3)
<nowiki> </nowiki>  local p2 = Polar2D(pt1, 54.0,  InRadius)
    layerC:AddObject(CreateCadContour(lineC), true)
<nowiki> </nowiki>  local p3 =  Polar2D(pt1, 90.0, OutRadius)
    if IsAllNumber(Str) then
<nowiki> </nowiki>  local p4 =  Polar2D(pt1,  126.0, InRadius)
      DrawWriter(Double2Fraction(Str), TxtPt, ArrowLen, Layer, TxtAngle)
<nowiki> </nowiki>  local p5 =  Polar2D(pt1,  162.0, OutRadius)
    else
<nowiki> </nowiki>  local p6 = Polar2D(pt1,  198.0, InRadius)
      DrawWriter(Str, TxtPt, ArrowLen, Layer, TxtAngle)
<nowiki> </nowiki>  local p7 = Polar2D(pt1,  234.0, OutRadius)
    end -- if end
<nowiki> </nowiki>  local p8 = Polar2D(pt1, 270.0, InRadius)
    return true
  <nowiki> </nowiki>   local p9 =  Polar2D(pt1,  306.0, OutRadius)
  end -- function end</nowiki>
<nowiki> </nowiki>  local p0 = Polar2D(pt1, 342.0, InRadius)
 
<nowiki> </nowiki>  local line = Contour(0.0)
----
<nowiki> </nowiki>  -- local layers = job.LayerManager:GetLayerWithName(layer)
 
  <nowiki> </nowiki>   line:AppendPoint(p1);
===Scale===
<nowiki> </nowiki>  line:LineTo(p2);  line:LineTo(p3)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>   line:LineTo(p4);  line:LineTo(p5)
Provides the correct scale rate-based drawing units.
<nowiki> </nowiki>   line:LineTo(p6);  line:LineTo(p7)
 
<nowiki> </nowiki>   line:LineTo(p8);  line:LineTo(p9)
<nowiki>function Scale(Num)
<nowiki> </nowiki>   line:LineTo(p0); line:LineTo(p1)
  local mtl_block = MaterialBlock()
  <nowiki> </nowiki>  layer:AddObject(CreateCadContour(line), true)
  if mtl_block.InMM then
  <nowiki> </nowiki>   job:Refresh2DView()
    return Num * 25.4
  <nowiki> </nowiki>  return true
  else
  <nowiki> </nowiki> end -- function end
    return Num
  <nowiki> </nowiki> -- =====================================================]]
  end
<nowiki> </nowiki> function DrawTriangle(p1, p2, p3, Layer)
end -- function end</nowiki>
<nowiki> </nowiki> --<nowiki>[[Draw Triangle
 
    function main(script_path)
----
      local MyPt1 = Point2D(3.5,3.8)
 
      local MyPt2 = Point2D(3.5,6.8)
===AssyHoler===
      local MyPt3 = Point2D(9.8,6.8)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
      local layer = "My Triangle"
Draws Assy Holes in a stright line (Rabbet and/or Dado).
      DrawTriangle(MyPt1 , MyPt2, MyPt3, Layer)
 
      return true
<nowiki>function AssyHoler(pt1, pt2, PartName)                  -- Draws Assy Holes in a stright line
    end -- function end
    local Ang1 = GetPolarDirection(pt1, pt2)
  -- -----------------------------------------------------]]</nowiki>
    local Ang2 = GetPolarDirection(pt2, pt1)
  <nowiki> </nowiki>  local job = VectricJob()
            pt1 = Polar2D(pt1, Ang1, Milling.AssemblyHoleStartEnd)
<nowiki> </nowiki>  if not job.Exists then
    DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
<nowiki> </nowiki>    DisplayMessageBox("Error: No job loaded")
            pt2 = Polar2D(pt2, Ang2, Milling.AssemblyHoleStartEnd)
<nowiki> </nowiki>    return false
    DrawCircle(pt2, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
<nowiki> </nowiki>  end
    local Dist = GetDistance(pt1, pt2)
<nowiki> </nowiki>  local line = Contour(0.0)
    if Project.Debugger then
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(Layer)
        DMark("pt1", pt1)
<nowiki> </nowiki>  line:AppendPoint(p1)
        DMark("pt2", pt2)
<nowiki> </nowiki>  line:LineTo(p2)
    end -- if end
<nowiki> </nowiki>  line:LineTo(p3)
    BaseScrew(2)
<nowiki> </nowiki>  line:LineTo(p1)
    Milling.AssemblyHoleSpace = ((Milling.AssemblyHoleMaxSpace + Milling.AssemblyHoleMinSpace) * 0.5)
<nowiki> </nowiki>  layer:AddObject(CreateCadContour(line), true)
    HoleCount = Round(math.floor(Dist / Milling.AssemblyHoleSpace))
<nowiki> </nowiki>  job:Refresh2DView()
    HoleSpacing = (Dist / HoleCount)
<nowiki> </nowiki>  return true
    HoleCount = (Dist / HoleSpacing)
<nowiki> </nowiki> end -- function end
    if (Dist > (HoleSpacing * 2.0)) then
<nowiki> </nowiki> -- =====================================================]]
    for i = HoleCount, 1, -1 do
<nowiki> </nowiki> function Radius2Bulge (p1, p2, Rad)
      pt1 = Polar2D(pt1, Ang1, HoleSpacing)
<nowiki> </nowiki>  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
      DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
<nowiki> </nowiki>  local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
      if Project.Debugger then
<nowiki> </nowiki>  local bulge = (2 * seg) / chord
  >       DMark("pt1w", pt1)
<nowiki> </nowiki>  return bulge
      end -- if end
<nowiki> </nowiki> end
      BaseScrew(1)
<nowiki> </nowiki> -- =====================================================]]
    end -- for end
<nowiki> </nowiki> function ChordSeg2Radius (Chr, Seg)
  elseif (Dist > HoleSpacing) then
<nowiki> </nowiki>  local rad =  (((Chr * Chr)/(Seg * 4)) + Seg) / 2.0
    ptC = Polar2D(pt1, Ang1, Dist / 2.0)
<nowiki> </nowiki>  return rad
    if Project.Debugger then
<nowiki> </nowiki> end  -- end Function
      DMark("ptC", ptC)
    end -- if end
<nowiki> </nowiki> -- ====================================================]]
    DrawCircle(ptC, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
<nowiki> </nowiki> function CreateJob(job_name, width, height, thickness, in_mm, job_origin, z_on_surface)
  else
--<nowiki>[[ ----------- CreateJob -------------------------------------------------
    -- Done No Holes
  | This function was provided "as is" by Vectric technical team and a part of the gadget API documentation.
  end -- if end
  | Create a new empty job with the passed settings
  return true
]]</nowiki>
  end -- function end</nowiki>
<nowiki> </nowiki> -- we fill in most of our bounds in a Box2D
 
<nowiki> </nowiki> local job_bounds = Box2D()
----
<nowiki> </nowiki> local blc = Point2D(0, 0)
 
<nowiki> </nowiki> local trc = Point2D(width, height)
===DrawBoneCenter2Pts===
<nowiki> </nowiki> local origin_offset = Vector2D(0,0)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki> -- calculate bottom left corner offset for chosen origin
Draws dog bone joints.
<nowiki> </nowiki> if Template.DXFOrientation == "Vertical" then
 
<nowiki> </nowiki>  trc = Point2D(height, width)
<nowiki>function DrawBoneCenter2Pts(pt1, pt2, SlotWidth, BitRadius)
<nowiki> </nowiki>  if (job_origin == "BLC") then
  Local Project = {}
<nowiki> </nowiki>    origin_offset:Set(0, 0)
  Project.job   = VectricJob()
<nowiki> </nowiki>  elseif (job_origin == "BRC") then
  Project.ang   = GetPolarDirection(pt1, pt2)
<nowiki> </nowiki>    origin_offset:Set(height, 0)
  Project.dis  = H(SlotWidth)
<nowiki> </nowiki>  elseif (job_origin == "TRC") then
  Project.bit   = math.sin(math.rad(45.0)) * BitRadius
<nowiki> </nowiki>    origin_offset:Set(height, width)
  Project.ptA   = Polar2D(pt1, Project.ang + 90.0, Project.dis)
<nowiki> </nowiki>  elseif (job_origin == "TLC") then
  Project.ptAa = Polar2D(Project.ptA, Project.ang, Project.bit)
<nowiki> </nowiki>    origin_offset:Set(0, width)
  Project.ptAb = Polar2D(Project.ptA, Project.ang + 270.0, Project.bit)
<nowiki> </nowiki>  elseif (job_origin == "CENTRE") then
  Project.ptB   = Polar2D(pt1, Project.ang + 270.0, Project.dis)
<nowiki> </nowiki>    origin_offset:Set(height / 2, width / 2)
  Project.ptBa = Polar2D(Project.ptB, Project.ang + 90.0, Project.bit)
<nowiki> </nowiki>  elseif (job_origin == "CENTER") then
  Project.ptBb = Polar2D(Project.ptB, Project.ang, Project.bit)
<nowiki> </nowiki>    origin_offset:Set(height / 2, width / 2)
  Project.ptC  = Polar2D(pt2, Project.ang + 270.0, Project.dis)
<nowiki> </nowiki>  else
  Project.ptCa  = Polar2D(Project.ptC, Project.ang +  90.0, Project.bit)
<nowiki> </nowiki>    MessageBox("Unknown XY origin specified " .. job_origin)
  Project.ptCb  = Polar2D(Project.ptC, Project.ang - 180.0, Project.bit)
<nowiki> </nowiki>  end
  Project.ptD  = Polar2D(pt2, Project.ang +  90.0, Project.dis)
<nowiki> </nowiki> else
  Project.ptDa  = Polar2D(Project.ptD, Project.ang - 180.0, Project.bit)
<nowiki> </nowiki>  if (job_origin == "BLC") then
  Project.ptDb  = Polar2D(Project.ptD, Project.ang + 270.0, Project.bit)
<nowiki> </nowiki>    origin_offset:Set(0, 0)
  Project.line  = Contour(0.0)
<nowiki> </nowiki>  elseif (job_origin == "BRC") then
  Project.layer = Project.job.LayerManager:GetLayerWithName("DogBone")
<nowiki> </nowiki>    origin_offset:Set(width, 0)
  Project.line:AppendPoint(Project.ptAa)
<nowiki> </nowiki>  elseif (job_origin == "TRC") then
  Project.line:ArcTo(Project.ptAb, 1.0)
<nowiki> </nowiki>    origin_offset:Set(width, height)
  Project.line:LineTo(Project.ptBa)
<nowiki> </nowiki>  elseif (job_origin == "TLC") then
  Project.line:ArcTo(Project.ptBb, 1.0)
<nowiki> </nowiki>    origin_offset:Set(0, height)
  Project.line:LineTo(Project.ptCb)
<nowiki> </nowiki>  elseif (job_origin == "CENTRE") then
  Project.line:ArcTo(Project.ptCa, 1.0)
<nowiki> </nowiki>    origin_offset:Set(width / 2, height / 2)
  Project.line:LineTo(Project.ptDb)
<nowiki> </nowiki>  elseif (job_origin == "CENTER") then
  Project.line:ArcTo(Project.ptDa, 1.0)
<nowiki> </nowiki>    origin_offset:Set(width / 2, height / 2)
  Project.line:LineTo(Project.ptAa)
<nowiki> </nowiki>  else
  Project.layer:AddObject(CreateCadContour(Project.line), true)
<nowiki> </nowiki>    MessageBox("Unknown XY origin specified " .. job_origin)
  return true
<nowiki> </nowiki>  end
end -- function end</nowiki>
<nowiki> </nowiki> end
 
<nowiki> </nowiki> -- subtract the origin offset vector from our 'standard' corner positions to get position for corners for requested origin
----
<nowiki> </nowiki> blc = blc - origin_offset
 
<nowiki> </nowiki> trc = trc - origin_offset
===InsideCornerNipper===
<nowiki> </nowiki> job_bounds:Merge(blc)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki> job_bounds:Merge(trc)
Draws the nipping of a corner for easy fitting.
<nowiki> </nowiki> local success = CreateNewJob(job_name,job_bounds,thickness,in_mm,z_on_surface)
 
<nowiki> </nowiki> return success
  <nowiki>function InsideCornerNipper(AngPlung, BitRadius, CornerPt)
end
  local NipLength = math.sin(math.rad(45.0)) * ((BitRadius + 0.04) * 2.0)
<nowiki> </nowiki> -- =====================================================]]
  local Pt1, Pt2 = Point2D()
<nowiki> </nowiki> function DrawFontGrid(job)
  if Material.Orientation == "V" then
<nowiki> </nowiki>  local pt = Point2D(0.3,0.3)
    Pt1 = Polar2D(CornerPt, (AngPlung + 90.0) - 45.0, NipLength)
<nowiki> </nowiki>  local scl  = 1.0 -- (scl * 0.5)
    Pt2 = Polar2D(CornerPt, (AngPlung + 90.0) + 45.0, NipLength)
<nowiki> </nowiki>  local pA0  = pt
  else
<nowiki> </nowiki>  local ang  = 0.0
    Pt1 = Polar2D(CornerPt, (AngPlung + 180.0) - 45.0, NipLength)
<nowiki> </nowiki>  local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl))
     Pt2 = Polar2D(CornerPt, (AngPlung + 180.0) + 45.0, NipLength)
<nowiki> </nowiki>  local pA2  = Polar2D(pt, ang + 90.0000, (0.5000 * scl))
<nowiki> </nowiki>  local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl))
<nowiki> </nowiki>  local pA4  = Polar2D(pt, ang + 90.0000, (1.0000 * scl))
<nowiki> </nowiki>  local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl))
<nowiki> </nowiki>  local pA6  = Polar2D(pt, ang + 90.0000, (1.5000 * scl))
<nowiki> </nowiki>  local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl))
<nowiki> </nowiki>  local pA8  = Polar2D(pt, ang + 90.0000, (2.0000 * scl))
<nowiki> </nowiki>  local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl))
<nowiki> </nowiki>  local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl))
<nowiki> </nowiki>  PointCircle(pA0)
<nowiki> </nowiki>  PointCircle(pA1)
<nowiki> </nowiki>  PointCircle(pA2)
<nowiki> </nowiki>  PointCircle(pA3)
<nowiki> </nowiki>  PointCircle(pA4)
<nowiki> </nowiki>  PointCircle(pA5)
<nowiki> </nowiki>  PointCircle(pA6)
<nowiki> </nowiki>  PointCircle(pA7)
<nowiki> </nowiki>  PointCircle(pA8)
<nowiki> </nowiki>  PointCircle(pA9)
<nowiki> </nowiki>  PointCircle(pA10)
<nowiki> </nowiki>  local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl))
<nowiki> </nowiki>  local pB1  = Polar2D(pt, ang + 45.0000, (0.3536 * scl))
<nowiki> </nowiki>  local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl))
<nowiki> </nowiki>  local pB3  = Polar2D(pt, ang + 71.5651, (0.7906 * scl))
<nowiki> </nowiki>  local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl))
<nowiki> </nowiki>  local pB5  = Polar2D(pt, ang + 78.6901, (1.2748 * scl))
<nowiki> </nowiki>  local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl))
<nowiki> </nowiki>  local pB7  = Polar2D(pt, ang + 81.8699, (1.7678 * scl))
<nowiki> </nowiki>  local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl))
<nowiki> </nowiki>  local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl))
<nowiki> </nowiki>  PointCircle(pB0)
<nowiki> </nowiki>  PointCircle(pB1)
<nowiki> </nowiki>  PointCircle(pB2)
<nowiki> </nowiki>  PointCircle(pB3)
<nowiki> </nowiki>  PointCircle(pB4)
<nowiki> </nowiki>  PointCircle(pB5)
<nowiki> </nowiki>  PointCircle(pB7)
<nowiki> </nowiki>  PointCircle(pB8)
<nowiki> </nowiki>  PointCircle(pB10)
<nowiki> </nowiki>  local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl))
<nowiki> </nowiki>  local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl))
<nowiki> </nowiki>  local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl))
<nowiki> </nowiki>  local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl))
<nowiki> </nowiki>  local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
<nowiki> </nowiki>  local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl))
<nowiki> </nowiki>  local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl))
<nowiki> </nowiki>  local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
<nowiki> </nowiki>  local pC8 = Polar2D(pt, ang + 74.0550, (1.8201 * scl))
<nowiki> </nowiki>  local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl))
<nowiki> </nowiki>  PointCircle(pC0)
<nowiki> </nowiki>  PointCircle(pC1)
<nowiki> </nowiki>  PointCircle(pC2)
<nowiki> </nowiki>  PointCircle(pC3)
<nowiki> </nowiki>  PointCircle(pC4)
<nowiki> </nowiki>  PointCircle(pC6)
<nowiki> </nowiki>  PointCircle(pC8)
<nowiki> </nowiki>  PointCircle(pC10)
<nowiki> </nowiki>  local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl))
<nowiki> </nowiki>  local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl))
<nowiki> </nowiki>  local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
<nowiki> </nowiki>  local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl))
<nowiki> </nowiki>  local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl))
<nowiki> </nowiki>  local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl))
<nowiki> </nowiki>  PointCircle(pD0)
<nowiki> </nowiki>  PointCircle(pD1)
<nowiki> </nowiki>  PointCircle(pD2)
<nowiki> </nowiki>  PointCircle(pD4)
<nowiki> </nowiki>  PointCircle(pD7)
<nowiki> </nowiki>  PointCircle(pD8)
<nowiki> </nowiki>  local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl))
<nowiki> </nowiki>  local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl))
<nowiki> </nowiki>  local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
<nowiki> </nowiki>  local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl))
<nowiki> </nowiki>  local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl))
<nowiki> </nowiki>  local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl))
<nowiki> </nowiki>  local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl))
<nowiki> </nowiki>  local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl))
<nowiki> </nowiki>  PointCircle(pE0)
<nowiki> </nowiki>  PointCircle(pE1)
<nowiki> </nowiki>  PointCircle(pE2)
<nowiki> </nowiki>  PointCircle(pE3)
<nowiki> </nowiki>  PointCircle(pE5)
<nowiki> </nowiki>  PointCircle(pE6)
<nowiki> </nowiki>  PointCircle(pE7)
<nowiki> </nowiki>  PointCircle(pE8)
<nowiki> </nowiki>  local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl))
<nowiki> </nowiki>  local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl))
<nowiki> </nowiki>  local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl))
<nowiki> </nowiki>  local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl))
<nowiki> </nowiki>  local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl))
<nowiki> </nowiki>  local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl))
<nowiki> </nowiki>  local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl))
<nowiki> </nowiki>  local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl))
<nowiki> </nowiki>  local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl))
<nowiki> </nowiki>  PointCircle(pF0)
<nowiki> </nowiki>  PointCircle(pF1)
<nowiki> </nowiki>  PointCircle(pF2)
<nowiki> </nowiki>  PointCircle(pF3)
<nowiki> </nowiki>  PointCircle(pF4)
<nowiki> </nowiki>  PointCircle(pF5)
<nowiki> </nowiki>  PointCircle(pF6)
<nowiki> </nowiki>  PointCircle(pF7)
<nowiki> </nowiki>  PointCircle(pF8)
<nowiki> </nowiki>  local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl))
<nowiki> </nowiki>  local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl))
<nowiki> </nowiki>  local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl))
<nowiki> </nowiki>  local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl))
<nowiki> </nowiki>  local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl))
<nowiki> </nowiki>  local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl))
<nowiki> </nowiki>  local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl))
<nowiki> </nowiki>  local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl))
<nowiki> </nowiki>  local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl))
<nowiki> </nowiki>  local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))
<nowiki> </nowiki>  PointCircle(pG0)
<nowiki> </nowiki>  PointCircle(pG1)
<nowiki> </nowiki>  PointCircle(pG2)
<nowiki> </nowiki>  PointCircle(pG3)
<nowiki> </nowiki>  PointCircle(pG4)
<nowiki> </nowiki>  PointCircle(pG5)
<nowiki> </nowiki>  PointCircle(pG6)
<nowiki> </nowiki>  PointCircle(pG7)
<nowiki> </nowiki>  PointCircle(pG8)
<nowiki> </nowiki>  PointCircle(pG10)
<nowiki> </nowiki>  local pH0  = Polar2D(pt, ang + 0.0000, (1.5000 * scl))
<nowiki> </nowiki>  local pH10 = Polar2D(pt, 63.4349,      (2.7951 * scl))
<nowiki> </nowiki>  PointCircle(pH0)
<nowiki> </nowiki>  PointCircle(pH10)
<nowiki> </nowiki>  job:Refresh2DView()
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawWriterOld(what, where, size, lay, ang)
<nowiki> </nowiki>  local group
<nowiki> </nowiki> --<nowiki>[[ How to use:
  |    local TextMessage = "Your Text Here"
  |    local TextPt = Point2D(3.5,3.8)
  |    local TextHight = 0.5
  |    local TextLayer = "Jim Anderson"
  |    local TextAng = 20.0
  |    DrawWriter(TextMessage ,local TextPt , TextHight , TextLayer,TextAng )
  |    -- ==Draw Writer==
  |    -- Utilizing a provided string of text, the program walks the string and reproduces each letter (parametrically) on the drawing using vectors.
  function main()
      -- create a layer with passed name if it doesn't already exist
    local job = VectricJob()
    if not job.Exists then
          DisplayMessageBox("No job loaded")
          return false;
    end
    local TextMessage = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0 ! @ # $ % & * ( ) { } [ ] ? , . : ; '' ' _ - + = ~ ^ < > |"
     local TextPt = Point2D(0.1, 2.0)
    local TextHight = 0.25
    local TextLayer = "Gadget Text"
    local TextAng = 10.0
    DrawWriter(TextMessage, TextPt, TextHight, TextLayer, TextAng)
    job:Refresh2DView()
    return true
   end
   end
   -- -----------------------------------------------------]]</nowiki>
   return Pt1, Pt2
  <nowiki> </nowiki> -- ==============================================================================
end -- function end</nowiki>
<nowiki> </nowiki> local function Polar2D(pt, ang, dis)
 
<nowiki> </nowiki>  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
----
<nowiki> </nowiki> end
 
<nowiki> </nowiki> -- ==============================================================================
===AddGroupToJob===
<nowiki> </nowiki> local function MonoFont(job, pt, letter, scl, lay, ang)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki> </nowiki>  scl = (scl * 0.5) ;
Builds a Grouping from the layer selection.
<nowiki> </nowiki>  local pA0 = pt ;
 
<nowiki> </nowiki>  local pA1 = Polar2D(pt, ang + 90.0000, (0.2500 * scl)) ;  local pA2 = Polar2D(pt, ang + 90.0000, (0.5000 * scl)) ;
<nowiki>function AddGroupToJob(job, group, layer_name)
<nowiki> </nowiki>  local pA3 = Polar2D(pt, ang + 90.0000, (0.7500 * scl)) ;  local pA4 = Polar2D(pt, ang + 90.0000, (1.0000 * scl)) ;
  --[[  --------------- AddGroupToJob --------------------------------------------------|
<nowiki> </nowiki>  local pA5 = Polar2D(pt, ang + 90.0000, (1.2500 * scl)) ;  local pA6 = Polar2D(pt, ang + 90.0000, (1.5000 * scl)) ;
  |  Add passed group to the job - returns object created
<nowiki> </nowiki>  local pA7 = Polar2D(pt, ang + 90.0000, (1.7500 * scl)) ;  local pA8 = Polar2D(pt, ang + 90.0000, (2.0000 * scl)) ;
  | Parameters:
<nowiki> </nowiki>  local pA9 = Polar2D(pt, ang + 90.0000, (2.2500 * scl)) ;  local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl)) ;
  |    job              -- job we are working with
<nowiki> </nowiki>  local pB0 = Polar2D(pt, ang +  0.0000, (0.2500 * scl)) ;  local pB1 = Polar2D(pt, ang + 45.0000, (0.3536 * scl)) ;
  |    group            -- group of contours to  add to document
<nowiki> </nowiki>  local pB2 = Polar2D(pt, ang + 63.4352, (0.5590 * scl)) ;  local pB3 = Polar2D(pt, ang + 71.5651, (0.7906 * scl)) ;
  |    layer_name      -- name of layer group will be created on|
<nowiki> </nowiki>  local pB4 = Polar2D(pt, ang + 75.9638, (1.0308 * scl)) ;  local pB5 = Polar2D(pt, ang + 78.6901, (1.2748 * scl)) ;
  |  Return Values:
<nowiki> </nowiki>  local pB6 = Polar2D(pt, ang + 80.5376, (1.5207 * scl)) ;  local pB7 = Polar2D(pt, ang + 81.8699, (1.7678 * scl)) ;
  |    object created to represent group in document
<nowiki> </nowiki>  local pB8 = Polar2D(pt, ang + 82.8750, (2.0156 * scl)) ;  local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl)) ;
  ]]
<nowiki> </nowiki>  local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl)) ;  local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl)) ;
  --  create a CadObject to represent the  group
<nowiki> </nowiki>  local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl)) ;  local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl)) ;
  local cad_object = CreateCadGroup(group);
<nowiki> </nowiki>  local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;  local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl)) ;
  -- create a layer with passed name if it doesnt already exist
<nowiki> </nowiki>  local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl)) ;  local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;
  local layer = job.LayerManager:GetLayerWithName(layer_name)
<nowiki> </nowiki>  local pC8 = Polar2D(pt, ang + 75.9640, (2.0616 * scl)) ;  local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl)) ;
  -- and add our object to it
<nowiki> </nowiki>  local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl)) ;  local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl)) ;
  layer:AddObject(cad_object, true)
<nowiki> </nowiki>  local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl)) ;
  return cad_object
<nowiki> </nowiki>  local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl)) ;  local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl)) ;
   end -- function end</nowiki>
<nowiki> </nowiki>  local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl)) ;  local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl)) ;
 
<nowiki> </nowiki>  local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl)) ;
----
<nowiki> </nowiki>  local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl)) ;  local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl)) ;
<nowiki> </nowiki>  local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl)) ;  local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl)) ;
<nowiki> </nowiki>  local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl)) ;  local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl)) ;
<nowiki> </nowiki>  local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl)) ;  local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl)) ;
<nowiki> </nowiki>  local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl)) ;  local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl)) ;
<nowiki> </nowiki>  local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl)) ;  local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl)) ;
<nowiki> </nowiki>  local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl)) ;  local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl)) ;
<nowiki> </nowiki>  local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl)) ;  local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl)) ;
<nowiki> </nowiki>  local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl)) ;  local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl)) ;
<nowiki> </nowiki>  local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl)) ;  local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl)) ;
<nowiki> </nowiki>  local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl)) ;  local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl)) ;
<nowiki> </nowiki>  local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))      ;  local pH0 = Polar2D(pt, ang +  0.0000, (1.5000 * scl)) ;
<nowiki> </nowiki>  local pH10 = Polar2D(pt,63.4349, (2.7951 * scl))      ;  local layer = job.LayerManager:GetLayerWithName(lay) ;
<nowiki> </nowiki>  local line = Contour(0.0) ;
<nowiki> </nowiki>  -- ------------------------------------------------------------------
<nowiki> </nowiki>  if letter == 32 then
<nowiki> </nowiki>    pH0 = pH0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 33 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) line:AppendPoint(pB3) ;  line:LineTo(pE3) ;  line:LineTo(pE8) ;  line:LineTo(pB8) ;  line:LineTo(pB3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 34 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB7) ;  line:LineTo(pC10) ;
<nowiki> </nowiki>    group:AddTail(line) ;  pH0 = pE0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 35 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) ;  line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 36 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pB4) ;  line:LineTo(pA5) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) ;  line:AppendPoint(pC0) ;  line:LineTo(pE0) ;  line:LineTo(pE8) ;  line:LineTo(pC8) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 37 then
<nowiki> </nowiki>    line:AppendPoint(pC6) ;  line:LineTo(pC8) ;  line:LineTo(pA8) ;  line:LineTo(pA6) ;  line:LineTo(pE6) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pC2) ;  line:LineTo(pG2) ;  line:LineTo(pG0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 38 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA3) ;
<nowiki> </nowiki>    line:LineTo(pE6) ;  line:LineTo(pE7) ;  line:LineTo(pD8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA6) ;  line:LineTo(pG0) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 39 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  pH0 = pC0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 40 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA5) ;  line:LineTo(pA3) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  pH0 = pD0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 41 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB5) ;  line:LineTo(pB3) ;  line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pG0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 42 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;  line:LineTo(pG2) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD7) ;
<nowiki> </nowiki>    line:LineTo(pD1) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 43 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD1) ;  line:LineTo(pD7) ;
<nowiki> </nowiki>    group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 44 then
<nowiki> </nowiki>    line:AppendPoint(pC0) ;  line:LineTo(pE2) ;  line:LineTo(pC2) ;  line:LineTo(pC4) ;  line:LineTo(pF4) ;  line:LineTo(pF2) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 45 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 46 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 47 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 48 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG8) ;  line:LineTo(pA0) ; group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 49 then
<nowiki> </nowiki>    line:AppendPoint(pA6) ;  line:LineTo(pD8) ;  line:LineTo(pD0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 50 then
<nowiki> </nowiki>    line:AppendPoint(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;
<nowiki> </nowiki>    line:LineTo(pA2) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 51 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pF4) ;  line:LineTo(pB4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 52 then
<nowiki> </nowiki>    line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 53 then
<nowiki> </nowiki>    line:AppendPoint(pG8) ;  line:LineTo(pA8) ;  line:LineTo(pA5) ;  line:LineTo(pF4) ;  line:LineTo(pG3) ;  line:LineTo(pG1) ;
<nowiki> </nowiki>    line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 54 then
<nowiki> </nowiki>    line:AppendPoint(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA1) ;  line:LineTo(pB0) ;
<nowiki> </nowiki>    line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 55 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pG8) ;  line:LineTo(pA8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 56 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;
<nowiki> </nowiki>    line:LineTo(pA3) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB4) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 57 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG3) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;
<nowiki> </nowiki>    line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 58 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;
<nowiki> </nowiki>    group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 59 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB3) ;  line:LineTo(pB4) ;  line:LineTo(pA4) ;  line:LineTo(pA3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 60 then
<nowiki> </nowiki>    line:AppendPoint(pF8) ;  line:LineTo(pA4) ;  line:LineTo(pG0) ;  group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 61 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 62 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pF4) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 63 then
<nowiki> </nowiki>    line:AppendPoint(pB5) ;  line:LineTo(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pE8) ;  line:LineTo(pF7) ;
<nowiki> </nowiki>    line:LineTo(pF5) ;  line:LineTo(pC3) ;  line:LineTo(pC2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pE0) ;
<nowiki> </nowiki>    line:LineTo(pE1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 64 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  line:LineTo(pG3) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB5) ;  line:LineTo(pE5) ;  line:LineTo(pE2) ;
<nowiki> </nowiki>    group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 65 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 66 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 67 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
<nowiki> </nowiki>    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 68 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 69 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 70 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
<nowiki> </nowiki>    line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 71 then
<nowiki> </nowiki>    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
<nowiki> </nowiki>    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 72 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 73 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 74 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 75 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 76 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 77 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 78 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 79 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 80 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 81 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 82 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 83 then
<nowiki> </nowiki>    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 84 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 85 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 86 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 87 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 88 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 89 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
<nowiki> </nowiki>    line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 90 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 91 then
<nowiki> </nowiki>    line:AppendPoint(pC0) ;  line:LineTo(pB0) ;  line:LineTo(pB8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 92 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 93 then
<nowiki> </nowiki>    line:AppendPoint(pE0) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pE8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 94 then
<nowiki> </nowiki>    line:AppendPoint(pD8) ;  line:LineTo(pG6) ;  line:LineTo(pG5) ;  line:LineTo(pD7) ;  line:LineTo(pA5) ;  line:LineTo(pA6) ;
<nowiki> </nowiki>    line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 95 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 96 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  -- Start of Lower Case
<nowiki> </nowiki>  if letter == 97 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 98 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 99 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
<nowiki> </nowiki>    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 100 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 101 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 102 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
<nowiki> </nowiki>    line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 103 then
<nowiki> </nowiki>    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
<nowiki> </nowiki>    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 104 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 105 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 106 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 107 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 108 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 109 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 110 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 111 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 112 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 113 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 114 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 115 then
<nowiki> </nowiki>    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 116 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 117 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 118 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 119 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 120 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 121 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
<nowiki> </nowiki>    line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 122 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  -- End of Lower Case
<nowiki> </nowiki>  if letter == 123 then
<nowiki> </nowiki>    line:AppendPoint(pD0) ;  line:LineTo(pC0) ;  line:LineTo(pB1) ;  line:LineTo(pB2) ;  line:LineTo(pC3) ;  line:LineTo(pA4) ;
<nowiki> </nowiki>    line:LineTo(pC5) ;  line:LineTo(pB6) ;  line:LineTo(pB7) ;  line:LineTo(pC8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 124 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA10) ;  line:LineTo(pC10) ;  line:LineTo(pC0) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 125 then
<nowiki> </nowiki>    line:AppendPoint(pD0) ;  line:LineTo(pE0) ;  line:LineTo(pF1) ;  line:LineTo(pF2) ;  line:LineTo(pE3) ;  line:LineTo(pG4) ;
<nowiki> </nowiki>    line:LineTo(pE5) ;  line:LineTo(pF6) ;  line:LineTo(pF7) ;  line:LineTo(pE8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 126 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pA3) ;  line:LineTo(pB5) ;  line:LineTo(pF3) ;  line:LineTo(pG5) ;
<nowiki> </nowiki>    line:LineTo(pG4) ;  line:LineTo(pF2) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  return pH0
<nowiki> </nowiki> end -- function end
<nowiki> </nowiki> -- ==============================================================================
<nowiki> </nowiki> local function AddGroupToJob(job, group, layer_name)
<nowiki> </nowiki>    --  create a CadObject to represent the  group
<nowiki> </nowiki>  local cad_object = CreateCadGroup(group);
<nowiki> </nowiki>    -- create a layer with passed name if it doesnt already exist
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(layer_name)
<nowiki> </nowiki>    -- and add our object to it
<nowiki> </nowiki>  layer:AddObject(cad_object, true)
<nowiki> </nowiki>  return cad_object
<nowiki> </nowiki> end -- end function
<nowiki> </nowiki> -- =========================================================================
<nowiki> </nowiki>  local job = VectricJob()
<nowiki> </nowiki>  if not job.Exists then
<nowiki> </nowiki>    DisplayMessageBox("Error: Not finding a job loaded")
<nowiki> </nowiki>    return false
<nowiki> </nowiki>  end
<nowiki> </nowiki>  local strlen = string.len(what)
<nowiki> </nowiki>  local strup = string.upper(what)
<nowiki> </nowiki>  local x = strlen
<nowiki> </nowiki>  local i = 1
<nowiki> </nowiki>  local y = ""
<nowiki> </nowiki>  local ptx = where
<nowiki> </nowiki>  group = ContourGroup(true)
<nowiki> </nowiki>  while i <=  x do
<nowiki> </nowiki>    y = string.byte(string.sub(strup, i, i))
<nowiki> </nowiki>    ptx = MonoFont(job, ptx, y, size, lay, ang)
<nowiki> </nowiki>    i = i + 1
<nowiki> </nowiki>  end -- while end;
<nowiki> </nowiki>  AddGroupToJob(job, group, lay)
<nowiki> </nowiki>  job:Refresh2DView()
<nowiki> </nowiki>  return true ;
<nowiki> </nowiki> end -- Draw Text function end
<nowiki> </nowiki> -- =====================================================]]
<nowiki> </nowiki> function DrawWriter(what, where, size, lay, ang)
<nowiki> </nowiki>  local group
<nowiki> </nowiki> --<nowiki>[[ How to use:
  |    local TextMessage = "Your Text Here"
  |    local TextPt = Point2D(3.5,3.8)
  |    local TextHight = 0.5
  |    local TextLayer = "Jim Anderson"
  |    local TextAng = 20.0
  |    DrawWriter(TextMessage ,local TextPt , TextHight , TextLayer,TextAng )
  |    -- ==Draw Writer==
  |    -- Utilizing a provided string of text, the program walks the string and reproduces each letter (parametrically) on the drawing using vectors.
  function main()
      -- create a layer with passed name if it doesn't already exist
    local job = VectricJob()
    if not job.Exists then
          DisplayMessageBox("No job loaded")
          return false;
    end
    local TextMessage = "Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz 1 2 3 4 5 6 7 8 9 0 ! @ # $ % & * ( ) { } [ ] ? , . : ; '' ' _ - + = ~ ^ < > |"
    local TextPt = Point2D(0.1, 2.0)
    local TextHight = 0.25
    local TextLayer = "Gadget Text"
    local TextAng = 10.0
    DrawWriter(TextMessage, TextPt, TextHight, TextLayer, TextAng)
    job:Refresh2DView()
    return true
  end
  -- -----------------------------------------------------]]</nowiki>
<nowiki> </nowiki> -- ==============================================================================
<nowiki> </nowiki> local function Polar2D(pt, ang, dis)
<nowiki> </nowiki>  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
<nowiki> </nowiki> end
<nowiki> </nowiki> -- ==============================================================================
<nowiki> </nowiki> local function MonoFont(job, pt, letter, scl, lay, ang)
<nowiki> </nowiki>  scl = (scl * 0.5) ;
<nowiki> </nowiki>  local pA0 = pt ;
<nowiki> </nowiki>  local pA1 = Polar2D(pt, ang + 90.0000, (0.2500 * scl)) ;  local pA2 = Polar2D(pt, ang + 90.0000, (0.5000 * scl)) ;
<nowiki> </nowiki>  local pA3 = Polar2D(pt, ang + 90.0000, (0.7500 * scl)) ;  local pA4 = Polar2D(pt, ang + 90.0000, (1.0000 * scl)) ;
<nowiki> </nowiki>  local pA5 = Polar2D(pt, ang + 90.0000, (1.2500 * scl)) ;  local pA6 = Polar2D(pt, ang + 90.0000, (1.5000 * scl)) ;
<nowiki> </nowiki>  local pA7 = Polar2D(pt, ang + 90.0000, (1.7500 * scl)) ;  local pA8 = Polar2D(pt, ang + 90.0000, (2.0000 * scl)) ;
<nowiki> </nowiki>  local pA9 = Polar2D(pt, ang + 90.0000, (2.2500 * scl)) ;  local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl)) ;
<nowiki> </nowiki>  local pB0 = Polar2D(pt, ang +  0.0000, (0.2500 * scl)) ;  local pB1 = Polar2D(pt, ang + 45.0000, (0.3536 * scl)) ;
<nowiki> </nowiki>  local pB2 = Polar2D(pt, ang + 63.4352, (0.5590 * scl)) ;  local pB3 = Polar2D(pt, ang + 71.5651, (0.7906 * scl)) ;
<nowiki> </nowiki>  local pB4 = Polar2D(pt, ang + 75.9638, (1.0308 * scl)) ;  local pB5 = Polar2D(pt, ang + 78.6901, (1.2748 * scl)) ;
<nowiki> </nowiki>  local pB6 = Polar2D(pt, ang + 80.5376, (1.5207 * scl)) ;  local pB7 = Polar2D(pt, ang + 81.8699, (1.7678 * scl)) ;
<nowiki> </nowiki>  local pB8 = Polar2D(pt, ang + 82.8750, (2.0156 * scl)) ;  local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl)) ;
<nowiki> </nowiki>  local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl)) ;  local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl)) ;
<nowiki> </nowiki>  local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl)) ;  local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl)) ;
<nowiki> </nowiki>  local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;  local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl)) ;
<nowiki> </nowiki>  local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl)) ;  local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;
<nowiki> </nowiki>  local pC8 = Polar2D(pt, ang + 75.9640, (2.0616 * scl)) ;  local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl)) ;
<nowiki> </nowiki>  local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl)) ;  local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl)) ;
<nowiki> </nowiki>  local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl)) ;
<nowiki> </nowiki>  local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl)) ;  local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl)) ;
<nowiki> </nowiki>  local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl)) ;  local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl)) ;
<nowiki> </nowiki>  local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl)) ;
<nowiki> </nowiki>  local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl)) ;  local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl)) ;
<nowiki> </nowiki>  local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl)) ;  local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl)) ;
<nowiki> </nowiki>  local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl)) ;  local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl)) ;
<nowiki> </nowiki>  local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl)) ;  local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl)) ;
<nowiki> </nowiki>  local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl)) ;  local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl)) ;
<nowiki> </nowiki>  local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl)) ;  local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl)) ;
<nowiki> </nowiki>  local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl)) ;  local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl)) ;
<nowiki> </nowiki>  local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl)) ;  local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl)) ;
<nowiki> </nowiki>  local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl)) ;  local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl)) ;
<nowiki> </nowiki>  local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl)) ;  local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl)) ;
<nowiki> </nowiki>  local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl)) ;  local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl)) ;
<nowiki> </nowiki>  local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))      ;  local pH0 = Polar2D(pt, ang +  0.0000, (1.5000 * scl)) ;
<nowiki> </nowiki>  local pH10 = Polar2D(pt,63.4349, (2.7951 * scl))      ;  local layer = job.LayerManager:GetLayerWithName(lay) ;
<nowiki> </nowiki>  local line = Contour(0.0) ;
<nowiki> </nowiki>  -- ------------------------------------------------------------------
<nowiki> </nowiki>  if letter == 32 then
<nowiki> </nowiki>    pH0 = pH0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 33 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) line:AppendPoint(pB3) ;  line:LineTo(pE3) ;  line:LineTo(pE8) ;  line:LineTo(pB8) ;  line:LineTo(pB3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 34 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB7) ;  line:LineTo(pC10) ;
<nowiki> </nowiki>    group:AddTail(line) ;  pH0 = pE0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 35 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) ;  line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 36 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pB4) ;  line:LineTo(pA5) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  group:AddTail(line) ;
<nowiki> </nowiki>    line = Contour(0.0) ;  line:AppendPoint(pC0) ;  line:LineTo(pE0) ;  line:LineTo(pE8) ;  line:LineTo(pC8) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 37 then
<nowiki> </nowiki>    line:AppendPoint(pC6) ;  line:LineTo(pC8) ;  line:LineTo(pA8) ;  line:LineTo(pA6) ;  line:LineTo(pE6) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pC2) ;  line:LineTo(pG2) ;  line:LineTo(pG0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 38 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA3) ;
<nowiki> </nowiki>    line:LineTo(pE6) ;  line:LineTo(pE7) ;  line:LineTo(pD8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA6) ;  line:LineTo(pG0) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 39 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  pH0 = pC0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 40 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA5) ;  line:LineTo(pA3) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  pH0 = pD0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 41 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB5) ;  line:LineTo(pB3) ;  line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pG0
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 42 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;  line:LineTo(pG2) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD7) ;
<nowiki> </nowiki>    line:LineTo(pD1) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 43 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD1) ;  line:LineTo(pD7) ;
<nowiki> </nowiki>    group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 44 then
<nowiki> </nowiki>    line:AppendPoint(pC0) ;  line:LineTo(pE2) ;  line:LineTo(pC2) ;  line:LineTo(pC4) ;  line:LineTo(pF4) ;  line:LineTo(pF2) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 45 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 46 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 47 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 48 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG8) ;  line:LineTo(pA0) ; group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 49 then
<nowiki> </nowiki>    line:AppendPoint(pA6) ;  line:LineTo(pD8) ;  line:LineTo(pD0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 50 then
<nowiki> </nowiki>    line:AppendPoint(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;
<nowiki> </nowiki>    line:LineTo(pA2) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 51 then
<nowiki> </nowiki>    line:AppendPoint(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pF4) ;  line:LineTo(pB4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 52 then
<nowiki> </nowiki>    line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 53 then
<nowiki> </nowiki>    line:AppendPoint(pG8) ;  line:LineTo(pA8) ;  line:LineTo(pA5) ;  line:LineTo(pF4) ;  line:LineTo(pG3) ;  line:LineTo(pG1) ;
<nowiki> </nowiki>    line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 54 then
<nowiki> </nowiki>    line:AppendPoint(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA1) ;  line:LineTo(pB0) ;
<nowiki> </nowiki>    line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 55 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pG8) ;  line:LineTo(pA8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 56 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;
<nowiki> </nowiki>    line:LineTo(pA3) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB4) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 57 then
<nowiki> </nowiki>    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG3) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;
<nowiki> </nowiki>    line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 58 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;
<nowiki> </nowiki>    group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 59 then
<nowiki> </nowiki>    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB3) ;  line:LineTo(pB4) ;  line:LineTo(pA4) ;  line:LineTo(pA3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pD0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 60 then
<nowiki> </nowiki>    line:AppendPoint(pF8) ;  line:LineTo(pA4) ;  line:LineTo(pG0) ;  group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 61 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 62 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pF4) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 63 then
<nowiki> </nowiki>    line:AppendPoint(pB5) ;  line:LineTo(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pE8) ;  line:LineTo(pF7) ;
<nowiki> </nowiki>    line:LineTo(pF5) ;  line:LineTo(pC3) ;  line:LineTo(pC2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pE0) ;
<nowiki> </nowiki>    line:LineTo(pE1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 64 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;
<nowiki> </nowiki>    line:LineTo(pG6) ;  line:LineTo(pG3) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB5) ;  line:LineTo(pE5) ;  line:LineTo(pE2) ;
<nowiki> </nowiki>    group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 65 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 66 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 67 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
<nowiki> </nowiki>    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 68 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 69 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 70 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
<nowiki> </nowiki>    line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 71 then
<nowiki> </nowiki>    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
<nowiki> </nowiki>    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 72 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 73 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 74 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 75 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 76 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 77 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 78 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 79 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 80 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 81 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 82 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 83 then
<nowiki> </nowiki>    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 84 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 85 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 86 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 87 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 88 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 89 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
<nowiki> </nowiki>    line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 90 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 91 then
<nowiki> </nowiki>    line:AppendPoint(pC0) ;  line:LineTo(pB0) ;  line:LineTo(pB8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 92 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 93 then
<nowiki> </nowiki>    line:AppendPoint(pE0) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pE8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 94 then
<nowiki> </nowiki>    line:AppendPoint(pD8) ;  line:LineTo(pG6) ;  line:LineTo(pG5) ;  line:LineTo(pD7) ;  line:LineTo(pA5) ;  line:LineTo(pA6) ;
<nowiki> </nowiki>    line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 95 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 96 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  -- Start of Lower Case
<nowiki> </nowiki>  if letter == 97 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 98 then
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 99 then
<nowiki> </nowiki>    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
<nowiki> </nowiki>    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 100 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
<nowiki> </nowiki>    line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 101 then
<nowiki> </nowiki>    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
<nowiki> </nowiki>    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 102 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
<nowiki> </nowiki>    line:LineTo(pF4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 103 then
<nowiki> </nowiki>    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
<nowiki> </nowiki>    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 104 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 105 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 106 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 107 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
<nowiki> </nowiki>    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 108 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 109 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 110 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 111 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 112 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 113 then
<nowiki> </nowiki>    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
<nowiki> </nowiki>    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 114 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
<nowiki> </nowiki>    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 115 then
<nowiki> </nowiki>    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
<nowiki> </nowiki>    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 116 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
<nowiki> </nowiki>    line:LineTo(pD0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 117 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
<nowiki> </nowiki>    group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 118 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 119 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 120 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
<nowiki> </nowiki>    line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 121 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
<nowiki> </nowiki>    line:LineTo(pD4) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 122 then
<nowiki> </nowiki>    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  -- End of Lower Case
<nowiki> </nowiki>  if letter == 123 then
<nowiki> </nowiki>    line:AppendPoint(pD0) ;  line:LineTo(pC0) ;  line:LineTo(pB1) ;  line:LineTo(pB2) ;  line:LineTo(pC3) ;  line:LineTo(pA4) ;
<nowiki> </nowiki>    line:LineTo(pC5) ;  line:LineTo(pB6) ;  line:LineTo(pB7) ;  line:LineTo(pC8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 124 then
<nowiki> </nowiki>    line:AppendPoint(pA0) ;  line:LineTo(pA10) ;  line:LineTo(pC10) ;  line:LineTo(pC0) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 125 then
<nowiki> </nowiki>    line:AppendPoint(pD0) ;  line:LineTo(pE0) ;  line:LineTo(pF1) ;  line:LineTo(pF2) ;  line:LineTo(pE3) ;  line:LineTo(pG4) ;
<nowiki> </nowiki>    line:LineTo(pE5) ;  line:LineTo(pF6) ;  line:LineTo(pF7) ;  line:LineTo(pE8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  if letter == 126 then
<nowiki> </nowiki>    line:AppendPoint(pA2) ;  line:LineTo(pA3) ;  line:LineTo(pB5) ;  line:LineTo(pF3) ;  line:LineTo(pG5) ;
<nowiki> </nowiki>    line:LineTo(pG4) ;  line:LineTo(pF2) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
<nowiki> </nowiki>  end
<nowiki> </nowiki>  return pH0
<nowiki> </nowiki> end -- function end
<nowiki> </nowiki> -- ==============================================================================
<nowiki> </nowiki> local function AddGroupToJob(job, group, layer_name)
<nowiki> </nowiki>    --  create a CadObject to represent the  group
<nowiki> </nowiki>  local cad_object = CreateCadGroup(group);
<nowiki> </nowiki>    -- create a layer with passed name if it doesnt already exist
<nowiki> </nowiki>  local layer = job.LayerManager:GetLayerWithName(layer_name)
<nowiki> </nowiki>    -- and add our object to it
<nowiki> </nowiki>  layer:AddObject(cad_object, true)
<nowiki> </nowiki>  return cad_object
<nowiki> </nowiki> end -- end function
<nowiki> </nowiki> -- =========================================================================
<nowiki> </nowiki>  local job = VectricJob()
<nowiki> </nowiki>  if not job.Exists then
<nowiki> </nowiki>    DisplayMessageBox("Error: Not finding a job loaded")
<nowiki> </nowiki>    return false
<nowiki> </nowiki>  end
<nowiki> </nowiki>  local strlen = string.len(what)
<nowiki> </nowiki>  local strup = what
<nowiki> </nowiki>  local x = strlen
<nowiki> </nowiki>  local i = 1
<nowiki> </nowiki>  local y = ""
<nowiki> </nowiki>  local ptx = where
<nowiki> </nowiki>  group = ContourGroup(true)
<nowiki> </nowiki>  while i <=  x do
<nowiki> </nowiki>    y = string.byte(string.sub(strup, i, i))
<nowiki> </nowiki>    if (y >= 97) and (y <= 122) then -- Lower case
<nowiki> </nowiki>      ptx = MonoFont(job, ptx, y, (size * 0.75), lay, ang)
<nowiki> </nowiki>      ptx = Polar2D(ptx, ang, size * 0.05)
<nowiki> </nowiki>    else -- Upper case
<nowiki> </nowiki>      ptx = MonoFont(job, ptx, y, size, lay, ang)
<nowiki> </nowiki>      ptx = Polar2D(ptx, ang, size * 0.07)
<nowiki> </nowiki>    end
<nowiki> </nowiki>    i = i + 1
<nowiki> </nowiki>  end -- while end;
<nowiki> </nowiki>  AddGroupToJob(job, group, lay)
<nowiki> </nowiki>  job:Refresh2DView()
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end -- Draw Text function end
<nowiki> </nowiki> --  ====================================================]]
<nowiki> </nowiki> function Holer(pt, ang, dst, dia, lay)
<nowiki> </nowiki>    local job = VectricJob()
<nowiki> </nowiki>    if not job.Exists then
<nowiki> </nowiki>      DisplayMessageBox("Error: No job loaded")
<nowiki> </nowiki>      return false
<nowiki> </nowiki>    end
<nowiki> </nowiki>  --Caller: Holer(ptx, anx, BaseDim.HoleSpace, Milling.ShelfPinRadius, Milling.LNSideShelfPinDrill .. "-Base")
<nowiki> </nowiki>    local function AddGroupToJob(job, group, layer_name)
<nowiki> </nowiki>      local cad_object = CreateCadGroup(group);
<nowiki> </nowiki>      local layer = job.LayerManager:GetLayerWithName(layer_name)
<nowiki> </nowiki>      layer:AddObject(cad_object, true)
<nowiki> </nowiki>      return cad_object
<nowiki> </nowiki>    end
<nowiki> </nowiki>  local group = ContourGroup(true)
<nowiki> </nowiki>  group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
<nowiki> </nowiki>   pt = Polar2D(pt, ang, dst)
<nowiki> </nowiki>   group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
<nowiki> </nowiki>  AddGroupToJob(job, group, lay)
<nowiki> </nowiki>  return true
<nowiki> </nowiki> end  --  function end
-- =====================================================]]
end -- DrawTools function end


==Data Export Tools==
===DrawArc===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Draws an Arc from points provided.


  <nowiki>  
  <nowiki>function DrawArc(PtS, PtE, ArcRadius, Layer)
  --[[Draw Arc
-- =====================================================]]
  function main(script_path)
╔╦╗╔═╗╔╦╗╔═╗  ╔═╗═╗ ╦╔═╗╔═╗╦═╗╔╦╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
  local MyPt1 = Point2D(3.5,3.8)
║║╠═╣ ║ ╠═╣  ║╣ ╔╩╦╝╠═╝║ ║╠╦╝ ║    ║ ║ ║║ ║║  ╚═╗
  local MyPt2 = Point2D(3.5,6.8)
═╩╝╩ ╩ ╩ ╩ ╩  ╚═╝╩ ╚═╩  ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
  local layer = "My Arc"
function ExportTools()
  DrawArc(MyPt1, MyPt2, -0.456, Layer)
-- =====================================================]]
  return true
function LogWriter(LogName, xText)
  end -- function end
  -- Adds a new xText Line to a app log file
  -- -----------------------------------------------------]]
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
      local job = VectricJob()
  local fileW = io.open(LogName, "a")
      if not job.Exists then
  if fileW then
        DisplayMessageBox("Error: No job loaded")
    fileW:write(xText .. "\n")
        return false
    fileW:close()
      end
  end -- if end
      local line = Contour(0.0)
  Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
      local layer = job.LayerManager:GetLayerWithName(Layer)
  return true
      line:AppendPoint(PtS)
end -- function end
      line:ArcTo(PtE,1);
-- =====================================================]]
      layer:AddObject(CreateCadContour(line), true)
function Write_CSV(xFilename) -- Writes the values to a csv format file
      return true
-- Usage: Write_CSV("C:\\Path\\MyName.csv")
    end -- function end</nowiki>
-- Door.CSVPath = dialog:GetTextField("DoorCSVPath")
-- local filename = Path .. "\\" .. Name .. ".csv"
  local filename = xFilename
  xFilename
  local file = io.open(filename, "w")
  if file then  -- if the file was opened
    file:write("Count,Height,Width\n")  -- Header Line
    if Door.Unit then
      file:write("1,110,595\n");    file:write("1,150,75\n");    file:write("1,175,395\n");    file:write("1,140,495\n")
      file:write("1,175,445\n");    file:write("1,175,595\n");    file:write("2,200,100\n");    file:write("3,250,125\n")
      file:write("1,300,150\n");    file:write("2,350,175\n");    file:write("3,400,200\n");    file:write("1,450,225\n")
      file:write("2,500,250\n");    file:write("3,550,275\n");    file:write("1,600,300\n");    file:write("2,650,325\n")
      file:write("3,700,350\n");    file:write("1,750,375\n");    file:write("2,800,400\n");    file:write("3,850,425\n");
      file:write("1,900,450\n");    file:write("2,950,475\n");    file:write("3,1000,500\n");    file:write("1,1050,525\n");
      file:write("2,1100,550\n");  file:write("3,1150,575\n");  file:write("1,1200,600\n");    file:write("2,1250,625\n");
      file:write("3,1300,650\n");  file:write("1,1350,675\n");  file:write("2,1400,700\n");    file:write("3,1450,725\n");
      file:write("1,1500,750\n");  file:write("2,1550,775\n");  file:write("3,1600,800\n");    file:write("1,1650,825\n");
      file:write("2,1700,850\n");  file:write("3,1750,875\n");  file:write("1,1800,900\n");    file:write("2,1850,925\n");
      file:write("3,1900,950\n");  file:write("1,1950,975\n");  file:write("2,2000,1000\n");  file:write("3,2050,1025\n");
      file:write("1,2100,1050\n");  file:write("2,2150,1075\n");  file:write("3,2200,1100\n");  file:write("1,2250,1125\n");
      file:write("2,2300,1150\n");  file:write("3,2350,1175\n");  file:write("1,2400,1200\n");  file:write("2,2450,1225\n")
    else
      file:write("1,04.5000,23.2500\n");  file:write("1,06.0000,03.3125\n");  file:write("1,06.5000,15.5000\n");  file:write("1,05.3750,19.5000\n");
      file:write("1,07.1875,17.5000\n");  file:write("1,06.1875,23.5000\n");  file:write("2,07.8750,03.8750\n");  file:write("3,09.8750,05.0000\n");
      file:write("1,11.7500,05.8750\n");  file:write("2,13.7500,06.6750\n");  file:write("3,15.7500,07.8750\n");  file:write("1,17.1250,08.8250\n");
      file:write("2,19.5000,09.5000\n");  file:write("3,21.1250,10.3750\n");  file:write("1,23.6250,11.1250\n");  file:write("2,25.5000,12.1250\n");
      file:write("3,27.6250,13.7500\n");  file:write("1,29.5000,14.7500\n");  file:write("2,31.4375,15.7500\n");  file:write("3,33.4375,16.7500\n");
      file:write("1,35.4375,17.7500\n");  file:write("2,37.4375,18.6250\n");  file:write("3,39.3750,19.6250\n");  file:write("1,41.3750,20.6250\n");
      file:write("2,43.3750,21.6250\n");  file:write("3,45.1875,22.6250\n");  file:write("1,47.2500,23.6250\n");  file:write("2,49.1875,24.6250\n");
      file:write("3,51.1250,25.5000\n");  file:write("1,53.1250,26.5000\n");  file:write("2,55.1250,27.5000\n");  file:write("3,57.1250,28.5000\n");
      file:write("1,59.1250,29.5000\n");  file:write("2,61.2500,30.5000\n");  file:write("3,62.9375,31.4375\n");  file:write("1,64.9375,32.4375\n");
      file:write("2,66.9375,33.4375\n");  file:write("3,68.8125,34.4375\n");  file:write("1,70.8750,35.3750\n");  file:write("2,72.9375,36.4375\n");
      file:write("3,74.8750,37.4375\n");  file:write("1,76.9375,38.3750\n");  file:write("2,78.7500,39.3750\n");  file:write("3,80.7500,40.3750\n");
      file:write("1,82.6250,41.3750\n");  file:write("2,84.6250,42.3750\n");  file:write("3,86.6250,43.3750\n");  file:write("1,88.5000,44.2500\n");
      file:write("2,90.6250,45.2500\n");  file:write("3,92.6250,46.2500\n");  file:write("1,94.4375,47.2500\n");  file:write("2,95.4375,48.2500\n")
    end -- if end
    file:close()-- closes the open file
  end -- if end
  return true
end
-- =====================================================]]
end -- ExportTools function end


----


</nowiki>
===DrawEllipse===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Draws a DrawEllipse from points provided.
 
<nowiki>function DrawEllipse(CenterPt, LongAxe, ShortAxe, Layer)
  local LongAngle = 90.0
  local ValueAB = (LongAxe - ShortAxe) * 0.50
  local ValueAC = ValueAB * math.cos(math.rad(LongAngle))
  local job = VectricJob()
  local LRad = LongAxe * 0.50
  local ptT = Polar2D(CenterPt, LongAngle, LRad)
  local X = 0.0
  local pty = Point2D(0.0,0.0)
  local ptx = Point2D(0.0,0.0)
  local mylayer = job.LayerManager:GetLayerWithName(Layer)
  local line = Contour(0.0)
        line:AppendPoint(ptT)
    while (X < 360.0) do
        pty = Polar2D(CenterPt, LongAngle + X, LRad)
    ValueAC = ValueAB * math.cos(math.rad(LongAngle + X))
    if ((LongAngle + X) >= 90.0) then
      ptx = Polar2D(pty, 180.0, ValueAC)
    else
      ptx = Polar2D(pty,  0.0, ValueAC)
    end
    line:LineTo(ptx)
    X = X + 1
  end -- while end
  line:LineTo(ptT)
  mylayer:AddObject(CreateCadContour(line), true)
  return true
end -- function end</nowiki>
 
----


==Text File Tools==
===DrawEllipse1===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Draws a DrawEllipse from points provided.


  <nowiki>  
  <nowiki>function DrawEllipse1(DrawEllipse_CenterPt, DrawEllipse_LongAxe, DrawEllipse_ShortAxe, DrawEllipse_LongAxeAngle, DrawEllipse_Layer)
    -- ---------------------------------------------------]]
    function H(x)                                        -- Returns half the value
      return x * 0.5
    end -- function end
    -- ---------------------------------------------------]]
    function Polar2D(pt, ang, dis)                        -- Calculate a new point based on reference point, angle and distance.
    -- Returns a 2Dpoint(x, y)
      return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
    end -- End Function
    -- ---------------------------------------------------]]
    function GetDistance(objA, objB)
      local xDist = objB.x - objA.x
      local yDist = objB.y - objA.y
      return math.sqrt((xDist ^ 2) + (yDist ^ 2))
    end -- function end
    -- ---------------------------------------------------]]
    function Radius2Bulge (p1, p2, Rad)
      local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
      local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
      local bulge = (2 * seg) / chord
      return bulge
    end -- function end
    -- ---------------------------------------------------]]
  function GetPolarAngle(Start, Corner, End)
    local function GetPolarDirection(point1, point2)              --
      local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
      if point1.X < point2.X then
        if point1.Y < point2.Y then
          ang = ang + 0.0
        else
          ang = 360.0 - ang
        end -- if end
      else
        if point1.Y < point2.Y then
          ang = 180.0 - ang
        else
          ang = ang + 180.0
        end -- if end
      end -- if end
      if ang >=360 then
        ang = ang -360.0
      end -- if end
      return ang
    end -- function end
    return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
  end -- function end
    -- ---------------------------------------------------]]
   
   
-- =====================================================]]
    -- Call = DrawEllipse(2DPoint(20.0, 20.0), 20.0, 10.0, 0.0, "Jim")
╔╦╗═╗ ╦╔╦╗ ╔═╗╦╦  ╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
    local job = VectricJob()
  ║ ╔╩╦╝ ║  ╠╣ ║║ ║╣    ║ ║ ║║ ║║  ╚═╗
    local EndRadius = 0.0
  ╩ ╩ ╚═ ╩  ╚ ╩╩═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
    local TopRadius = 0.0
function FileTools()
    local ptT = Polar2D(DrawEllipse_CenterPt,  (90.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
-- =====================================================]]
    local ptB = Polar2D(DrawEllipse_CenterPt, (270.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
  function LengthOfFile(filename)                       -- Returns file line count
    local ptR = Polar2D(DrawEllipse_CenterPt,  (0.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
--[[Counts the lines in a file
    local ptL = Polar2D(DrawEllipse_CenterPt, (180.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
    Returns: number]]
    local ptC = DrawEllipse_CenterPt
    local len = 0
    --[[
    if FileExists(filename) then
      DMark("ptC", ptC)
      local file = io.open(filename)
      DMark("ptT", ptT)
      if file then
      DMark("ptB", ptB)
      for _ in file:lines() do
      DMark("ptL", ptL)
        len = len + 1
      DMark("ptR", ptR)]]
      end
    local C_Offset = H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe)
      file:close()
    local LT_SlopeDist = H(GetDistance(ptL, ptT) - H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe))
    end -- if end
    local LT_Dist  = GetDistance(ptL, ptT)
    end
    local LT_Angle = math.abs(90.0 - GetAngle(ptT, ptL, ptC))
    return len
    local pt_a = Polar2D(ptL, LT_Angle + DrawEllipse_LongAxeAngle, LT_SlopeDist)
   end -- function end
    local aT_Dist  = GetDistance(pt_a, ptT)
   -- =====================================================]]
    local aC_Dist = aT_Dist / (math.tan(math.rad(LT_Angle)))
  function NameValidater(FileName)
    local Tc_Dist = math.sqrt(aT_Dist^2 + aC_Dist^2)
    local MyTrue = true
    local pt_c = Polar2D(ptT, (270.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
    local strlen = string.len(FileName)
    local cC_Dist  = GetDistance(pt_c, ptC)
    local strup = string.upper(FileName)
    local b_Dist = math.tan(math.rad(LT_Angle)) * cC_Dist
    local i = 1
    local pt_b = Polar2D(ptC, (180.0 + DrawEllipse_LongAxeAngle), b_Dist)
    local y = ""
    local pt_d = Polar2D(ptB,  (90.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
    while i <=  strlen do
    local pt_e = Polar2D(ptC,  (0.0 + DrawEllipse_LongAxeAngle), b_Dist)
      y = string.byte(string.sub(strup, i, i))
    local pt1  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
      if y == 32 then  --  Space
    local pt2 = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
        MyTrue = false
    local pt3 = Polar2D(pt_c, (90.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
        break
    local pt4 = Polar2D(pt_c, (90.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
      elseif y == 45 then  -- Dash
    --[[
        MyTrue = false
      DMark("pt1", pt1)
        break
      DMark("pt2", pt2)
      elseif y == 127 then  -- Delete
      DMark("pt3", pt3)
        MyTrue = false
      DMark("pt4", pt4)
        break
      local line = Contour(0.0)
      elseif y == 126 then  -- Delete
      local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
        MyTrue = false
      line:AppendPoint(pt1)
        break
      line:LineTo(pt2)
      line:LineTo(pt3)
      line:LineTo(pt4)
      line:LineTo(pt1)
      layer:AddObject(CreateCadContour(line), true)]]
    local T_Sec   = GetDistance(ptC, ptT) - H(GetDistance(pt1, pt4))
    local R_Sec   = GetDistance(ptC, ptR) - H(GetDistance(pt1, pt2))
    local T_Chor  = GetDistance(pt1, pt2)
    local R_Chor  = GetDistance(pt1, pt4)
    local T_Bulge = Radius2Bulge (pt1, pt2, Tc_Dist)
    local L_Bulge = Radius2Bulge (pt1, pt4, GetDistance(ptL, pt_b))
    local line = Contour(0.0)
    local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
    line:AppendPoint(pt1)
    line:ArcTo(pt2, T_Bulge)
    line:ArcTo(pt3, L_Bulge)
    line:ArcTo(pt4, T_Bulge)
    line:ArcTo(pt1, L_Bulge)
    layer:AddObject(CreateCadContour(line), true)
    job:Refresh2DView()
    return true
  end -- function end</nowiki>
 
----


      elseif y == 123 then  -- Open brace
===DrawBox===
        MyTrue = false
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
        break
Draws a Box from points provided.
      elseif y == 124 then  -- Pipe
        MyTrue = false
        break
      elseif y == 125 then  -- Close brace
        MyTrue = false
        break


      elseif -- Illegal Filename Characters
  <nowiki>function DrawBox(p1, p2, p3, p4, Layer)
      (y == 33) or -- ! Exclamation mark
    --[[ Draw Box
      (y == 34) or -- " Double Quotes
    function main(script_path)
      (y == 35) or -- # Hash
    local MyPt1 = Point2D(1.0,1.0)
      (y == 36) or -- $ Dollar
    local MyPt2 = Point2D(1.0,3.0)
      (y == 37) or -- % Percent
    local MyPt3 = Point2D(3.0,1.0)
      (y == 38) or -- & Ampersand
    local MyPt4 = Point2D(3.0,3.0)
      (y == 39) or -- ' Apostrophe
    local layer = "My Box"
      (y == 42) or -- * Asterisk
    DrawBox(MyPt1 ,MyPt2, MyPt3, MyPt4, Layer)
      (y == 43) or -- + Plus
    return true
      (y == 44) or -- , Comma
    end -- function end
      (y == 47) or -- / Slash
  -- -----------------------------------------------------]]
      (y == 58) or -- : Colon
      local job = VectricJob()
      (y == 59) or -- ; Semi-colon
      if not job.Exists then
      (y == 60) or -- < Less than
        DisplayMessageBox("Error: No job loaded")
      (y == 62) or -- > Greater than
        return false
      (y == 63) or -- ? Question mark
      end -- if end
      (y == 64) or -- @ At
      local line = Contour(0.0)
      (y == 92) or -- \ Backslash
      local layer = job.LayerManager:GetLayerWithName(Layer)
      (y == 96) or -- ` Single Quotes
      line:AppendPoint(p1)
      (y == 123) or -- { Open brace
      line:LineTo(p2)
      (y == 124) or -- | Pipe
      line:LineTo(p3)
      (y == 125)    -- } Close brace
      line:LineTo(p4)
      then
      line:LineTo(p1)
        MyTrue = false
      layer:AddObject(CreateCadContour(line), true)
        break
      return true
      elseif (y <= 31) then -- Control Codes
end -- function end</nowiki>
        MyTrue = false
 
        break
----
      elseif (y >= 48) and (y <= 57) then -- Numbers
 
        MyTrue = false
===DrawCircle===
        break
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
Draws a circle.
        MyTrue = false
 
        break
  <nowiki>function DrawCircle(Pt1, CenterRadius, Layer)
      elseif (y >= 97) and (y <= 122) then -- Lowercase A to Z
  --[[ ==Draw Circle==
        MyTrue = false
    function main(script_path)
        break
    local MyPt1 = Point2D(1.0,1.0)
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
    local MyRad = 3.0
        MyTrue = false
    local layer = "My Box"
        break
    DrawCircle(MyPt1, MyRad, Layer)
      end -- if end
    return true
      i = i + 1 end -- while end;
    end -- function end
    return MyTrue
  -- -----------------------------------------------------]]
  end -- if end
    local job = VectricJob()
-- =====================================================]]
    if not job.Exists then
  function CopyFileFromTo(OldFile, NewFile)             -- Copy Old File to Newfile
      DisplayMessageBox("Error: No job loaded")
    if FileExists(NewFile) then
      return false
      DisplayMessageBox("File copy " .. File .. " failed. \n\nFile found at: " .. NewFile  .. "\n" )
    end -- if end
      return false
    local pa = Polar2D(Pt1,   180.0, CenterRadius)
    elseif not FileExists(OldFile) then
    local pb = Polar2D(Pt1,    0.0, CenterRadius)
      DisplayMessageBox("File copy of " .. File .. " failed. \n\nFile not found at: " .. OldFile .. "\n" )
    local Contour = Contour(0.0)
      return false
    local layer = job.LayerManager:GetLayerWithName(Layer)
    else
    Contour:AppendPoint(pa)
      local fileR = io.open(OldFile)      -- reader file
    Contour:ArcTo(pb, 1)
      local fileW = io.open(NewFile, "w") -- writer file
    Contour:ArcTo(pa, 1)
      if fileR and fileW then  -- if both files are open
    layer:AddObject(CreateCadContour(Contour), true)
        for Line in fileR:lines() do
    return true
          fileW:write(Line .. "\n")
end -- function end</nowiki>
        end -- for end
 
      end
----
      if fileR then fileR:close() end
 
      if fileW then fileW:close() end
 
      return true
===DrawLine===
    end -- for end
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  end -- function end
Draws a Line from points provided.
-- =====================================================]]
 
  function ValidateName(FileName)                      -- Returns True if the file name is safe to use
<nowiki>function DrawLine(Pt1, Pt2, Layer)
  local MyTrue = true
  --[[Draws a line from Pt1 to Pt2 on the layer name.
  local strlen = string.len(FileName)
  function main(script_path)
  local strup = string.upper(FileName)
  local MyPt1 = Point2D(3.5,3.8)
  local i = 1
  local MyPt2 = Point2D(3.5,6.8)
  local y = ""
  local layer = "My Line"
   while i <=  strlen do
  DrawLine(MyPt1 , MyPt2, MyPt3, Layer)
    y = string.byte(string.sub(strup, i, i))
  return true
    if y == 32 then -- Space
  end -- function end
      MyTrue = true
  -- -----------------------------------------------------]]
    elseif y == 45 then -- hyphn
    local job = VectricJob()
      MyTrue = true
    if not job.Exists then
    elseif (y >= 48) and (y <= 57) then -- numbers
      DisplayMessageBox("Error: No job loaded")
      MyTrue = true
      return false
    elseif (y >= 65) and (y <= 90) then -- Uppercase
    end
      MyTrue = true
    local line = Contour(0.0)
    else
    local layer = job.LayerManager:GetLayerWithName(Layer)
      MyTrue = false
    line:AppendPoint(Pt1)
      break
    line:LineTo(Pt2)
    end -- if end
    layer:AddObject(CreateCadContour(line), true)
    i = i + 1
    return true
  end -- while end
end -- function end</nowiki>
  return MyTrue
 
end -- if end
----
-- =====================================================]]
 
  function FileExists(name)                             -- Returns True if file is found
===DrawStar===
  -- call = ans = FileExists("sample.txt")
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    local f=io.open(name,"r")
Draws a Star from points provided.
    if f~=nil then io.close(f) return true else io.close(f) return false end
 
  end -- end function
<nowiki>function DrawStar(pt1, InRadius ,OutRadius, layer)     --This draw function requires the center point, inter star radius, outer star radius and layer name.
  -- ===================================================]]
  --[[
  function FileAccess(FileName)                        -- Returns true if file is available for update.
    function main(script_path)
    if (not(os.rename(FileName, FileName))) then
      local MyPt = Point2D(3.5,3.8)
      StatusMessage("Error", FileName, "The Gadget cannot access the ".. FileName ..
      local InRadius = 9.0
        " The OS has blocked write access. " ..
      local OutRadius= 20.0
        "Verify the full path is correct and No application has the file open. ", "(1405)")
      local layer = "My Star"
        return false
      DrawStar(MyPt , InRadius ,OutRadius, layer)
  else
      return true
    return true
    end -- function end
  end -- if end
  -- -----------------------------------------------------]]
end -- function end
    local job = VectricJob()
-- =====================================================]]
    if not job.Exists then
  function isdir(path)                                 -- Returns true if path is found
      DisplayMessageBox("Error: No job loaded")
  local function exists(file)
      return false
    local ok, err, code = os.rename(file, file)
    end
    if not ok then
    local p1 = Polar2D(pt1,  18.0,  OutRadius)
      if code == 13 then
    local p2 = Polar2D(pt1, 54.0,  InRadius)
        return true
    local p3 =  Polar2D(pt1, 90.0,  OutRadius)
      end
    local p4 = Polar2D(pt1,  126.0, InRadius)
    end
    local p5 = Polar2D(pt1, 162.0, OutRadius)
    return ok, err
    local p6 = Polar2D(pt1, 198.0, InRadius)
  end
    local p7 = Polar2D(pt1,  234.0, OutRadius)
  return exists(path.."/")
    local p8 = Polar2D(pt1,  270.0, InRadius)
end
    local p9 = Polar2D(pt1, 306.0, OutRadius)
-- =====================================================]]
    local p0 = Polar2D(pt1, 342.0, InRadius)
  function Sheetlabel(Wpt, xTextHeight,  xThickness, xType, YY) -- Constructs sheet label
    local line = Contour(0.0)
  local pt1Text = Point2D()
    -- local layers = job.LayerManager:GetLayerWithName(layer)
  local Pang    = 0.0
    line:AppendPoint(p1);
  local Tang    = 0.0
    line:LineTo(p2);  line:LineTo(p3)
  if YY then
    line:LineTo(p4);  line:LineTo(p5)
    pt1Text = Polar2D(Polar2D(Wpt, 90.0,  YY), 90.0,  6.0 * JimAndi.Cal)
    line:LineTo(p6);  line:LineTo(p7)
    Pang = 270.0
    line:LineTo(p8);  line:LineTo(p9)
    Tang = 0.0
    line:LineTo(p0);  line:LineTo(p1)
  else
    layer:AddObject(CreateCadContour(line), true)
    if Material.Orientation == "V" then
    job:Refresh2DView()
      pt1Text = Polar2D(Wpt, 90.0, Milling.MaterialBlockWidth + (4.0 * JimAndi.Cal))
    return true
    else
end -- function end</nowiki>
      pt1Text = Polar2D(Wpt, 90.0,  Milling.MaterialBlockHeight + (4.0 * JimAndi.Cal))
 
    end
----
    Pang = 270.0
 
    Tang = 0.0
===DrawTriangle===
  end
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  DrawWriter(Project.ProgramName, pt1Text, Milling.TextHeight * 3.0, JimAndi.LNDrawNotes, Tang)
Draws a Triangle from points provided.
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 3.35)
 
  DrawWriter("Cabinet ID: " .. Project.DrawerID, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
<nowiki>function DrawTriangle(p1, p2, p3, Layer)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
  --<nowiki>[[Draw Triangle
  DrawWriter("Cabinet Name: " .. Project.CabinetName, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
    function main(script_path)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
      local MyPt1 = Point2D(3.5,3.8)
  if xThickness then
      local MyPt2 = Point2D(3.5,6.8)
    DrawWriter("Material: " .. xThickness .. " " .. xType, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
      local MyPt3 = Point2D(9.8,6.8)
  end -- if end
      local layer = "My Triangle"
end -- function end
      DrawTriangle(MyPt1 , MyPt2, MyPt3, Layer)
-- =====================================================]]
      return true
  function DiskRights(path)                             -- Returns true if you have write access to path.
    end -- function end
  xx = io.open(path, "w")
    local job = VectricJob()
  if xx == nil then
    if not job.Exists then
      io.close()
      DisplayMessageBox("Error: No job loaded")
      return false
      return false
  else
    end
      xx:close()
    local line = Contour(0.0)
      return true
    local layer = job.LayerManager:GetLayerWithName(Layer)
  end
    line:AppendPoint(p1)
end -- function rights
    line:LineTo(p2)
-- =====================================================]]
    line:LineTo(p3)
end -- FileTools function end
    line:LineTo(p1)
 
    layer:AddObject(CreateCadContour(line), true)
 
    job:Refresh2DView()
</nowiki>
    return true
 
  end -- function end
==Geometry Tools==
  -- =====================================================]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
  function Radius2Bulge (p1, p2, Rad)
 
    local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
<nowiki>
    local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
    local bulge = (2 * seg) / chord
-- =====================================================]]
    return bulge
╔═╗╔═╗╔═╗╔╦╗╔═╗╔╦╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
  end
║ ╦║╣ ║ ║║║║║╣  ║ ╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
  -- =====================================================]]
╚═╝╚═╝╚═╝╩ ╩╚═╝ ╩ ╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
  function ChordSeg2Radius (Chr, Seg)
function GeometryTools()
    local rad =  (((Chr * Chr)/(Seg * 4)) + Seg) / 2.0
-- =====================================================]]
    return rad
function SheetNew()                                     -- Adds a new sheet to the drawing
end -- function end</nowiki>
  if GetVersion() >= 10.5 then then
 
    local layer_manager = Milling.job.LayerManager
----
    -- get current sheet count - note sheet 0 the default sheet counts as one sheet
 
    local orig_num_sheets = layer_manager.NumberOfSheets
===CreateJob===
    -- get current active sheet index
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    local orig_active_sheet_index = layer_manager.ActiveSheetIndex
Create a new job/drawing setup.
    -- set active sheet to last sheet
 
    local num_sheets = layer_manager.NumberOfSheets
<nowiki>function CreateJob(job_name, width, height, thickness, in_mm, job_origin, z_on_surface)
    layer_manager.ActiveSheetIndex = num_sheets - 1
--[[ ----------- CreateJob -------------------------------------------------
    -- Add a new sheet
  | This function was provided "as is" by Vectric technical team and a part of the gadget API documentation.
    layer_manager:AddNewSheet()
  | Create a new empty job with the passed settings]]
    -- set active sheet to last sheet we just added
  -- we fill in most of our bounds in a Box2D
    num_sheets = layer_manager.NumberOfSheets
  local job_bounds = Box2D()
    layer_manager.ActiveSheetIndex = num_sheets - 1
  local blc = Point2D(0, 0)
    Milling.job:Refresh2DView()
  local trc = Point2D(width, height)
  end -- if end
  local origin_offset = Vector2D(0,0)
  return true
  -- calculate bottom left corner offset for chosen origin
end
  if Template.DXFOrientation == "Vertical" then
-- =====================================================]]
    trc = Point2D(height, width)
function GetDiameterAndCentre(cadcontour, point2d)
    if (job_origin == "BLC") then
  local contour = cadcontour:GetContour()
      origin_offset:Set(0, 0)
  local arc = contour:GetFirstSpan()
    elseif (job_origin == "BRC") then
  local point3d = Point3D();
      origin_offset:Set(height, 0)
  arc = CastSpanToArcSpan(arc)
    elseif (job_origin == "TRC") then
  local diameter = arc:RadiusAndCentre(point3d) * 2.0
      origin_offset:Set(height, width)
  point2d = Point2D(point3d.x, point3d.y)
    elseif (job_origin == "TLC") then
  -- MessageBox("Diameter = " .. diameter)
      origin_offset:Set(0, width)
  return diameter, point2d
    elseif (job_origin == "CENTRE") then
end
      origin_offset:Set(height / 2, width / 2)
-- =====================================================]]
    elseif (job_origin == "CENTER") then
function IsCircle(cadcontour)                           -- Returns True if conture is a circle
      origin_offset:Set(height / 2, width / 2)
  local contour = cadcontour:GetContour()
    else
  -- Does it consist only of arcs?
      MessageBox("Unknown XY origin specified " .. job_origin)
  if contour.ContainsBeziers then
    end
    return false
  else
  end
    if (job_origin == "BLC") then
  if not contour.ContainsArcs then
      origin_offset:Set(0, 0)
    return false
    elseif (job_origin == "BRC") then
  end
      origin_offset:Set(width, 0)
  -- Does is contain 4 contours?
    elseif (job_origin == "TRC") then
  if contour.Count ~= 4 then
      origin_offset:Set(width, height)
    return false;
    elseif (job_origin == "TLC") then
  end
      origin_offset:Set(0, height)
  -- Check the arcs end and initial points make a square.
    elseif (job_origin == "CENTRE") then
  local arcs = {}
      origin_offset:Set(width / 2, height / 2)
  local count = 1;
    elseif (job_origin == "CENTER") then
  local pos = contour:GetHeadPosition()
      origin_offset:Set(width / 2, height / 2)
  local object
    else
  while pos ~= nil do
      MessageBox("Unknown XY origin specified " .. job_origin)
    object, pos = contour:GetNext(pos)
    end
    arcs[count] = object
  end
    count = count + 1
  -- subtract the origin offset vector from our 'standard' corner positions to get position for corners for requested origin
  end
  blc = blc - origin_offset
  local x_1 =(arcs[1]).StartPoint2D.x
  trc = trc - origin_offset
  local y_1 =(arcs[1]).StartPoint2D.y
  job_bounds:Merge(blc)
  local x_3 =(arcs[3]).StartPoint2D.x
  job_bounds:Merge(trc)
  local y_3 =(arcs[3]).StartPoint2D.y
  local success = CreateNewJob(job_name,job_bounds,thickness,in_mm,z_on_surface)
  local x_2 =(arcs[2]).StartPoint2D.x
  return success
  local y_2 =(arcs[2]).StartPoint2D.y
end -- function end</nowiki>
  local x_4 =(arcs[4]).StartPoint2D.x
 
  local y_4 =(arcs[4]).StartPoint2D.y
----
  local horizontal_distance = (x_1 - x_3)*(x_1 - x_3) + (y_1 - y_3)*(y_1 - y_3)
 
  local vertical_distance = (x_4 - x_2)*(x_4 - x_2) + (y_2 - y_4)*(y_2 - y_4)
===DrawFontGrid - Draws font grid to create letters===
  if math.abs(horizontal_distance - vertical_distance) > 0.04 then
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
    return false
Draws the font grid for drawing new letters.
  end
 
  -- Check the bulge factor is 90
<nowiki>function DrawFontGrid(job)
  local bulge = 0;
    local pt = Point2D(0.3,0.3)
  for _, arc_span in ipairs(arcs) do
    local scl  = 1.0 -- (scl * 0.5)
    bulge = CastSpanToArcSpan(arc_span).Bulge;
    local pA0  = pt
    if math.abs(math.abs(bulge) - g_bulge90) > 0.04 then
    local ang  = 0.0
      return false
    local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl))
    end
    local pA2  = Polar2D(pt, ang + 90.0000, (0.5000 * scl))
  end
    local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl))
    local pA4  = Polar2D(pt, ang + 90.0000, (1.0000 * scl))
    local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl))
    local pA6  = Polar2D(pt, ang + 90.0000, (1.5000 * scl))
    local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl))
    local pA8  = Polar2D(pt, ang + 90.0000, (2.0000 * scl))
    local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl))
    local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl))
    PointCircle(pA0)
    PointCircle(pA1)
    PointCircle(pA2)
    PointCircle(pA3)
    PointCircle(pA4)
    PointCircle(pA5)
    PointCircle(pA6)
    PointCircle(pA7)
    PointCircle(pA8)
    PointCircle(pA9)
    PointCircle(pA10)
    local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl))
    local pB1  = Polar2D(pt, ang + 45.0000, (0.3536 * scl))
    local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl))
    local pB3  = Polar2D(pt, ang + 71.5651, (0.7906 * scl))
    local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl))
    local pB5  = Polar2D(pt, ang + 78.6901, (1.2748 * scl))
    local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl))
    local pB7  = Polar2D(pt, ang + 81.8699, (1.7678 * scl))
    local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl))
    local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl))
    PointCircle(pB0)
    PointCircle(pB1)
    PointCircle(pB2)
    PointCircle(pB3)
    PointCircle(pB4)
    PointCircle(pB5)
    PointCircle(pB7)
    PointCircle(pB8)
    PointCircle(pB10)
    local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl))
    local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl))
    local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl))
    local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl))
    local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
    local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl))
    local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl))
    local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
    local pC8 = Polar2D(pt, ang + 74.0550, (1.8201 * scl))
    local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl))
    PointCircle(pC0)
    PointCircle(pC1)
    PointCircle(pC2)
    PointCircle(pC3)
    PointCircle(pC4)
    PointCircle(pC6)
    PointCircle(pC8)
    PointCircle(pC10)
    local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl))
    local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl))
    local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
    local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl))
    local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl))
    local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl))
    PointCircle(pD0)
    PointCircle(pD1)
    PointCircle(pD2)
    PointCircle(pD4)
    PointCircle(pD7)
    PointCircle(pD8)
    local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl))
    local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl))
    local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
    local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl))
    local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl))
    local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl))
    local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl))
    local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl))
    PointCircle(pE0)
    PointCircle(pE1)
    PointCircle(pE2)
    PointCircle(pE3)
    PointCircle(pE5)
    PointCircle(pE6)
    PointCircle(pE7)
    PointCircle(pE8)
    local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl))
    local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl))
    local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl))
    local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl))
    local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl))
    local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl))
    local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl))
    local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl))
    local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl))
    PointCircle(pF0)
    PointCircle(pF1)
    PointCircle(pF2)
    PointCircle(pF3)
    PointCircle(pF4)
    PointCircle(pF5)
    PointCircle(pF6)
    PointCircle(pF7)
    PointCircle(pF8)
    local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl))
    local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl))
    local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl))
    local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl))
    local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl))
    local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl))
    local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl))
    local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl))
    local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl))
    local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))
    PointCircle(pG0)
    PointCircle(pG1)
    PointCircle(pG2)
    PointCircle(pG3)
    PointCircle(pG4)
    PointCircle(pG5)
    PointCircle(pG6)
    PointCircle(pG7)
    PointCircle(pG8)
    PointCircle(pG10)
    local pH0  = Polar2D(pt, ang + 0.0000, (1.5000 * scl))
    local pH10 = Polar2D(pt, 63.4349,      (2.7951 * scl))
    PointCircle(pH0)
    PointCircle(pH10)
    job:Refresh2DView()
    return true
  end
  -- =========================================================================
  local function AddGroupToJob(job, group, layer_name)
      --  create a CadObject to represent the group
    local cad_object = CreateCadGroup(group);
      -- create a layer with passed name if it doesnt already exist
    local layer = job.LayerManager:GetLayerWithName(layer_name)
      -- and add our object to it
    layer:AddObject(cad_object, true)
    return cad_object
  end -- end function
  -- =========================================================================
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: Not finding a job loaded")
      return false
    end
    local strlen = string.len(what)
    local strup = string.upper(what)
    local x = strlen
    local i = 1
    local y = ""
    local ptx = where
    group = ContourGroup(true)
    while i <=  x do
      y = string.byte(string.sub(strup, i, i))
      ptx = MonoFont(job, ptx, y, size, lay, ang)
      i = i + 1
    end -- while end;
    AddGroupToJob(job, group, lay)
    job:Refresh2DView()
    return true ;
end -- function end</nowiki>
 
----
 
===DrawWriter - Draws Upper and Lower case text on the drawing===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
<nowiki>function DrawWriter(what, where, size, lay, ang) -- Draws Upper and Lower case text on the drawing.
  --[[ How to use:
  |    local TextMessage = "Your Text Here"
  |    local TextPt = Point2D(3.5,3.8)
  |    local TextHight = 0.5
  |    local TextLayer = "Text Layer"
  |    local TextAng = 20.0
  |    DrawWriter(TextMessage, TextPt , TextHight , TextLayer, TextAng)
  |    -- ==Draw Writer==
  |    -- Utilizing a provided string of text, the program walks the string and reproduces each letter (parametrically) on the drawing using vectors.
  function main()
      -- create a layer with passed name if it doesn't already exist
    local job = VectricJob()
    if not job.Exists then
          DisplayMessageBox("No job loaded")
          return false;
    end
    local TextMessage = "Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz 1 2 3 4 5 6 7 8 9 0 ! @ # $ % & * ( ) { } [ ] ? , . : ; '' ' _ - + = ~ ^ < > |"
    local TextPt = Point2D(0.1, 2.0)
    local TextHight = 0.25
    local TextLayer = "Gadget Text"
    local TextAng = 10.0
    DrawWriter(TextMessage, TextPt, TextHight, TextLayer, TextAng)
    job:Refresh2DView()
    return true
  end
  --]]
  -- =========================================================================
  local function Polar2D(pt, ang, dis)
    return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
  end
  -- =========================================================================
  local function MonoFont(job, pt, letter, scl, lay, ang)
    scl = (scl * 0.5) ;
    local pA0 = pt ;
    local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl)) ;  local pA2  = Polar2D(pt, ang + 90.0000, (0.5000 * scl)) ;
    local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl)) ;  local pA4  = Polar2D(pt, ang + 90.0000, (1.0000 * scl)) ;
    local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl)) ;  local pA6  = Polar2D(pt, ang + 90.0000, (1.5000 * scl)) ;
    local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl)) ;  local pA8  = Polar2D(pt, ang + 90.0000, (2.0000 * scl)) ;
    local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl)) ;  local pA10  = Polar2D(pt, ang + 90.0000, (2.5000 * scl)) ;
    local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl)) ;  local pB1  = Polar2D(pt, ang + 45.0000, (0.3536 * scl)) ;
    local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl)) ;  local pB3  = Polar2D(pt, ang + 71.5651, (0.7906 * scl)) ;
    local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl)) ;  local pB5  = Polar2D(pt, ang + 78.6901, (1.2748 * scl)) ;
    local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl)) ;  local pB7  = Polar2D(pt, ang + 81.8699, (1.7678 * scl)) ;
    local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl)) ;  local pB10  = Polar2D(pt, ang + 84.2894, (2.5125 * scl)) ;
    local pC0  = Polar2D(pt, ang +  0.0000, (0.5000 * scl)) ;  local pC1  = Polar2D(pt, ang + 26.5650, (0.5590 * scl)) ;
    local pC2  = Polar2D(pt, ang + 45.0000, (0.7071 * scl)) ;  local pC3  = Polar2D(pt, ang + 56.3099, (0.9014 * scl)) ;
    local pC4  = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;  local pC5  = Polar2D(pt, ang + 68.1993, (1.3463 * scl)) ;
    local pC6  = Polar2D(pt, ang + 71.5650, (1.5811 * scl)) ;  local pC7  = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;
    local pC8  = Polar2D(pt, ang + 75.9640, (2.0616 * scl)) ;  local pC10  = Polar2D(pt, ang + 78.6899, (2.5495 * scl)) ;
    local pD0  = Polar2D(pt, ang +  0.0000, (0.6250 * scl)) ;  local pD1  = Polar2D(pt, ang + 21.8014, (0.6731 * scl)) ;
    local pD2  = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pD4  = Polar2D(pt, ang + 57.9946, (1.1792 * scl)) ;
    local pD7  = Polar2D(pt, ang + 70.3462, (1.8583 * scl)) ;  local pD8  = Polar2D(pt, ang + 72.6460, (2.0954 * scl)) ;
    local pE0  = Polar2D(pt, ang +  0.0000, (0.7500 * scl)) ;  local pE1  = Polar2D(pt, ang + 18.4346, (0.7906 * scl)) ;
    local pE2  = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pE3  = Polar2D(pt, ang + 45.0000, (1.0607 * scl)) ;
    local pE5  = Polar2D(pt, ang + 59.0371, (1.4578 * scl)) ;  local pE6  = Polar2D(pt, ang + 63.4349, (1.6771 * scl)) ;
    local pE7  = Polar2D(pt, ang + 66.4349, (1.9039 * scl)) ;  local pE8  = Polar2D(pt, ang + 69.4440, (2.1360 * scl)) ;
    local pF0  = Polar2D(pt, ang +  0.0000, (1.0000 * scl)) ;  local pF1  = Polar2D(pt, ang + 14.0360, (1.0308 * scl)) ;
    local pF2  = Polar2D(pt, ang + 26.5651, (1.1180 * scl)) ;  local pF3  = Polar2D(pt, ang + 36.8699, (1.2500 * scl)) ;
    local pF4  = Polar2D(pt, ang + 45.0000, (1.4142 * scl)) ;  local pF5  = Polar2D(pt, ang + 51.3425, (1.6006 * scl)) ;
    local pF6  = Polar2D(pt, ang + 56.3099, (1.8025 * scl)) ;  local pF7  = Polar2D(pt, ang + 60.2551, (2.0156 * scl)) ;
    local pF8  = Polar2D(pt, ang + 63.4349, (2.2361 * scl)) ;  local pG0  = Polar2D(pt, ang +  0.0000, (1.2500 * scl)) ;
    local pG1  = Polar2D(pt, ang + 11.3099, (1.2748 * scl)) ;  local pG2  = Polar2D(pt, ang + 21.8014, (1.3463 * scl)) ;
    local pG3  = Polar2D(pt, ang + 30.9638, (1.4577 * scl)) ;  local pG4  = Polar2D(pt, ang + 38.6598, (1.6008 * scl)) ;
    local pG5  = Polar2D(pt, ang + 45.0000, (1.7678 * scl)) ;  local pG6  = Polar2D(pt, ang + 50.1944, (1.9526 * scl)) ;
    local pG7  = Polar2D(pt, ang + 54.4623, (2.1506 * scl)) ;  local pG8  = Polar2D(pt, ang + 57.9946, (2.3585 * scl)) ;
    local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))        ;  local pH0  = Polar2D(pt, ang +  0.0000, (1.5000 * scl)) ;
    local pH10 = Polar2D(pt,63.4349, (2.7951 * scl))        ;  local layer = job.LayerManager:GetLayerWithName(lay) ;
    local line = Contour(0.0) ;
    -- ------------------------------------------------------------------------
    if letter == 32 then
      pH0 = pH0
    end
    if letter == 33 then
      line:AppendPoint(pB0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
      line = Contour(0.0) line:AppendPoint(pB3) ;  line:LineTo(pE3) ;  line:LineTo(pE8) ;  line:LineTo(pB8) ;  line:LineTo(pB3) ;  group:AddTail(line) ;
    end
    if letter == 34 then
      line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB7) ;  line:LineTo(pC10) ;
      group:AddTail(line) ;  pH0 = pE0
    end
    if letter == 35 then
      line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
      line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;
      line = Contour(0.0) ;  line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;
    end
    if letter == 36 then
      line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
      line:LineTo(pB4) ;  line:LineTo(pA5) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  group:AddTail(line) ;
      line = Contour(0.0) ;  line:AppendPoint(pC0) ;  line:LineTo(pE0) ;  line:LineTo(pE8) ;  line:LineTo(pC8) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
    end
    if letter == 37 then
      line:AppendPoint(pC6) ;  line:LineTo(pC8) ;  line:LineTo(pA8) ;  line:LineTo(pA6) ;  line:LineTo(pE6) ;  line:LineTo(pG8) ;
      line:LineTo(pA0) ;  line:LineTo(pC2) ;  line:LineTo(pG2) ;  line:LineTo(pG0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
    end
    if letter == 38 then
      line:AppendPoint(pG2) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA3) ;
      line:LineTo(pE6) ;  line:LineTo(pE7) ;  line:LineTo(pD8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA6) ;  line:LineTo(pG0) ;
      group:AddTail(line) ;
    end
    if letter == 39 then
      line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  pH0 = pC0
    end
    if letter == 40 then
      line:AppendPoint(pB8) ;  line:LineTo(pA5) ;  line:LineTo(pA3) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  pH0 = pD0
    end
    if letter == 41 then
      line:AppendPoint(pA8) ;  line:LineTo(pB5) ;  line:LineTo(pB3) ;  line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pG0
    end
    if letter == 42 then
      line:AppendPoint(pA2) ;  line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;  line:LineTo(pG2) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD7) ;
      line:LineTo(pD1) ;  group:AddTail(line) ;
    end
    if letter == 43 then
      line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD1) ;  line:LineTo(pD7) ;
      group:AddTail(line)
    end
    if letter == 44 then
      line:AppendPoint(pC0) ;  line:LineTo(pE2) ;  line:LineTo(pC2) ;  line:LineTo(pC4) ;  line:LineTo(pF4) ;  line:LineTo(pF2) ;
      line:LineTo(pD0) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
    end
    if letter == 45 then
      line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
    end
    if letter == 46 then
      line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  pH0 = pD0 ;
    end
    if letter == 47 then
      line:AppendPoint(pA0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
    end
    if letter == 48 then
      line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
      line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG8) ;  line:LineTo(pA0) ; group:AddTail(line) ;
    end
    if letter == 49 then
      line:AppendPoint(pA6) ;  line:LineTo(pD8) ;  line:LineTo(pD0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;
      line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 50 then
      line:AppendPoint(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;
      line:LineTo(pA2) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 51 then
      line:AppendPoint(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
      line:LineTo(pG3) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;
      line:AppendPoint(pF4) ;  line:LineTo(pB4) ;  group:AddTail(line) ;
    end
    if letter == 52 then
      line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;
    end
    if letter == 53 then
      line:AppendPoint(pG8) ;  line:LineTo(pA8) ;  line:LineTo(pA5) ;  line:LineTo(pF4) ;  line:LineTo(pG3) ;  line:LineTo(pG1) ;
      line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
    end
    if letter == 54 then
      line:AppendPoint(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA1) ;  line:LineTo(pB0) ;
      line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
    end
    if letter == 55 then
      line:AppendPoint(pB0) ;  line:LineTo(pG8) ;  line:LineTo(pA8) ;  group:AddTail(line) ;
    end
    if letter == 56 then
      line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
      line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;
      line:LineTo(pA3) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB4) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
    end
    if letter == 57 then
      line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG3) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;
      line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  group:AddTail(line) ;
    end
    if letter == 58 then
      line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;
      group:AddTail(line) ;  pH0 = pD0 ;
    end
    if letter == 59 then
      line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB3) ;  line:LineTo(pB4) ;  line:LineTo(pA4) ;  line:LineTo(pA3) ;  line:LineTo(pB3) ;
      line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pD0 ;
    end
    if letter == 60 then
      line:AppendPoint(pF8) ;  line:LineTo(pA4) ;  line:LineTo(pG0) ;  group:AddTail(line)
    end
    if letter == 61 then
      line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
      line:LineTo(pG6) ;  group:AddTail(line) ;
    end
    if letter == 62 then
      line:AppendPoint(pA8) ;  line:LineTo(pF4) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 63 then
      line:AppendPoint(pB5) ;  line:LineTo(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pE8) ;  line:LineTo(pF7) ;
      line:LineTo(pF5) ;  line:LineTo(pC3) ;  line:LineTo(pC2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pE0) ;
      line:LineTo(pE1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
    end
    if letter == 64 then
      line:AppendPoint(pG0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;
      line:LineTo(pG6) ;  line:LineTo(pG3) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB5) ;  line:LineTo(pE5) ;  line:LineTo(pE2) ;
      group:AddTail(line)
    end
    if letter == 65 then
      line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
      line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 66 then
      line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
      line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
    end
    if letter == 67 then
      line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
      line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
    end
    if letter == 68 then
      line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
      line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 69 then
      line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
      line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
    end
    if letter == 70 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
      line:LineTo(pF4) ;  group:AddTail(line) ;
    end
    if letter == 71 then
      line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
      line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
    end
    if letter == 72 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
    end
    if letter == 73 then
      line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
    end
    if letter == 74 then
      line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
      group:AddTail(line) ;
    end
    if letter == 75 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 76 then
      line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 77 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 78 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
    end
    if letter == 79 then
      line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
      line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
    end
    if letter == 80 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
      line:LineTo(pA4) ;  group:AddTail(line) ;
    end
    if letter == 81 then
      line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
      line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
    end
    if letter == 82 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
      line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 83 then
      line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
      line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
    end
    if letter == 84 then
      line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
      line:LineTo(pD0) ;  group:AddTail(line) ;
    end
    if letter == 85 then
      line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
      group:AddTail(line) ;
    end
    if letter == 86 then
      line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
    end
    if letter == 87 then
      line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
    end
    if letter == 88 then
      line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
      line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 89 then
      line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
      line:LineTo(pD4) ;  group:AddTail(line) ;
    end
    if letter == 90 then
      line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 91 then
      line:AppendPoint(pC0) ;  line:LineTo(pB0) ;  line:LineTo(pB8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;
    end
    if letter == 92 then
      line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
    end
    if letter == 93 then
      line:AppendPoint(pE0) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pE8) ;  group:AddTail(line) ;
    end
    if letter == 94 then
      line:AppendPoint(pD8) ;  line:LineTo(pG6) ;  line:LineTo(pG5) ;  line:LineTo(pD7) ;  line:LineTo(pA5) ;  line:LineTo(pA6) ;
      line:LineTo(pD8) ;  group:AddTail(line) ;
    end
    if letter == 95 then
      line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  group:AddTail(line) ;
    end
    if letter == 96 then
      line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
    end
    -- Start of Lower Case
    if letter == 97 then
      line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
      line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 98 then
      line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
      line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
    end
    if letter == 99 then
      line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
      line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
    end
    if letter == 100 then
      line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
      line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 101 then
      line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
      line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
    end
    if letter == 102 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
      line:LineTo(pF4) ;  group:AddTail(line) ;
    end
    if letter == 103 then
      line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
      line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
    end
    if letter == 104 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
    end
    if letter == 105 then
      line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
    end
    if letter == 106 then
      line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
      group:AddTail(line) ;
    end
    if letter == 107 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
      group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 108 then
      line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 109 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 110 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
    end
    if letter == 111 then
      line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
      line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
    end
    if letter == 112 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
      line:LineTo(pA4) ;  group:AddTail(line) ;
    end
    if letter == 113 then
      line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
      line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
    end
    if letter == 114 then
      line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
      line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 115 then
      line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
      line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
    end
    if letter == 116 then
      line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
      line:LineTo(pD0) ;  group:AddTail(line) ;
    end
    if letter == 117 then
      line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
      group:AddTail(line) ;
    end
    if letter == 118 then
      line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
    end
    if letter == 119 then
      line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
    end
    if letter == 120 then
      line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
      line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    if letter == 121 then
      line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
      line:LineTo(pD4) ;  group:AddTail(line) ;
    end
    if letter == 122 then
      line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
    end
    -- End of Lower Case
    if letter == 123 then
      line:AppendPoint(pD0) ;  line:LineTo(pC0) ;  line:LineTo(pB1) ;  line:LineTo(pB2) ;  line:LineTo(pC3) ;  line:LineTo(pA4) ;
      line:LineTo(pC5) ;  line:LineTo(pB6) ;  line:LineTo(pB7) ;  line:LineTo(pC8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
    end
    if letter == 124 then
      line:AppendPoint(pA0) ;  line:LineTo(pA10) ;  line:LineTo(pC10) ;  line:LineTo(pC0) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
    end
    if letter == 125 then
      line:AppendPoint(pD0) ;  line:LineTo(pE0) ;  line:LineTo(pF1) ;  line:LineTo(pF2) ;  line:LineTo(pE3) ;  line:LineTo(pG4) ;
      line:LineTo(pE5) ;  line:LineTo(pF6) ;  line:LineTo(pF7) ;  line:LineTo(pE8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
    end
    if letter == 126 then
      line:AppendPoint(pA2) ;  line:LineTo(pA3) ;  line:LineTo(pB5) ;  line:LineTo(pF3) ;  line:LineTo(pG5) ;
      line:LineTo(pG4) ;  line:LineTo(pF2) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
    end
    return pH0
  end -- function end
  -- =========================================================================
  local function AddGroupToJob(job, group, layer_name)
      --  create a CadObject to represent the  group
    local cad_object = CreateCadGroup(group);
      -- create a layer with passed name if it doesnt already exist
    local layer = job.LayerManager:GetLayerWithName(layer_name)
      -- and add our object to it
    layer:AddObject(cad_object, true)
    return cad_object
  end -- end function
  -- =========================================================================
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: Not finding a job loaded")
      return false
    end
    local strlen = string.len(what)
    local strup = what
    local x = strlen
    local i = 1
    local y = ""
    local ptx = where
    group = ContourGroup(true)
    while i <=  x do
      y = string.byte(string.sub(strup, i, i))
      if (y >= 97) and (y <= 122) then -- Lower case
        ptx = MonoFont(job, ptx, y, (size * 0.75), lay, ang)
        ptx = Polar2D(ptx, ang, size * 0.05)
      else -- Upper case
        ptx = MonoFont(job, ptx, y, size, lay, ang)
        ptx = Polar2D(ptx, ang, size * 0.07)
      end
      i = i + 1
    end -- while end;
    AddGroupToJob(job, group, lay)
    job:Refresh2DView()
    return true
end -- function end</nowiki>
 
----
 
===Holer - Draws two Holes and groups them===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Draws circles based on a layout.
 
<nowiki>function Holer(pt, ang, dst, dia, lay)
      local job = VectricJob()
      if not job.Exists then
        DisplayMessageBox("Error: No job loaded")
        return false
      end
    --Caller: Holer(ptx, anx, BaseDim.HoleSpace, Milling.ShelfPinRadius, Milling.LNSideShelfPinDrill .. "-Base")
      local function AddGroupToJob(job, group, layer_name)
        local cad_object = CreateCadGroup(group);
        local layer = job.LayerManager:GetLayerWithName(layer_name)
        layer:AddObject(cad_object, true)
        return cad_object
      end
    local group = ContourGroup(true)
    group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
    pt = Polar2D(pt, ang, dst)
    group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
    AddGroupToJob(job, group, lay)
    return true
end -- function end</nowiki>
 
----
 
==Data Export Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
===LogWriter===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
 
Writes a Log items to the log file.
 
<nowiki> function LogWriter(LogName, xText)
  -- Adds a new xText Line to a app log file
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
  local fileW = io.open(LogName,  "a")
  if fileW then
    fileW:write(xText .. "\n")
    fileW:close()
  end -- if end
  Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
   return true
   return true
end
end -- function end </nowiki>
-- =====================================================]]
 
function SheetSet(Name)                                 -- Move focus to a named sheet
----
  local job = VectricJob()
===Write_CSV===
   local sheet_manager = job.SheetManager
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
   local sheet_ids = sheet_manager:GetSheetIds()
Writes the values to a csv format file.
   for id in sheet_ids do
 
     if(sheet_manager:GetSheetName(id) == Name) then
<nowiki> function Write_CSV(xFilename) -- Writes the values to a csv format file
     sheet_manager.ActiveSheetId = id
-- Usage: Write_CSV("C:\\Path\\MyName.csv")
     end
-- Door.CSVPath = dialog:GetTextField("DoorCSVPath")
  end
-- local filename = Path .. "\\" .. Name .. ".csv"
end
   local filename = xFilename
-- ====================================================]]
   local file = io.open(filename, "w")
function SheetNextSize(X, Y)                           -- Make New Sheet to size (x, y)
   if file then  -- if the file was opened
   if X == nil then
    file:write("Count,Height,Width\n")  -- Header Line
    X = Milling.MaterialBlockWidth
     if Door.Unit then
   else
      file:write("1,110,595\n");    file:write("1,150,75\n");    file:write("1,175,395\n");    file:write("1,140,495\n")
    X = X + (2 * Milling.Cal)
      file:write("1,175,445\n");    file:write("1,175,595\n");    file:write("2,200,100\n");     file:write("3,250,125\n")
   end
      file:write("1,300,150\n");    file:write("2,350,175\n");    file:write("3,400,200\n");     file:write("1,450,225\n")
   if Y == nil then
      file:write("2,500,250\n");    file:write("3,550,275\n");    file:write("1,600,300\n");    file:write("2,650,325\n")
    Y = Milling.MaterialBlockHeight
      file:write("3,700,350\n");    file:write("1,750,375\n");    file:write("2,800,400\n");    file:write("3,850,425\n");
   else
      file:write("1,900,450\n");    file:write("2,950,475\n");    file:write("3,1000,500\n");    file:write("1,1050,525\n");
    Y = Y + (2 * Milling.Cal)
      file:write("2,1100,550\n");   file:write("3,1150,575\n");   file:write("1,1200,600\n");    file:write("2,1250,625\n");
   end
      file:write("3,1300,650\n");  file:write("1,1350,675\n");   file:write("2,1400,700\n");    file:write("3,1450,725\n");
   Milling.Sheet = Milling.Sheet + 1
      file:write("1,1500,750\n");   file:write("2,1550,775\n");   file:write("3,1600,800\n");    file:write("1,1650,825\n");
   local sheet_manager = Milling.job.SheetManager
      file:write("2,1700,850\n");  file:write("3,1750,875\n");   file:write("1,1800,900\n");    file:write("2,1850,925\n");
   local sheet_ids = sheet_manager:GetSheetIds()
      file:write("3,1900,950\n");   file:write("1,1950,975\n");  file:write("2,2000,1000\n");   file:write("3,2050,1025\n");
   for id in sheet_ids do
      file:write("1,2100,1050\n");  file:write("2,2150,1075\n");  file:write("3,2200,1100\n");   file:write("1,2250,1125\n");
     if(sheet_manager:GetSheetName(id) == "Sheet 1") then
      file:write("2,2300,1150\n");  file:write("3,2350,1175\n");  file:write("1,2400,1200\n");   file:write("2,2450,1225\n")
    sheet_manager:CreateSheets(1, id, Box2D(Point2D(0, 0), Point2D(X, Y)))
     else
    end
      file:write("1,04.5000,23.2500\n");  file:write("1,06.0000,03.3125\n");  file:write("1,06.5000,15.5000\n");  file:write("1,05.3750,19.5000\n");
  end
      file:write("1,07.1875,17.5000\n");  file:write("1,06.1875,23.5000\n");  file:write("2,07.8750,03.8750\n");  file:write("3,09.8750,05.0000\n");
  SheetSet("Sheet " .. tostring(Milling.Sheet))
      file:write("1,11.7500,05.8750\n");  file:write("2,13.7500,06.6750\n");  file:write("3,15.7500,07.8750\n");  file:write("1,17.1250,08.8250\n");
  return true
      file:write("2,19.5000,09.5000\n");  file:write("3,21.1250,10.3750\n");  file:write("1,23.6250,11.1250\n");  file:write("2,25.5000,12.1250\n");
end
      file:write("3,27.6250,13.7500\n");  file:write("1,29.5000,14.7500\n");  file:write("2,31.4375,15.7500\n");  file:write("3,33.4375,16.7500\n");
-- =====================================================]]
      file:write("1,35.4375,17.7500\n");  file:write("2,37.4375,18.6250\n");  file:write("3,39.3750,19.6250\n");  file:write("1,41.3750,20.6250\n");
function GetPolarAngle(Start, Corner, End)             -- Returns the Polar Angle
      file:write("2,43.3750,21.6250\n");  file:write("3,45.1875,22.6250\n");  file:write("1,47.2500,23.6250\n");  file:write("2,49.1875,24.6250\n");
  local function GetPolarDirection(point1, point2)             --
       file:write("3,51.1250,25.5000\n");  file:write("1,53.1250,26.5000\n");  file:write("2,55.1250,27.5000\n");  file:write("3,57.1250,28.5000\n");
    local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
       file:write("1,59.1250,29.5000\n");  file:write("2,61.2500,30.5000\n");  file:write("3,62.9375,31.4375\n");  file:write("1,64.9375,32.4375\n");
    if point1.X < point2.X then
       file:write("2,66.9375,33.4375\n");  file:write("3,68.8125,34.4375\n");  file:write("1,70.8750,35.3750\n");  file:write("2,72.9375,36.4375\n");
       if point1.Y < point2.Y then
       file:write("3,74.8750,37.4375\n");  file:write("1,76.9375,38.3750\n");  file:write("2,78.7500,39.3750\n");  file:write("3,80.7500,40.3750\n");
        ang = ang + 0.0
       file:write("1,82.6250,41.3750\n");  file:write("2,84.6250,42.3750\n");  file:write("3,86.6250,43.3750\n");  file:write("1,88.5000,44.2500\n");
       else
       file:write("2,90.6250,45.2500\n");  file:write("3,92.6250,46.2500\n");  file:write("1,94.4375,47.2500\n");  file:write("2,95.4375,48.2500\n")
        ang = 360.0 - ang
       end -- if end
    else
       if point1.Y < point2.Y then
        ang = 180.0 - ang
       else
        ang = ang + 180.0
       end -- if end
     end -- if end
     end -- if end
     if ang >=360 then
     file:close() -- closes the open file
       ang = ang -360.0
  end -- if end
  return  true
end -- function end </nowiki>
 
----
 
==Text File Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
===LengthOfFile===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
Returns file line count
 
<nowiki> function LengthOfFile(filename)
    Returns: number]]
    local len = 0
    if FileExists(filename) then
       local file = io.open(filename)
      if file then
      for _ in file:lines() do
        len = len + 1
      end
      file:close()
     end -- if end
     end -- if end
    return ang
  end -- function end
  return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
end -- function end
-- =====================================================]]
function GetOrientation(point1, point2)                -- Orientation of left, right, up or down
  if DecimalPlaces(point1.X,8) == DecimalPlaces(point2.X,8) then
    if point1.Y < point2.Y then
      return 90.0
    else
      return 270.0
     end
     end
  elseif DecimalPlaces(point1.Y,8) == DecimalPlaces(point2.Y,8) then
     return len
     if point1.X < point2.X then
end -- function end </nowiki>
      return 0.0
----
    else
 
      return 180.0
===NameValidater - Checks File Name for Valid Chars===
    end
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  else
Returns file line count
    return nil
 
  end
<nowiki> function NameValidater(FileName)
end -- function end
    local MyTrue = true
-- =====================================================]]
    local strlen = string.len(FileName)
function GetPolarDirection(point1, point2)             -- Retuens and amgle from two points
    local strup = string.upper(FileName)
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
    local i = 1
  if point1.X < point2.X then
    local y = ""
    if point1.Y < point2.Y then
    while i <=  strlen do
      ang = ang + 0.0
      y = string.byte(string.sub(strup, i, i))
    else
      if y == 32 then   --  Space
       ang = 360.0 - ang
        MyTrue = false
    end -- if end
        break
  else
       elseif y == 45 then  -- Dash
    if point1.Y < point2.Y then
        MyTrue = false
       ang = 180.0 - ang
        break
    else
       elseif y == 127 then  -- Delete
       ang = ang + 180.0
        MyTrue = false
    end -- if end
        break
  end -- if end
       elseif y == 126 then  -- Delete
  if ang >=360 then
        MyTrue = false
    ang = ang -360.0
        break
  end -- if end
 
  return ang
      elseif y == 123 then  -- Open brace
end -- function end
        MyTrue = false
-- =====================================================]]
        break
function CenterArc(A, B, RadiusD)                       -- Retuns 2DPoint from Arc point and Radius
      elseif y == 124 then -- Pipe
  local radius = ((tonumber(RadiusD) or 0) * g_var.scl)
        MyTrue = false
  local horda = (A - B).Length
        break
  if math.abs(radius) < (horda / 2) and radius ~= 0 then
      elseif y == 125 then  -- Close brace
--D("Too small radius " .. radius .. "\nreplaced by the smallest possible " .. (horda / 2))
        MyTrue = false
    radius = (horda / 2)
        break
  end
 
  return Point2D(((A.x + B.x) / 2 + (B.y - A.y) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda), ((A.y + B.y) / 2 + (A.x - B.x) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda))
      elseif  -- Illegal Filename Characters
end
      (y == 33) or -- ! Exclamation mark
-- =====================================================]]
      (y == 34) or -- " Double Quotes
function Polar2D(pt, ang, dis)                         -- Retuns 2DPoint from Known Point, Angle direction, and Projected distance.
      (y == 35) or -- # Hash
-- The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance.
      (y == 36) or -- $ Dollar
-- ::''Returns a 2Dpoint(x, y)''
      (y == 37) or -- % Percent
  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
      (y == 38) or -- & Ampersand
end -- End Function
      (y == 39) or -- ' Apostrophe
-- =====================================================]]
      (y == 42) or -- * Asterisk
function GetDistance(objA, objB)                        -- Returns Double from two Points
      (y == 43) or -- + Plus
  local xDist = objB.x - objA.x
      (y == 44) or -- , Comma
  local yDist = objB.y - objA.y
      (y == 47) or -- / Slash
  return math.sqrt((xDist ^ 2) + (yDist ^ 2))
      (y == 58) or -- : Colon
end -- function end
      (y == 59) or -- ; Semi-colon
-- =====================================================]]
      (y == 60) or -- < Less than
function GetAngle(point1, point2)
      (y == 62) or -- > Greater than
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
      (y == 63) or -- ? Question mark
  if point1.X < point2.X then
      (y == 64) or -- @ At
    if point1.Y < point2.Y then
      (y == 92) or -- \ Backslash
       ang = ang + 0.0
      (y == 96) or -- ` Single Quotes
     else
      (y == 123) or -- { Open brace
       ang = 360.0 - ang
      (y == 124) or -- | Pipe
    end -- if end
      (y == 125)   -- } Close brace
  else
      then
    if point1.Y < point2.Y then
        MyTrue = false
       ang = 180.0 - ang
        break
      elseif (y <= 31) then -- Control Codes
        MyTrue = false
        break
      elseif (y >= 48) and (y <= 57) then -- Numbers
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      elseif (y >= 97) and (y <= 122) then -- Lowercase A to Z
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      end -- if end
      i = i + 1  end -- while end;
    return MyTrue
end -- function end </nowiki>
----
 
===CopyFileFromTo===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
Copy Old File to Newfile
 
<nowiki> function CopyFileFromTo(OldFile, NewFile)
    if FileExists(NewFile) then
      DisplayMessageBox("File copy " .. File .. " failed. \n\nFile found at: " .. NewFile  .. "\n" )
       return false
     elseif not FileExists(OldFile) then
       DisplayMessageBox("File copy of " .. File .. " failed. \n\nFile not found at: " .. OldFile .. "\n" )
       return false
     else
     else
       ang = ang + 180.0
       local fileR = io.open(OldFile)      -- reader file
    end -- if end
      local fileW = io.open(NewFile, "w") -- writer file
  end -- if end
      if fileR and fileW then  -- if both files are open
  if ang >=360.0 then
        for Line in fileR:lines() do
    ang = ang -360.0
          fileW:write(Line .. "\n")
  end -- if end
        end -- for end
  return ang
      end
end -- function end
      if fileR then fileR:close() end
-- =====================================================]]
      if fileW then fileW:close() end
function Arc2Bulge(p1, p2, Rad)                         -- Returns the Bulge factor for an arc
      return true
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
    end -- for end
  local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
end -- function end </nowiki>
  local bulge = (2 * seg) / chord
----
  return bulge
 
end -- function end
===ValidateName===
-- =====================================================]]
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
function TrigIt()                                       -- Calulates Right Angle
Returns True if the file name is safe to use
-- ==Trig Function==
 
-- VECTRIC LUA SCRIPT
<nowiki> function ValidateName(FileName)
-- =====================================================]]
  local MyTrue = true
-- Gadgets are an entirely optional add-in to Vectric's core software products.
  local strlen = string.len(FileName)
-- They are provided 'as-is', without any express or implied warranty, and you
  local strup = string.upper(FileName)
--   make use of them entirely at your own risk.
  local i = 1
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages
  local y = ""
--  arising from their use.
  while i <= strlen do
-- Permission is granted to anyone to use this software for any purpose,
    y = string.byte(string.sub(strup, i, i))
-- including commercial applications, and to alter it and redistribute it freely,
    if y == 32 then -- Space
-- subject to the following restrictions:
      MyTrue = true
-- 1. The origin of this software must not be misrepresented; you must not
    elseif y == 45 then -- hyphn
--    claim that you wrote the original software.
      MyTrue = true
-- 2. If you use this software in a product, an acknowledgement in the product
    elseif (y >= 48) and (y <= 57) then -- numbers
--    documentation would be appreciated but is not required.
      MyTrue = true
-- 3. Altered source versions must be plainly marked as such, and must not be
    elseif (y >= 65) and (y <= 90) then -- Uppercase
--    misrepresented as being the original software.
      MyTrue = true
-- 4. This notice may not be removed or altered from any source distribution.
    else
--
      MyTrue = false
-- Right Triangle TrigFunction is written by Jim Anderson of Houston Texas 2020
      break
-- =====================================================]]
    end -- if end
-- Code Debugger
    i = i + 1
-- require("mobdebug").start()
  end -- while end
-- =====================================================]]
  return MyTrue
-- Global Variables --
  end -- function end </nowiki>
     Trig = {}
 
-- =====================================================]]
----
  function TrigTest() -- Test the All Right Angle
 
    TrigClear()
===FileExists===
    Trig.A  =  0.0
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    Trig.B  =  0.0
Returns True if file is found
     Trig.C  = 90.0
 
     Trig.Opp =  3.0  -- Rise  or (B2C)
<nowiki> function FileExists(name)
    Trig.Adj = 4.0  -- Base  or (A2C)
  -- call = ans = FileExists("sample.txt")
     Trig.Hyp =  0.0  -- Slope or (A2B)
    local f=io.open(name,"r")
    Trig.Slope = 0.0
    if f~=nil then io.close(f) return true else io.close(f) return false end
    Trig.Area = 0.0
  end -- function end </nowiki>
    Trig.OutRadius = 0.0
----
    Trig.InRadius = 0.0
 
     Trig.Parameter = 0.0
===FileAccess===
     TrigIt()
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
     DisplayMessageBox("Test 1: \n" ..
Returns true if file is available for update.
    " Trig.A  = " .. tostring(Trig.A) .. " \n" ..
 
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
<nowiki> function FileAccess(FileName)
    " Trig.C  = " .. tostring(Trig.C) .. " \n" ..
    if (not(os.rename(FileName, FileName))) then
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
      StatusMessage("Error", FileName, "The Gadget cannot access the ".. FileName ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
        " The OS has blocked write access. " ..
    " Trig.Hyp = " .. tostring(Trig.Hyp) .. " \n" ..
        "Verify the full path is correct and No application has the file open. ", "(1405)")
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
        return false
     " Trig.Area = " .. tostring(Trig.Area) .. " \n" ..
  else
     " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    return true
     " Trig.OutRadius " .. tostring(Trig.OutRadius) .. " \n" ..
  end -- if end
    " Trig.InRadius = " .. tostring(Trig.InRadius) .. " \n"
end -- function end </nowiki>
    )
----
     -- =====================================================]]
 
    TrigClear()
===IsDir===
     Trig.A  =  0.0
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    Trig.B  =  0.0
Returns true if path is found
    Trig.C  = 90.0
 
    Trig.Opp =  0.0  -- Rise  or (B2C)
<nowiki> function IsDir(path)                                  --
    Trig.Adj = 4.0 -- Base  or (A2C)
  local function exists(file)
     Trig.Hyp = 5.0  -- Slope or (A2B)
    local ok, err, code = os.rename(file, file)
    Trig.Slope =  0.0
    if not ok then
     Trig.Area =  0.0
      if code == 13 then
    Trig.OutRadius = 0.0
        return true
    Trig.InRadius = 0.0
      end
     Trig.Parameter = 0.0
    end
    TrigIt()
    return ok, err
    DisplayMessageBox("Test 2: \n" ..
  end
     " Trig.A  = " .. tostring(Trig.A) .. " \n" ..
  return exists(path.."/")
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
end -- function end </nowiki>
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
----
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
 
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
===Sheetlabel===
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
Returns file line count of a txt (assic) file
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
 
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
<nowiki> function Sheetlabel(Wpt, xTextHeight,  xThickness, xType, YY) -- Constructs sheet label
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  local pt1Text = Point2D()
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
  local Pang    = 0.0
    )
   local Tang    = 0.0
    -- =====================================================]]
  if YY then
    TrigClear()
    pt1Text = Polar2D(Polar2D(Wpt, 90.0,  YY), 90.0, 6.0 * JimAndi.Cal)
    Trig.A  =  0.0
    Pang = 270.0
    Trig.B  =  0.0
    Tang = 0.0
    Trig.C  = 90.0
  else
    Trig.Opp =  3.0  -- Rise  or (B2C)
    if Material.Orientation == "V" then
    Trig.Adj =  0.0  -- Base  or (A2C)
      pt1Text = Polar2D(Wpt, 90.0, Milling.MaterialBlockWidth + (4.0 * JimAndi.Cal))
    Trig.Hyp =  5.0  -- Slope or (A2B)
    else
    Trig.Slope =  0.0
      pt1Text = Polar2D(Wpt, 90.0, Milling.MaterialBlockHeight + (4.0 * JimAndi.Cal))
    Trig.Area =  0.0
    end
    Trig.OutRadius =  0.0
    Pang = 270.0
    Trig.InRadius =  0.0
    Tang = 0.0
    Trig.Parameter =  0.0
  end
    TrigIt()
  DrawWriter(Project.ProgramName, pt1Text, Milling.TextHeight * 3.0, JimAndi.LNDrawNotes, Tang)
    DisplayMessageBox("Test 3: \n" ..
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 3.35)
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
  DrawWriter("Cabinet ID: " .. Project.DrawerID, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
  DrawWriter("Cabinet Name: " .. Project.CabinetName, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
  if xThickness then
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
    DrawWriter("Material: " .. xThickness .. " " .. xType, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
  end -- if end
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
end -- function end </nowiki>
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
----
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
 
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
===DiskRights===
    )
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    -- =====================================================]]
Returns true if you have write access to path.
    TrigClear()
 
    Trig.A  =  36.86897645844
<nowiki> function DiskRights(path)                            --
    Trig.B  =  0.0
  local xx = io.open(path, "w")
    Trig.C  = 90.0
  if xx == nil then
    Trig.Opp =  3.0  -- Rise  or (B2C)
      io.close()
    Trig.Adj =  0.0  -- Base  or (A2C)
      return false
    Trig.Hyp =  0.0  -- Slope or (A2B)
  else
    Trig.Slope =  0.0
      xx:close()
    Trig.Area =  0.0
      return true
    Trig.OutRadius =  0.0
  end
    Trig.InRadius =  0.0
end -- function end </nowiki>
    Trig.Parameter =  0.0
----
    TrigIt()
 
    DisplayMessageBox("Test 4: \n" ..
==Geometry Tools==
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
 
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
===SheetNew===
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
 
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
Adds a new sheet to the drawing
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
 
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
<nowiki> function SheetNew()                                    -- Adds a new sheet to the drawing
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  if GetVersion() >= 10.5 then then
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
     local layer_manager = Milling.job.LayerManager
    )
    -- get current sheet count - note sheet 0 the default sheet counts as one sheet
    -- =====================================================]]
    local orig_num_sheets = layer_manager.NumberOfSheets
    TrigClear()
    -- get current active sheet index
    Trig.A  =  36.86897645844
    local orig_active_sheet_index = layer_manager.ActiveSheetIndex
    Trig.B  =  0.0
    -- set active sheet to last sheet
    Trig.C  = 90.0
    local num_sheets = layer_manager.NumberOfSheets
    Trig.Opp =  0.0  -- Rise  or (B2C)
    layer_manager.ActiveSheetIndex = num_sheets - 1
    Trig.Adj =  4.0  -- Base  or (A2C)
    -- Add a new sheet
    Trig.Hyp =  0.0  -- Slope or (A2B)
    layer_manager:AddNewSheet()
    Trig.Slope =  0.0
    -- set active sheet to last sheet we just added
    Trig.Area =  0.0
    num_sheets = layer_manager.NumberOfSheets
    Trig.OutRadius =  0.0
    layer_manager.ActiveSheetIndex = num_sheets - 1
    Trig.InRadius =  0.0
    Milling.job:Refresh2DView()
    Trig.Parameter =  0.0
  end -- if end
    TrigIt()
  return true
    DisplayMessageBox("Test 5: \n" ..
end  </nowiki>
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
 
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
----
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
 
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
===GetDiameterAndCentre===
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
<nowiki>function GetDiameterAndCentre(cadcontour, point2d)
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
  local contour = cadcontour:GetContour()
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  local arc = contour:GetFirstSpan()
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
  local point3d = Point3D();
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  arc = CastSpanToArcSpan(arc)
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
  local diameter = arc:RadiusAndCentre(point3d) * 2.0
    )
  point2d = Point2D(point3d.x, point3d.y)
    -- =====================================================]]
  -- MessageBox("Diameter = " .. diameter)
    TrigClear()
  return diameter, point2d
    Trig.A  =  36.86897645844
end</nowiki>
    Trig.B  =  0.0
 
    Trig.C  = 90.0
----
    Trig.Opp =  0.0  -- Rise  or (B2C)
 
    Trig.Adj =  0.0  -- Base  or (A2C)
===IsCircle===
    Trig.Hyp =  5.0  -- Slope or (A2B)
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    Trig.Slope =  0.0
<nowiki>function IsCircle(cadcontour)                           -- Returns True if conture is a circle
    Trig.Area =  0.0
  local contour = cadcontour:GetContour()
    Trig.OutRadius =  0.0
  -- Does it consist only of arcs?
    Trig.InRadius =  0.0
  if contour.ContainsBeziers then
    Trig.Parameter =  0.0
     return false
    TrigIt()
  end
    DisplayMessageBox("Test 6: \n" ..
  if not contour.ContainsArcs then
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
     return false
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
  end
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
  -- Does is contain 4 contours?
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
  if contour.Count ~= 4 then
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
     return false
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
  end
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
  -- Check the arcs end and initial points make a square.
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  local arcs = {}
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
  local count = 1;
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  local pos = contour:GetHeadPosition()
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
  local object
    )
  while pos ~= nil do
    TrigClear()
     object, pos = contour:GetNext(pos)
    Trig.A  =  0.0
     arcs[count] = object
    Trig.B  =  0.0
     count = count + 1
    Trig.C  = 90.0
  end
    Trig.Opp =  3.0  -- Rise  or (B2C)
  local x_1 =(arcs[1]).StartPoint2D.x
    Trig.Adj =  0.0  -- Base  or (A2C)
  local y_1 =(arcs[1]).StartPoint2D.y
    Trig.Hyp =  0.0  -- Slope or (A2B)
  local x_3 =(arcs[3]).StartPoint2D.x
    Trig.Slope =  9.0
  local y_3 =(arcs[3]).StartPoint2D.y
    Trig.Area =  0.0
  local x_2 =(arcs[2]).StartPoint2D.x
    Trig.OutRadius =  0.0
  local y_2 =(arcs[2]).StartPoint2D.y
    Trig.InRadius =  0.0
  local x_4 =(arcs[4]).StartPoint2D.x
    Trig.Parameter =  0.0
  local y_4 =(arcs[4]).StartPoint2D.y
    TrigIt()
  local horizontal_distance = (x_1 - x_3)*(x_1 - x_3) + (y_1 - y_3)*(y_1 - y_3)
    DisplayMessageBox("Test 7: \n" ..
  local vertical_distance = (x_4 - x_2)*(x_4 - x_2) + (y_2 - y_4)*(y_2 - y_4)
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
  if math.abs(horizontal_distance - vertical_distance) > 0.04 then
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    return false
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
  end
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
  -- Check the bulge factor is 90
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
  local bulge = 0;
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
  for _, arc_span in ipairs(arcs) do
    " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
     bulge = CastSpanToArcSpan(arc_span).Bulge;
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
     if math.abs(math.abs(bulge)  - g_bulge90) > 0.04 then
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
      return false
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
     end
    " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
  end
    " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
  return true
    )
end</nowiki>
    -- =====================================================]]
 
    TrigClear()
----
    Trig.A  =  0.0
 
    Trig.B  =  0.0
===SheetSet===
    Trig.C  = 90.0
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    Trig.Opp =  0.0  -- Rise  or (B2C)
  <nowiki>function SheetSet(Name)                   -- Move focus to a named sheet
    Trig.Adj =  0.0  -- Base  or (A2C)
  local job = VectricJob()
    Trig.Hyp =  0.0  -- Slope or (A2B)
  local sheet_manager = job.SheetManager
    Trig.Slope =  9.0
  local sheet_ids = sheet_manager:GetSheetIds()
    Trig.Area =  0.0
  for id in sheet_ids do
    Trig.OutRadius =  0.0
     if(sheet_manager:GetSheetName(id) == Name) then
    Trig.InRadius =  0.0
    sheet_manager.ActiveSheetId = id
    Trig.Parameter =  0.0
    end
    TrigIt()
  end
    DisplayMessageBox("Test Error: \n" ..
end</nowiki>
      " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
 
      " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
----
      " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
 
      " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
===SheetNextSize===
      " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
      " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
<nowiki>function SheetNextSize(X, Y)              -- Make New Sheet to size (x, y)
      " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
  if X == nil then
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    X = Milling.MaterialBlockWidth
      " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  else
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    X = X + (2 * Milling.Cal)
      " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
  end
      " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
  if Y == nil then
    )
    Y = Milling.MaterialBlockHeight
    return true
  else
  end -- function end --
    Y = Y + (2 * Milling.Cal)
-- =====================================================]]
  end
  function TrigClear()  -- Clears and resets Trig Table
  Milling.Sheet = Milling.Sheet + 1
    Trig.A  =  0.0
  local sheet_manager = Milling.job.SheetManager
    Trig.B  =  0.0
  local sheet_ids = sheet_manager:GetSheetIds()
    Trig.C  = 90.0
  for id in sheet_ids do
    Trig.Opp =  0.0  -- Rise  or (B2C)
    if(sheet_manager:GetSheetName(id) == "Sheet 1") then
    Trig.Adj = 0.0 -- Base  or (A2C)
    sheet_manager:CreateSheets(1, id, Box2D(Point2D(0, 0), Point2D(X, Y)))
     Trig.Hyp =  0.0  -- Slope or (A2B)
     end
    Trig.Slope =  0.0
  end
     return true
  SheetSet("Sheet " .. tostring(Milling.Sheet))
  return true
end</nowiki>
 
----
 
===GetPolarAngle===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  <nowiki>function GetPolarAngle(Start, Corner, End)          -- Returns the Polar Angle
  local function GetPolarDirection(point1, point2)  
     local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
     if point1.X < point2.X then
      if point1.Y < point2.Y then
        ang = ang + 0.0
      else
        ang = 360.0 - ang
      end -- if end
     else
      if point1.Y < point2.Y then
        ang = 180.0 - ang
      else
        ang = ang + 180.0
      end -- if end
    end -- if end
     if ang >=360 then
      ang = ang -360.0
     end -- if end
     return ang
   end -- function end
   end -- function end
-- =====================================================]]
  return math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
      local function BSA()
end -- function end</nowiki>
        Trig.B = (Trig.C - Trig.A)
 
        Trig.Slope = math.tan(math.rad(Trig.A)) * 12.0
----
        Trig.Area =  (Trig.Opp * Trig.Adj) * 0.5
 
        Trig.Inscribing = ((Trig.Opp + Trig.Adj) - Trig.Hyp) * 0.5
===GetOrientation===
        Trig.Circumscribing =  Trig.Hyp * 0.5
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
        Trig.Parameter = Trig.Opp + Trig.Adj + Trig.Hyp
<nowiki>function GetOrientation(point1, point2)                 -- Orientation of left, right, up or down
      end
  if DecimalPlaces(point1.X,8) == DecimalPlaces(point2.X,8) then
      if Trig.A == 0.0 and Trig.B > 0.0 and Trig.Slope == 0.0 then
    if point1.Y < point2.Y then
        Trig.A = Trig.C - Trig.B
      return 90.0
      elseif Trig.A == 0.0 and Trig.B == 0.0 and Trig.Slope > 0.0 then
    else
        Trig.A = math.deg(math.atan(Trig.Slope / 12.0))
      return 270.0
      end -- if end
    end
-- test 4
  elseif DecimalPlaces(point1.Y,8) == DecimalPlaces(point2.Y,8) then
      if (Trig.A > 0.0) and (Trig.Opp >  0.0) then -- A and Rise or (B2C)
    if point1.X < point2.X then
        Trig.Adj =  Trig.Opp / (math.tan(math.rad(Trig.A)))
      return 0.0
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
    else
        BSA()
      return 180.0
        return true
    end
      -- test 6
  else
      elseif (Trig.A > 0.0) and (Trig.Hyp >  0.0) then -- A and Slope or (A2B)
    return nil
        Trig.Adj = math.cos(math.rad(Trig.A)) * Trig.Hyp
  end
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
end -- function end</nowiki>
        BSA()
 
        return true
----
      -- test 5
 
      elseif (Trig.A > 0.0) and (Trig.Adj >  0.0)  then -- A and Base or (A2C)
===GetPolarDirection===
        Trig.Opp = math.tan(math.rad(Trig.A)) * Trig.Adj
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
<nowiki>function GetPolarDirection(point1, point2)             -- Retuens and amgle from two points
        BSA()
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
        return true
  if point1.X < point2.X then
        -- test 1
    if point1.Y < point2.Y then
      elseif (Trig.Opp >  0.0) and (Trig.Adj >  0.0) then -- Rise and Base
      ang = ang + 0.0
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
    else
        Trig.= math.deg(math.atan(Trig.Opp / Trig.Adj))
      ang = 360.0 - ang
        BSA()
    end -- if end
        return true
  else
      elseif (Trig.Adj > 0.0) and (Trig.Hyp >  0.0) then -- Rise and Slope
    if point1.Y < point2.Y then
-- test 2
      ang = 180.0 - ang
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
    else
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
      ang = ang + 180.0
        BSA()
     end -- if end
        return true
  end -- if end
      elseif (Trig.Opp >  0.0) and (Trig.Hyp >  0.0) then -- Base and Slope
  if ang >=360 then
-- test 3
    ang = ang -360.0
        Trig.Adj = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Opp * Trig.Opp))
  end -- if end
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
  return ang
        BSA()
end -- function end</nowiki>
        return true
      else
        DisplayMessageBox("Error: Trig Values did not match requirements: \n" ..
                          " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
                          " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
                          " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
                          " Trig.Opp = " .. tostring(Trig.Opp) .. " \n" ..
                          " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
                          " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
                          " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
                          " Trig.Area = " .. tostring(Trig.Area) .. " \n" ..
                          " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
                          " Trig.OutRadius = " .. tostring(Trig.OutRadius) .. " \n" ..
                          " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
                          )
        return false
      end
     end -- function end
-- =====================================================]]
end -- Geometry Tools end


</nowiki>
----


==INI File Tools==
===CenterArc===
These functions manipulate the INI files for the storage and retrieval of data.
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function CenterArc(A, B, RadiusD)                      -- Returns 2DPoint from Arc point and Radius
  local radius = ((tonumber(RadiusD) or 0) * g_var.scl)
  local horda = (A - B).Length
  if math.abs(radius) < (horda / 2) and radius ~= 0 then
--D("Too small radius " .. radius .. "\nreplaced by the smallest possible " .. (horda / 2))
    radius = (horda / 2)
  end
  return Point2D(((A.x + B.x) / 2 + (B.y - A.y) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda), ((A.y + B.y) / 2 + (A.x - B.x) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda))
end -- function end</nowiki>
 
----
 
===Polar2D===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]


The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance. Returns 2DPoint from Known Point, Angle direction, and Projected distance.


===NameStrip===
<nowiki>function Polar2D(pt, ang, dis)                       
Convert string to the correct data type.
-- The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance.
-- ::''Returns a 2Dpoint(x, y)''
  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
end -- End Function</nowiki>


Local Words = NameStrip("KPSDFKSPSK - 34598923", "-") -- returns "KPSDFKSPSK"
----


===GetDistance===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]


'''Source Code'''
Returns Double from two Points


<nowiki> function NameStrip(str, var)
  <nowiki>function GetDistance(objA, objB)                       -- Returns Double from two Points
    if "" == str then
  local xDist = objB.x - objA.x
      DisplayMessageBox("Error in string")
  local yDist = objB.y - objA.y
    else
  return math.sqrt((xDist ^ 2) + (yDist ^ 2))
      if string.find(str, var) then
end -- function end</nowiki>
        local j = assert(string.find(str, var) - 1)
        return All_Trim(string.sub(str, 1, j))
      else
        return str
      end
    end
  end -- function end </nowiki>  


===HeadStrip===
----
Convert string to the correct data type.


===GetAngle===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  <nowiki>
  <nowiki>
   function HeadStrip(str, var)                           -- convert string to the correct data type
   -- ===========================================================]]
-- Local Words = HeadStrip("LastName23 = Smith", "=") -- returns "Smith"
  </nowiki>function GetAngle(point1, point2)
     if "" == str then
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
       DisplayMessageBox("Error in string")
  if point1.X < point2.X then
    if point1.Y < point2.Y then
      ang = ang + 0.0
    else
      ang = 360.0 - ang
    end -- if end
  else
     if point1.Y < point2.Y then
       ang = 180.0 - ang
     else
     else
       if string.find(str, var) then
       ang = ang + 180.0
        local j = assert(string.find(str, var) + 1)
    end -- if end
        return All_Trim(string.sub(str, j))
  end -- if end
      else
  if ang >=360.0 then
        return str
    ang = ang -360.0
      end
  end -- if end
    end
   return ang
   end -- function end
end -- function end</nowiki>
   -- =====================================================]]
----
   function INI_AreDupGroups(xPath, xFile)                 -- Are there duplicate groups
 
    local GroupNames = {}
===Arc2Bulge===
    local CleanNames = {}
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    local DupGroups  = {}
<nowiki>
      GroupNames = INI_ReadGroups(xFile, aName)
   -- ===========================================================]]
      CleanNames = RemoveDups(GroupNames)
   </nowiki>function Arc2Bulge(p1, p2, Rad)                         -- Returns the Bulge factor for an arc
    if TableLength(GroupNames) == TableLength(CleanNames)then
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
      return true
  local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
    else
  local bulge = (2 * seg) / chord
      return false
  return bulge
    end
end -- function end</nowiki>
  end -- function end
 
----


  -- =====================================================]]
===TrigIt===
  function INI_FixDupGroups(xPath, xFile)                -- Find and fix duplicate groups
Calculates Right Angle
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
    return true
  end -- function end


  -- =====================================================]]
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  function INI_DeleteGroup(xPath, xFile, xGroup)          -- Deletes only the first find of xGroup
<nowiki>function TrigIt()                                      -- Calculates Right Angle
-- Deletes old ini (.bak) file
-- ==Trig Function==
-- Copy's the .ini to a backup (.bak) new file
-- VECTRIC LUA SCRIPT
-- Reads the new backup file and writes a new file to the xGroup value
-- =====================================================]]
-- Stops Writing lines until next Group is found
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- Writes to end of file
-- They are provided 'as-is', without any express or implied warranty, and you
-- Call: DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
--   make use of them entirely at your own risk.
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages
    if FileExists(OfileName) then
--  arising from their use.
      os.remove(OfileName)
-- Permission is granted to anyone to use this software for any purpose,
    end
-- including commercial applications, and to alter it and redistribute it freely,
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
-- subject to the following restrictions:
--    os.rename(NfileName, OfileName) -- makes backup copy file
-- 1. The origin of this software must not be misrepresented; you must not
    if CopyFileFromTo(NfileName, OfileName) then
--    claim that you wrote the original software.
      local fileR  = io.open(OfileName)
-- 2. If you use this software in a product, an acknowledgement in the product
      local fileW  = io.open(NfileName, "w")
--    documentation would be appreciated but is not required.
      local groups  = false
-- 3. Altered source versions must be plainly marked as such, and must not be
      local writit  = true
--    misrepresented as being the original software.
      local MyTxt  = ""
-- 4. This notice may not be removed or altered from any source distribution.
      local txt = ""
--
      if fileR and fileW then  -- files are open
-- Right Triangle TrigFunction is written by Jim Anderson of Houston Texas 2020
        for Line in fileR:lines() do  -- read each line of the backup file
-- =====================================================]]
          txt = Line  -- copy line from file to txt
-- Code Debugger
          if All_Trim(Line) == "[" .. All_Trim(xGroup) ..  MyTxt .. "]" then  -- look for a match
-- require("mobdebug").start()
            groups = true
-- =====================================================]]
            txt = ""
-- Global Variables --
          end -- if end
    Trig = {}
          if groups and MyTxt == "" then  -- if group is true turn off the write function
-- =====================================================]]
            writit = false
  function TrigTest() -- Test the All Right Angle
            if "[" == string.sub(All_Trim(txt), 1, 1) then  -- turns write function on if next group is found
    TrigClear()
              groups = false
    Trig.A  =  0.0
              xGroup = "-"
    Trig.B  = 0.0
              writit = true
    Trig.C  = 90.0
              MyTxt  = "--"
     Trig.Opp =  3.0  -- Rise  or (B2C)
            else
     Trig.Adj =  4.0  -- Base  or (A2C)
              writit = false
     Trig.Hyp =  0.0  -- Slope or (A2B)
            end -- if end
    Trig.Slope =  0.0
          end -- if end
    Trig.Area =  0.0
          if writit then
    Trig.OutRadius = 0.0
            fileW:write(txt .. "\n")
    Trig.InRadius = 0.0
            txt = ""
    Trig.Parameter = 0.0
          end -- if end
    TrigIt()
        end -- for end
    DisplayMessageBox("Test 1: \n" ..
        os.remove(OfileName)
    " Trig.A  = " .. tostring(Trig.A) .. " \n" ..
      end -- if end
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
      if fileR then fileR:close() end
    " Trig.C  = " .. tostring(Trig.C) .. " \n" ..
      if fileW then fileW:close() end
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    end
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    return true
    " Trig.Hyp = " .. tostring(Trig.Hyp) .. " \n" ..
  end -- function end
    " Trig.Slope = " .. tostring(Trig.Slope) .. " \n" ..
 
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  -- =====================================================]]
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
  function INI_RenameGroup(xOldGroup, xNewGroup)          -- Renames a group
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
--Deletes old ini Hardware.bak file
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
--Copys the ini file to a backup copy file
    )
--Reads the backup file and writes a new ini file to the xGroup
    -- =====================================================]]
--Writes new file with new group  to the new ini file
    TrigClear()
  local NfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".ini"
    Trig.A  =  0.0
  local OfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".bak"
    Trig.B  =  0.0
  os.remove(OfileName)
    Trig.C  = 90.0
  CopyFileFromTo(NfileName, OfileName) -- makes backup file
    Trig.Opp =  0.-- Rise  or (B2C)
  local fileR = io.open(OfileName)
    Trig.Adj = 4.0  -- Base  or (A2C)
  local fileW = io.open(NfileName, "w")
     Trig.Hyp =  5.0  -- Slope or (A2B)
  if fileR and fileW then
     Trig.Slope =  0.0
    local groups = false
     Trig.Area =  0.0
    local txt = ""
    Trig.OutRadius =  0.0
    for Line in fileR:lines() do
    Trig.InRadius =  0.0
      if All_Trim(Line) == "[" .. All_Trim(xOldGroup) .. txt .. "]" then -- Group
    Trig.Parameter =  0.0
        fileW:write(xNewGroup .. "\n")
    TrigIt()
        txt = "-"
    DisplayMessageBox("Test 2: \n" ..
      else
    " Trig.A  = " .. tostring(Trig.A) .. " \n" ..
        fileW:write(Line .. "\n")
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
      end -- if end
    " Trig.C  = " .. tostring(Trig.C) .. " \n" ..
     end -- for end
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    fileR:close()
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
     fileW:close()
    " Trig.Hyp = " .. tostring(Trig.Hyp) .. " \n" ..
     os.remove(OfileName)
    " Trig.Slope = " .. tostring(Trig.Slope) .. " \n" ..
  end -- if end
    " Trig.Area = " .. tostring(Trig.Area) .. " \n" ..
  return true
    " Trig.Parameter = " .. tostring(Trig.Parameter) .. " \n" ..
end -- function end
    " Trig.OutRadius = " .. tostring(Trig.OutRadius) .. " \n" ..
 
    " Trig.InRadius = " .. tostring(Trig.InRadius) .. " \n"
  -- =====================================================]]
     )
  function INI_DeleteItem(xPath, xFile, xGroup, xItem)
     -- =====================================================]]
-- Deletes old ini (.bak) file
    TrigClear()
-- Copys the .ini to a backup (.bak) new file
     Trig.A  =  0.0
-- Reads the new backup file and writes a new file to the xGroup value
    Trig.B  = 0.0
-- Stops Writing lines until next Group is found
     Trig.C  = 90.0
-- Writes to end of file
    Trig.Opp = 3.0  -- Rise  or (B2C)
-- DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
    Trig.Adj = 0.0  -- Base or (A2C)
  local NfileName = xPath .. "\\" .. xFile .. ".ini"
    Trig.Hyp =  5.0 -- Slope or (A2B)
  local OfileName = xPath .. "\\" .. xFile .. ".bak"
    Trig.Slope = 0.0
  os.remove(OfileName)
    Trig.Area =  0.0
  CopyFileFromTo(NfileName, OfileName) -- makes backup copy file
    Trig.OutRadius =  0.0
  local fileR = io.open(OfileName)
    Trig.InRadius = 0.0
  local fileW = io.open(NfileName,  "w")
    Trig.Parameter =  0.0
  if fileR and fileW then
    TrigIt()
    local groups = false
    DisplayMessageBox("Test 3: \n" ..
    local writit = true
    " Trig.A = " .. tostring(Trig.A) .. " \n" ..
    local txt = ""
     " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    for Line in fileR:lines() do
     " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
      txt = Line
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
      if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
        groups = true
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
      end -- if end
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
      if groups then
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  -- ===================
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
        if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
          writit = false
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
          groups = false
    )
        end -- if end
    -- =====================================================]]
      end -- if end
    TrigClear()
  -- ===================
    Trig.A  36.86897645844
      if writit then
    Trig.B  =  0.0
        fileW:write(txt .. "\n")
    Trig.C  = 90.0
      end -- if end
    Trig.Opp = 3.0 -- Rise  or (B2C)
      writit = true
    Trig.Adj =  0.0  -- Base  or (A2C)
    end -- for end
    Trig.Hyp = 0.0 -- Slope or (A2B)
     os.remove(OfileName)
    Trig.Slope =  0.0
     fileR:close()
    Trig.Area =  0.0
     fileW:close()
    Trig.OutRadius =  0.0
  end -- if end
    Trig.InRadius =  0.0
  return true
    Trig.Parameter =  0.0
end -- function end
    TrigIt()
 
     DisplayMessageBox("Test 4: \n" ..
-- =======================================================]]
     " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
  function INI_ValidateGroup(xFile, xGroup)               -- Reads INI file and returns true if group is found
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
  -- Reads INI file and returns true if the group is found
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
  local fileR = io.open(xFile)
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
  local group = false
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
  for Line in fileR:lines() do
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    if string.upper(All_Trim(Line)) == "[" .. string.upper(All_Trim(xGroup)) .. "]" then  -- Group
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
     group = true
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
     break
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    end -- if end
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  end -- for end
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
  fileR:close()
    )
  return group
    -- =====================================================]]
end -- function end
     TrigClear()
-- =======================================================]]
     Trig.A  = 36.86897645844
  function INI_ValidateItem(xFile, xGroup, xItem)         -- Reads INI file and returns true if group and item is found
    Trig.B  =  0.0
     local fileR = io.open(xFile)
    Trig.C  = 90.0
     if fileR then
     Trig.Opp = 0.0  -- Rise  or (B2C)
      local group = false
     Trig.Adj = 4.0  -- Base  or (A2C)
      local item = false
     Trig.Hyp = 0.0  -- Slope or (A2B)
      local ItemLen = string.len(xItem)
     Trig.Slope =  0.0
      for Line in fileR:lines() do
    Trig.Area = 0.0
        if All_Trim(Line) == "[" .string.upper(All_Trim(xGroup)) .. "]" then -- Group
    Trig.OutRadius = 0.0
        group = true
    Trig.InRadius = 0.0
        end -- if end
    Trig.Parameter =  0.0
        if group then
    TrigIt()
          if string.upper(xItem) == string.upper(string.sub(Line, 1, string.len(xItem))then -- Item
    DisplayMessageBox("Test 5: \n" ..
            item = true
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
            break
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
          end -- if end
    " Trig.= " .. tostring(Trig.C) .. " \n" ..
        end -- if end
    " Trig.Opp = " .. tostring(Trig.Opp) .. " \n" ..
      end -- for end
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
      fileR:close()
     " Trig.Hyp = " .. tostring(Trig.Hyp) .. " \n" ..
     end -- if end
     " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
     return group
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
  end -- function end
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
 
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
  -- =====================================================]]
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
  function INI_StrValue(str, ty)
    )
-- Convert string to the correct data type
    -- =====================================================]]
    if nil == str then
    TrigClear()
      DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
     Trig.A  = 36.86897645844
    else
     Trig.B  =  0.0
      if "" == All_Trim(str) then
    Trig.C  = 90.0
        DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
     Trig.Opp =  0.0  -- Rise  or (B2C)
      else
    Trig.Adj = 0.0  -- Base  or (A2C)
        local j = (string.find(str, "=") + 1)
     Trig.Hyp =  5.0  -- Slope or (A2B)
        if ty == "D" then -- Double
     Trig.Slope = 0.0
          return tonumber(string.sub(str, j))
    Trig.Area =  0.0
        end -- if end
    Trig.OutRadius =  0.0
        if ty == "I" then -- Intiger
    Trig.InRadius =  0.0
          return math.floor(tonumber(string.sub(str, j)))
     Trig.Parameter = 0.0
        end -- if end
    TrigIt()
        if ty == "S" then -- String
     DisplayMessageBox("Test 6: \n" ..
          return All_Trim(string.sub(str, j))
     " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
        end -- if end
    " Trig.B  = " .. tostring(Trig.B) .. " \n" ..
        if ty == "B" then -- Bool
    " Trig.= " .. tostring(Trig.C) .. " \n" ..
          if "TRUE" == All_Trim(string.sub(str, j)) then
    " Trig.Opp = " .. tostring(Trig.Opp) .. " \n" ..
            return true
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
          else
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
            return false
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
          end -- if end
     " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
        end -- if end
     " Trig.Parameter = " .. tostring(Trig.Parameter) .. " \n" ..
      end -- if end
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
     end -- if end
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
     return nil
    )
  end -- function end
    TrigClear()
 
    Trig.A  =  0.0
  -- =====================================================]]
    Trig.B  =  0.0
  function INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)
    Trig.C  = 90.0
    -- ==INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)==
    Trig.Opp =  3.0  -- Rise  or (B2C)
     -- Returns a value from a file, group, and Item
    Trig.Adj =  0.0  -- Base  or (A2C)
    -- Usage: XX.YY = GetIniValue("C:/temp", "ScrewDia", "[Screws]", "Diameter", "D")
    Trig.Hyp =  0.0  -- Slope or (A2B)
     local filenameR = xPath .. "\\" .. FileName .. ".ini"
    Trig.Slope =  9.0
     local FL = LengthOfFile(filenameR)
    Trig.Area =  0.0
     local file = io.open(filenameR, "r")
    Trig.OutRadius =  0.0
     local dat = "."
    Trig.InRadius =  0.0
    local ItemNameLen = string.len(ItemName)
    Trig.Parameter =  0.0
     if file then
    TrigIt()
      while (FL >= 1) do
    DisplayMessageBox("Test 7: \n" ..
        dat = string.upper(All_Trim(file:read()))
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
        if dat == "[" .. string.upper(GroupName) .. "]" then
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
          break
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
        else
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
          FL = FL - 1
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
        end -- if end
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
      end -- while end
    " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
      while (FL >= 1) do
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
        dat = string.upper(All_Trim(file:read()))
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
        if string.upper(ItemName) == string.sub(dat, 1, ItemNameLen) then
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
          break
    " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
        else
    " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
          FL = FL - 1
    )
          if FL == 0 then
    -- =====================================================]]
            dat = "Error - item not  found"
    TrigClear()
            break
    Trig.A  =  0.0
          end -- if end
    Trig.B  =  0.0
        end -- if end
    Trig.C  = 90.0
      end -- while end
    Trig.Opp =  0.0  -- Rise  or (B2C)
      file:close()-- closes the open file
    Trig.Adj =  0.0  -- Base  or (A2C)
     end -- if end
    Trig.Hyp =  0.0  -- Slope or (A2B)
    local XX = StrIniValue(dat, ValueType)
    Trig.Slope =  9.0
     return XX
    Trig.Area =  0.0
  end -- function end
    Trig.OutRadius =  0.0
 
    Trig.InRadius =  0.0
  -- =====================================================]]
    Trig.Parameter =  0.0
  function INI_GetIDFor(xPath, FileName, GroupName, ItemValue)
    TrigIt()
     -- == INI_GetIDFor(xPath, FileName, GroupName, ItemValue) ==
    DisplayMessageBox("Test Error: \n" ..
     -- Returns a ItemID from a file, group, and ItemValue
      " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
     -- Usage: XX.YY = INI_GetIDFor("C:/temp", "UserList", "[Users]", "Anderson")
      " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
     -- returns: "UserLastName22"
      " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
     local filenameR = xPath .. "\\" .. FileName .. ".ini"
      " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
     local FL = LengthOfFile(filenameR)
      " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
     local file = io.open(filenameR, "r")
      " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
     if file then
      " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
      local dat = "."
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
      local ItemValueLen = string.len(ItemValue)
      " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
      while (FL >= 1) do
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
        dat = string.upper(All_Trim(file:read()))
      " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
        if dat == "[" .. string.upper(GroupName) .. "]" then
      " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
          break
    )
        else
     return true
          FL = FL - 1
  end -- function end --
        end -- if end
-- =====================================================]]
      end -- while end
  function TrigClear()  -- Clears and resets Trig Table
      while (FL >= 1) do
    Trig.A  =  0.0
        dat = string.upper(All_Trim(file:read()))
    Trig.B  =  0.0
        if string.upper(ItemValue) == HeadStrip(dat, "=")  then
    Trig.C  = 90.0
          break
    Trig.Opp =  0.0  -- Rise  or (B2C)
        else
    Trig.Adj =  0.0  -- Base  or (A2C)
          FL = FL - 1
    Trig.Hyp =  0.0  -- Slope or (A2B)
          if FL == 0 then
    Trig.Slope =  0.0
            dat = "Error - item not found"
    return true
            break
          end -- if end
        end -- if end
      end -- while end
      file:close()-- closes the open file
     end -- if end
     local XX = NameStrip(dat, "=")
     return XX
   end -- function end
   end -- function end
 
-- =====================================================]]
  -- =====================================================]]
      local function BSA()
  function INI_ReadGroups(xFile, aName)
        Trig.= (Trig.C - Trig.A)
  --[[Reads INI and returns a list contain the [Headers] as Array
         Trig.Slope = math.tan(math.rad(Trig.A)) * 12.0
  IniFile = {} Global variables
         Trig.Area = (Trig.Opp * Trig.Adj) * 0.5
  xPath = script_path
         Trig.Inscribing = ((Trig.Opp + Trig.Adj) - Trig.Hyp) * 0.5
  ]]
         Trig.Circumscribing = Trig.Hyp * 0.5
    local filename = xFile
        Trig.Parameter = Trig.Opp + Trig.Adj + Trig.Hyp
    local file = io.open(filename, "r")
    if file then
      local fLength = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (fLength >= 1) do
         if "[" == string.sub(dat, 1, 1) then
          table.insert (aName, string.sub(dat, 2, -2))
         end
        dat = file:read()
         if dat then
          dat = All_Trim(dat)
        else
          file:close()-- closes the open file
          return true
         end
        fLength = fLength - 1
      end -- while
    end -- if
    if file then file:close() end
    return true
  end
 
  -- =====================================================]]
  function INI_ProjectHeaderReader(xPath)
  -- ==ProjectHeaderReader(xPath)==
  -- Gets the INI Header values of a ini file and uploads to "IniFile" Array
  --[[
  Gets the INI Header values of a ini file and uploads to "IniFile" Array
  IniFile = {} Global variables
  xPath = script_path
  ]]
    local filename = xPath .. "/CabinetProjects.ini"
    local file = io.open(filename, "r")
    if file then
      local Cabing = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (Cabing >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (Projects, string.sub(dat, 2, -2))
        end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          return true
        end
        Cabing = Cabing - 1
       end
       end
       file:close()
       if Trig.A == 0.0 and Trig.B > 0.0 and Trig.Slope == 0.0 then
    end
        Trig.A = Trig.C - Trig.B
    return true
      elseif Trig.A == 0.0 and Trig.B == 0.0 and Trig.Slope > 0.0 then
  end -- function end
        Trig.A = math.deg(math.atan(Trig.Slope / 12.0))
 
      end -- if end
 
-- test 4
  -- =====================================================]]
      if (Trig.A > 0.0) and (Trig.Opp >  0.0) then -- A and Rise or (B2C)
  function INI_AddNewProject(xPath, xGroup)
        Trig.Adj =  Trig.Opp / (math.tan(math.rad(Trig.A)))
  -- Appends a New Project to CabinetProjectQuestion.ini
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
  -- ==AddNewProject(xPath)==
        BSA()
  -- Appends a New Project to CabinetProjectQuestion.ini
        return true
    local filename = xPath .. "/ProjectList.ini"
      -- test 6
    local file = io.open(filename, "a")
      elseif (Trig.A > 0.0) and (Trig.Hyp >  0.0)  then -- A and Slope or (A2B)
    if file then
        Trig.Adj = math.cos(math.rad(Trig.A)) * Trig.Hyp
      file:write("[" .. All_Trim(xGroup) .. "] \n")
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
      file:write("load_date = " .. StartDate(true) .. " \n")
        BSA()
      file:write("#====================================== \n")
        return true
       file:close()-- closes the open file
      -- test 5
    end
      elseif (Trig.A > 0.0) and (Trig.Adj >  0.0)  then -- A and Base or (A2C)
     return true
        Trig.Opp = math.tan(math.rad(Trig.A)) * Trig.Adj
  end -- function end
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
 
        BSA()
  -- =====================================================]]
        return true
  function INI_StdHeaderReader(xPath, Fname)
        -- test 1
  -- ==StdHeaderReader(xPath, Fname)==
      elseif (Trig.Opp >  0.0) and (Trig.Adj >  0.0) then -- Rise and Base
  -- Gets the INI Header values of a ini file and uploads to "IniFile" Array
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
  --[[
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
  Gets the INI Header values of a ini file and uploads to "IniFile" Array
        BSA()
  IniFile = {} Global variables
        return true
  xPath = script_path
      elseif (Trig.Adj >  0.0) and (Trig.Hyp >  0.0) then -- Rise and Slope
  ]]
-- test 2
    local filename = xPath .. "\\" .. Fname .. ".ini"
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
    local file = io.open(filename, "r")
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
    if file then
        BSA()
      local WallMilling = (LengthOfFile(filename) - 1)
        return true
      local dat = All_Trim(file:read())
      elseif (Trig.Opp >  0.0) and (Trig.Hyp >  0.0) then -- Base and Slope
      while (WallMilling >= 0) do
-- test 3
        if "[" == string.sub(dat, 1, 1) then
        Trig.Adj = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Opp * Trig.Opp))
          table.insert (IniFile, string.sub(dat, 2, -2))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        end -- if end
        BSA()
        dat = file:read()
        return true
        if dat then
      else
          dat = All_Trim(dat)
        DisplayMessageBox("Error: Trig Values did not match requirements: \n" ..
        else
                          " Trig.A  = " .. tostring(Trig.A) .. " \n" ..
          return true
                          " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
        end -- if end
                          " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
        WallMilling = WallMilling - 1
                          " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
      end -- while end
                          " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
      file:close()
                          " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    end
                          " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    return true
                          " Trig.Area = " .. tostring(Trig.Area) .. " \n" ..
  end  -- function end
                          " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
                          " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
                          " Trig.InRadius = " .. tostring(Trig.InRadius) .. " \n"
                          )
        return false
       end
     end -- function end
-- =====================================================]]
end -- Geometry Tools end


</nowiki>


  -- =====================================================]]
==INI File Tools==
  function INI_ReadProjectinfo(Table, xPath, xGroup, xFile)
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
-- ProjectQuestion = {}
These functions manipulate the INI files for the storage and retrieval of data.
-- ==ReadProjectinfo(xPath, xGroup, xFile)==
-- Reads an ini files group and sets the table.names
    Table.ProjectContactEmail      = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactEmail", "S")
    Table.ProjectContactName        = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactName", "S")
    Table.ProjectContactPhoneNumber = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactPhoneNumber", "S")
    Table.ProjectName              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectName", "S")
    Table.ProjectPath              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectPath", "S")
    Table.StartDate                = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.StartDate", "S")
    return true
  end -- function end




  -- =====================================================]]
===INI_NameStrip===
  function INI_UpdateItem(xPath, xFile, xGroup, xItem, xValue)
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  -- Deletes old ini (.bak) file
Convert string to the correct data type.
  -- Copys the .ini to a backup (.bak) new file
  -- Reads the new backup file and writes a new file to the xGroup
  -- Writes new xValue for the for the xItem
  -- Reads and writes a new file to end of file
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
    os.remove(OfileName)
    if CopyFileFromTo(NfileName, OfileName) then-- makes backup file
      local fileR = io.open(OfileName)
      local fileW = io.open(NfileName,  "w")
      if fileR and fileW then
        local groups = false
        local txt = ""
        for Line in fileR:lines() do
          txt = Line
          if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then -- Group
            groups = true
          end -- if end
          if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
            if groups then
              txt = xItem .. " = " .. xValue
              groups = false
            end -- if end
          end -- if end
          fileW:write(txt .. "\n")
          txt = ""
        end -- for end
        os.remove(OfileName)
        fileR:close()
        fileW:close()
      end
    end
    return true
  end -- function end


Local Words = NameStrip("KPSDFKSPSK - 34598923", "-") -- returns "KPSDFKSPSK"


  -- =====================================================]]
  function INI_ReadProject(xPath, xFile, xGroup)
  -- Milling = {}
    Milling.LayerNameBackPocket          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameBackPocket", "S")
    Milling.LayerNameTopBottomCenterDado = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameTopBottomCenterDado", "S")
    Milling.LayerNameDrawNotes          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawNotes", "S")
    Milling.LayerNameDrawFaceFrame      = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawFaceFrame", "S")
    Milling.BackPocketDepthWall          = GetIniValue(xPath, xFile, xGroup, "Milling.BackPocketDepthWall", "N")
    Milling.BlindDadoSetbackWall        = GetIniValue(xPath, xFile, xGroup, "Milling.BlindDadoSetbackWall", "N")
    Milling.CabDepthWall                = GetIniValue(xPath, xFile, xGroup, "Milling.CabDepthWall", "N")
    return true
  end -- function end


'''Source Code'''


   -- =====================================================]]
<nowiki> function INI_NameStrip(str, var)
   function INI_TestDeleteDups()
    if "" == str then
    --[[ Requires 3 global variables
      DisplayMessageBox("Error in string")
    clean  = {}
    else
    dups  = {}
      if string.find(str, var) then
    Names  = {}
        local j = assert(string.find(str, var) - 1)
    ]]
        return All_Trim(string.sub(str, 1, j))
    local myPath = "C:\\Users\\CNC\\Documents\\test"
      else
     local myName = "Tester"
        return str
    local myfile = "C:\\Users\\CNC\\Documents\\test\\Tester.ini"
      end
     INI_ReadGroups(myfile, Names)
    end
    FindDups(Names, dups, clean)
   end -- function end </nowiki>
    for i,v in ipairs(dups) do
----
       INI_DeleteGroup(myPath, myName, v)
 
===INI_HeadStrip===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Convert string to the correct data type.
 
<nowiki>
   function INI_HeadStrip(str, var)                           -- convert string to the correct data type
-- Local Words = HeadStrip("LastName23 = Smith", "=") -- returns "Smith"
     if "" == str then
      DisplayMessageBox("Error in string")
     else
      if string.find(str, var) then
        local j = assert(string.find(str, var) + 1)
        return All_Trim(string.sub(str, j))
       else
        return str
      end
     end
     end
    return true
  end -- function end </nowiki>
  -- =====================================================]]
----
 
===INI_AreDupGroups===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Checks if there are duplicate groups.


end -- INI_Tools()
<nowiki>function INI_AreDupGroups(xPath, xFile)
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
      CleanNames = RemoveDups(GroupNames)
    if TableLength(GroupNames) == TableLength(CleanNames)then
      return true
    else
      return false
    end
  end -- function end </nowiki>
----


-- =====================================================]]
===INI_FixDupGroups===
end -- INI Tools end
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Find and fix duplicate groups


</nowiki>
  <nowiki>function INI_FixDupGroups(xPath, xFile)
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
    return true
  end -- function end</nowiki>
----


==Data Import Tools==
===INI_DeleteGroup===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Deletes only the first find of xGroup


<nowiki>  
  <nowiki>function INI_DeleteGroup(xPath, xFile, xGroup)
-- Deletes old ini (.bak) file
-- =====================================================]]
-- Copy's the .ini to a backup (.bak) new file
╔╦╗╔═╗╔╦╗╔═╗  ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
-- Reads the new backup file and writes a new file to the xGroup value
║║╠═╣ ║ ╠═╣  ║║║║╠═╝║ ║╠╦╝ ║    ║ ║ ║║ ║║  ╚═╗
-- Stops Writing lines until next Group is found
═╩╝╩ ╩ ╩ ╩ ╩  ╩╩ ╩╩  ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
-- Writes to end of file
function ImportTools()
-- Call: DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
-- =====================================================]]
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
function Read_CSV(xFile, Header)
    if FileExists(OfileName) then
  --Read_CSV(Door.CSVFile, true)
      os.remove(OfileName)
  local fileR = io.open(xFile)
    end
   local xLine = ""
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
  local result = {}
--    os.rename(NfileName, OfileName) -- makes backup copy file
  if fileR then
    if CopyFileFromTo(NfileName, OfileName) then
    for Line in fileR:lines() do
      local fileR   = io.open(OfileName)
      xLine = Line
      local fileW   = io.open(NfileName,  "w")
      if Header then
      local groups  = false
        Header = false
      local writit  = true
      else
      local MyTxt  = ""
        xLine = All_Trim(Line)
      local txt = ""
        for match in (xLine..","):gmatch("(.-)"..",") do
      if fileR and fileW then -- files are open
           table.insert(result, match)
        for Line in fileR:lines() do -- read each line of the backup file
          txt = Line -- copy line from file to txt
          if All_Trim(Line) == "[" .. All_Trim(xGroup) ..  MyTxt .. "]" then  -- look for a match
            groups = true
            txt = ""
          end -- if end
          if groups and MyTxt == "" then -- if group is true turn off the write function
            writit = false
            if "[" == string.sub(All_Trim(txt), 1, 1) then  -- turns write function on if next group is found
              groups = false
              xGroup = "-"
              writit = true
              MyTxt  = "--"
            else
              writit = false
            end -- if end
          end -- if end
          if writit then
            fileW:write(txt .. "\n")
            txt = ""
           end -- if end
         end -- for end
         end -- for end
         Door.Count    = tonumber(result[1])
         os.remove(OfileName)
        Door.Height    = tonumber(result[2])
      end -- if end
        Door.Width    = tonumber(result[3])
       if fileR then fileR:close() end
 
       if fileW then fileW:close() end
        result = {}
     end
        while Door.Count > 0 do
    return true
          if      Door.Style == StyleA.Name then
  end -- function end</nowiki>
            DoorStyleA()
----
          elseif  Door.Style == StyleB.Name then
            DoorStyleB()
          elseif  Door.Style == StyleC.Name then
            DoorStyleC()
          elseif  Door.Style == StyleE.Name then
            DoorStyleE()
          elseif  Door.Style == StyleF.Name then
            DoorStyleF()
          elseif  Door.Style == StyleG.Name then
            DoorStyleG()
          else
            DisplayMessageBox("No Style Select!")
          end --if end
          Door.Count =  Door.Count - 1
        end -- for end
       end --if end
       Door.Record = Door.Record + 1
      MyProgressBar:SetPercentProgress(ProgressAmount(Door.Record))
     end --for end
  end --if end
  return true
end -- function end
-- =====================================================]]
end -- ImportTools function end


</nowiki>
===INI_RenameGroup===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Renames a group


==Job Tools==
  <nowiki>function INI_RenameGroup(xOldGroup, xNewGroup)
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
--Deletes old ini Hardware.bak file
 
--Copys the ini file to a backup copy file
<nowiki>
--Reads the backup file and writes a new ini file to the xGroup
   
--Writes new file with new group to the new ini file
-- =====================================================]]
  local NfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".ini"
╦╔═╗╔╗   ╔╦╗╔═╗╔═╗╦  ╔═╗
   local OfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".bak"
║║ ║╠╩╗   ║ ║ ║║ ║║  ╚═╗
   os.remove(OfileName)
╚╝╚═╝╚═╝   ╩ ╚═╝╚═╝╩═╝╚═╝
   CopyFileFromTo(NfileName, OfileName) -- makes backup file
function JobTools()
  local fileR = io.open(OfileName)
-- =====================================================]]
   local fileW = io.open(NfileName, "w")
   function ValidJob()
   if fileR and fileW then
   -- A better error message
    local groups = false
     local job = VectricJob()
     local txt = ""
    if not job.Exists then
    for Line in fileR:lines() do
      DisplayMessageBox("Error: Cannot run Gadget, no drawing found \n" ..
      if All_Trim(Line) == "[" .. All_Trim(xOldGroup) .. txt .. "]" then -- Group
                        "Please create a new file (drawing) and \n" ..
        fileW:write(xNewGroup .. "\n")
                        "specify the material dimensions \n"
        txt = "-"
      )
      else
       return false
        fileW:write(Line .. "\n")
    else
       end -- if end
      return true
    end -- for end
    end -- if end
     fileR:close()
  end -- ValidJob end
     fileW:close()
-- =====================================================]]
     os.remove(OfileName)
  function MoveSetectedVectors(job, NewBasePoint)
  end -- if end
     local Selection = job.Selection
  return true
    if Selection.IsEmpty then
end -- function end</nowiki>
      MessageBox("LayoutImportedVectors: No vectors selected!")
----
      return false
 
    end
===INI_DeleteItem===
     local MySelection = Selection:GetBoundingBox();
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
     if not NewBasePoint then
Deleates a group
      NewBasePoint = Point2D(0,0)
 
    end
   <nowiki>function INI_DeleteItem(xPath, xFile, xGroup, xItem)
    local MyNewLocatioin = BasePoint - MySelection.BLC
-- Deletes old ini (.bak) file
    local Txform = TranslationMatrix2D(MyNewLocatioin)
-- Copys the .ini to a backup (.bak) new file
    Selection:Transform(Txform)
-- Reads the new backup file and writes a new file to the xGroup value
    return true
-- Stops Writing lines until next Group is found
  end
-- Writes to end of file
-- =====================================================]]
-- DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
   function FixPath(path)                               -- Lua Returns a fixed path
  local NfileName = xPath .. "\\" .. xFile .. ".ini"
    return path:gsub("%\\", "/")
  local OfileName = xPath .. "\\" .. xFile .. ".bak"
  end -- function end
  os.remove(OfileName)
-- =====================================================]]
  CopyFileFromTo(NfileName, OfileName) -- makes backup copy file
  function FixPath(myPath) {                            -- JavaScript Tool Returns a fixed path
  local fileR = io.open(OfileName)
    /* myPath  = "C:\\User\\Bob\\Home\\Drawings"; */
  local fileW = io.open(NfileName,  "w")
    /* NewPath = "C:/User/Bob/Home/Drawings"; */
  if fileR and fileW then
    var NewPath = "";
    local groups = false
    var myLetter = "";
    local writit = true
     var CheckPathLen = myPath.length;
     local txt = ""
     for (let i = 0; i < myPath.length; i++) {
     for Line in fileR:lines() do
       myLetter = myPath.charAt(i)
       txt = Line
       if myLetter.charCodeAt(0) == 92 {
       if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then
        NewPath = NewPath + "/";
         groups = true
      } else {
       end -- if end
         NewPath = NewPath + myLetter;
      if groups then
       }
   -- ===================
    }
        if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
    return NewPath;
          writit = false
  }
          groups = false
   -- =====================================================]]
        end -- if end
  function GetUnits(UTable)                              -- returns Drawing Units data
      end -- if end
    local mtl_block = MaterialBlock()
  -- ===================
    if mtl_block.InMM then
      if writit then
      UTable.Units  = "Drawing Units: mm"
        fileW:write(txt .. "\n")
      UTable.Unit = true
       end -- if end
      UTable.UnitCheck = {"metric", "kilometer", "kilometers", "kh", "meter", "meters", "m", "decimeter", "decimeters", "dm", "centimeter", "centimeters", "cm", "millimeter", "millimeters", "mm"}
       writit = true
       UTable.Cal = 25.4
    end -- for end
    else
    os.remove(OfileName)
       UTable.Units  = "Drawing Units: inches"
    fileR:close()
      UTable.Unit = false
     fileW:close()
      UTable.UnitCheck = {"imperial", "miles", "mile", "mi", "yards", "yard", "yd", "feet", "foot", "ft", "inches", "inch", "in", "fractions", "fraction"}
  end -- if end
      UTable.Cal = 1.0
  return true
     end
end -- function end</nowiki>
    return true
----
  end -- end function
 
  -- =====================================================]]
===INI_ValidateGroup===
function CheckTheUnits(UTable, Value)                     -- Checks if the unit of messure in of drawing units
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
   local goodtogo = false
Reads INI file and returns true if group is found
   for i=1, #UTable.UnitCheck  do
 
     if string.upper(Value) == string.upper(UTable.UnitCheck[i]) then
  <nowiki>function INI_ValidateGroup(xFile, xGroup)
      goodtogo = true
  -- Reads INI file and returns true if the group is found
      break
  local fileR = io.open(xFile)
   local group = false
   for Line in fileR:lines() do
     if string.upper(All_Trim(Line)) == "[" .. string.upper(All_Trim(xGroup)) .. "]" then -- Group
    group = true
    break
     end -- if end
     end -- if end
   end -- for end
   end -- for end
   if goodtogo then
   fileR:close()
    return true
   return group
   else
end -- function end</nowiki>
    return false
----
  end -- if end
 
end -- function end
===INI_ValidateItem===
  -- =====================================================]]
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
   function GetMatlBlk(Table)
Reads INI file and returns true if group and item is found
     local mtl_block = MaterialBlock()
 
     if mtl_block.InMM then
   <nowiki>function INI_ValidateItem(xFile, xGroup, xItem)
       Table.Units = "Drawing Units: mm"
     local fileR = io.open(xFile)
       Table.Unit = true
     if fileR then
    else
       local group = false
       Table.Units = "Drawing Units: inches"
       local item = false
      Table.Unit = false
      local ItemLen = string.len(xItem)
    end
       for Line in fileR:lines() do
    if mtl_block.Width> mtl_block.Height then
        if All_Trim(Line) == "[" ..  string.upper(All_Trim(xGroup)) .. "]" then  -- Group
       Table.MaterialThickness = mtl_block.Height
        group = true
       Table.MaterialLength = mtl_block.Width
        end -- if end
      Table.Orantation = "H"
        if group then
          if string.upper(xItem) == string.upper(string.sub(Line, 1, string.len(xItem)))  then -- Item
            item = true
            break
          end -- if end
        end -- if end
      end -- for end
       fileR:close()
    end -- if end
    return group
  end -- function end</nowiki>
----
 
===INI_StrValue===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Reads INI file and returns string value
 
  <nowiki>function INI_StrValue(str, ty)
-- Convert string to the correct data type
    if nil == str then
       DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
     else
     else
       Table.MaterialThickness = mtl_block.Width
       if "" == All_Trim(str) then
       Table.MaterialLength = mtl_block.Height
        DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
      Table.Orantation = "V"
       else
    end
        local j = (string.find(str, "=") + 1)
    Table.FrontThickness = Dovetail.MaterialThickness
        if ty == "D" then -- Double
    Table.SideThickness = Dovetail.MaterialThickness
          return tonumber(string.sub(str, j))
    if mtl_block.Height == mtl_block.Width then
        end -- if end
        MessageBox("Error! Material block cannot square")
        if ty == "I" then  -- Intiger
     end
          return math.floor(tonumber(string.sub(str, j)))
     return true
        end -- if end
   end -- end function
        if ty == "S" then  -- String
  -- =====================================================]]
          return All_Trim(string.sub(str, j))
   function GetBoxJointMaterialSettings(Table)
        end -- if end
     local mtl_block = MaterialBlock()
        if ty == "B" then -- Bool
     --local units
          if "TRUE" == All_Trim(string.sub(str, j)) then
     if mtl_block.InMM then
            return true
      Table.Units = "Drawing Units: mm"
          else
      Table.Unit = true
            return false
    else
          end -- if end
      Table.Units = "Drawing Units: inches"
        end -- if end
      Table.Unit = false
      end -- if end
     end
     end -- if end
    if mtl_block.Width > mtl_block.Height then
     return nil
      Table.MaterialThickness = mtl_block.Height
   end -- function end</nowiki>
      Table.MaterialLength = mtl_block.Width
----
      Table.Orantation = "H"
 
    else
===INI_GetValue===
      Table.MaterialThickness = mtl_block.Width
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
      Table.MaterialLength = mtl_block.Height
Reads INI file and returns value
      Table.Orantation = "V"
 
     end
   <nowiki>function INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)
     if mtl_block.Height == mtl_block.Width then
     -- ==INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)==
      MessageBox("Error! Material block cannot square")
     -- Returns a value from a file, group, and Item
    end
     -- Usage: XX.YY = GetIniValue("C:/temp", "ScrewDia", "[Screws]", "Diameter", "D")
    -- Display material XY origin
     local filenameR = xPath .. "\\" .. FileName .. ".ini"
     local xy_origin_text = "invalid"
     local FL = LengthOfFile(filenameR)
     local xy_origin = mtl_block.XYOrigin
     local file = io.open(filenameR, "r")
     if xy_origin == MaterialBlock.BLC then
     local dat = "."
         Table.xy_origin_text = "Bottom Left Corner"
     local ItemNameLen = string.len(ItemName)
      if Table.Orantation == "V" then
     if file then
        Table.Direction1 = 90.0
      while (FL >= 1) do
        Table.Direction2 = 0.0
        dat = string.upper(All_Trim(file:read()))
         Table.Direction3 = 270.0
         if dat == "[" .. string.upper(GroupName) .. "]" then
        Table.Direction4 = 180.0
          break
         Table.Bulge = 1.0
         else
       else
          FL = FL - 1
        Table.Direction1 = 0.0
         end -- if end
         Table.Direction2 = 90.0
       end -- while end
         Table.Direction3 = 180.0
      while (FL >= 1) do
         Table.Direction4 = 270.0
         dat = string.upper(All_Trim(file:read()))
        Table.Bulge = -1.0
         if string.upper(ItemName) == string.sub(dat, 1, ItemNameLen)  then
      end
          break
    elseif xy_origin == MaterialBlock.BRC then
         else
      Table.xy_origin_text = "Bottom Right Corner"
          FL = FL - 1
       if Table.Orantation == "V" then
          if FL == 0 then
        Table.Direction1 = 90.0
            dat = "Error - item not  found"
        Table.Direction2 = 180.0
            break
        Table.Direction3 = 270.0
          end -- if end
        Table.Direction4 = 0.0
        end -- if end
        Table.Bulge = -1.0
       end -- while end
      else
      file:close()-- closes the open file
        Table.Direction1 = 180.0
    end -- if end
        Table.Direction2 = 90.0
    local XX = StrIniValue(dat, ValueType)
        Table.Direction3 = 0.0
    return XX
        Table.Direction4 = 270.0
  end -- function end</nowiki>
        Table.Bulge = 1.0
----
      end
 
     elseif xy_origin == MaterialBlock.TRC then
===INI_GetIDFor===
       Table.xy_origin_text = "Top Right Corner"
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
       if Table.Orantation == "V" then
Reads INI file and returns ID for a value
         Table.Direction1 = 270.0
 
         Table.Direction2 = 180.0
  <nowiki>function INI_GetIDFor(xPath, FileName, GroupName, ItemValue)
        Table.Direction3 = 90.0
    -- == INI_GetIDFor(xPath, FileName, GroupName, ItemValue) ==
        Table.Direction4 = 0.0
    -- Returns a ItemID from a file, group, and ItemValue
         Table.Bulge = 1.0
    -- Usage: XX.YY = INI_GetIDFor("C:/temp", "UserList", "[Users]", "Anderson")
       else
    -- returns: "UserLastName22"
        Table.Direction1 = 180.0
    local filenameR = xPath .. "\\" .. FileName .. ".ini"
         Table.Direction2 = 270.0
    local FL = LengthOfFile(filenameR)
         Table.Direction3 = 0.0
     local file = io.open(filenameR, "r")
         Table.Direction4 = 90.0
    if file then
        Table.Bulge = -1.0
       local dat = "."
      end
       local ItemValueLen = string.len(ItemValue)
    elseif xy_origin == MaterialBlock.TLC then
      while (FL >= 1) do
      Table.xy_origin_text = "Top Left Corner"
         dat = string.upper(All_Trim(file:read()))
       if Table.Orantation == "V" then
         if dat == "[" .. string.upper(GroupName) .. "]" then
        Table.Direction1 = 270.0
          break
        Table.Direction2 = 0.0
         else
        Table.Direction3 = 90.0
          FL = FL - 1
        Table.Direction4 = 180.0
        end -- if end
        Table.Bulge = -1.0
       end -- while end
      else
      while (FL >= 1) do
        Table.Direction1 = 0.0
         dat = string.upper(All_Trim(file:read()))
        Table.Direction2 = 270.0
         if string.upper(ItemValue) == HeadStrip(dat, "=")  then
        Table.Direction3 = 180.0
          break
        Table.Direction4 = 90.0
         else
        Table.Bulge = 1.0
          FL = FL - 1
       end
          if FL == 0 then
    elseif xy_origin == MaterialBlock.CENTRE then  -- NOTE: English spelling for Centre!
            dat = "Error - item not  found"
       Table.xy_origin_text = "Center"
            break
      if Table.Orantation == "V" then
          end -- if end
        Table.Direction1 = 0.0
        end -- if end
         Table.Direction2 = 0.0
       end -- while end
         Table.Direction3 = 0.0
      file:close()-- closes the open file
         Table.Direction4 = 0.0
    end -- if end
         Table.Bulge = 1.0
    local XX = NameStrip(dat, "=")
      else
    return XX
        Table.Direction1 = 0.0
  end -- function end</nowiki>
        Table.Direction2 = 0.0
----
         Table.Direction3 = 0.0
 
        Table.Direction4 = 0.0
===INI_ReadGroups===
         Table.Bulge = -1.0
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
       end
Reads INI file group and returns true if found
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
 
     else
  <nowiki>function INI_ReadGroups(xFile, aName)
        Table.xy_origin_text = "Unknown XY origin value!"
  --[[Reads INI and returns a list contain the [Headers] as Array
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
  IniFile = {} Global variables
       if Table.Orantation == "V" then
  xPath = script_path
        Table.Direction1 = 0
  ]]
         Table.Direction2 = 0
    local filename = xFile
         Table.Direction3 = 0
    local file = io.open(filename, "r")
         Table.Direction4 = 0
    if file then
      else
      local fLength = (LengthOfFile(filename) - 1)
        Table.Direction1 = 0
       local dat = All_Trim(file:read())
         Table.Direction2 = 0
       while (fLength >= 1) do
         Table.Direction3 = 0
        if "[" == string.sub(dat, 1, 1) then
        Table.Direction4 = 0
          table.insert (aName, string.sub(dat, 2, -2))
         end
         dat = file:read()
         if dat then
          dat = All_Trim(dat)
         else
          file:close()-- closes the open file
          return true
         end
         fLength = fLength - 1
       end -- while
    end -- if
    if file then file:close() end
     return true
  end -- function end</nowiki>
----
 
===INI_ProjectHeaderReader===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Reads INI file group and returns the INI Header values of a ini file and uploads to "IniFile" Array
 
  <nowiki>function INI_ProjectHeaderReader(xPath)
    local filename = xPath .. "/CabinetProjects.ini"
    local file = io.open(filename, "r")
    if file then
      local Cabing = (LengthOfFile(filename) - 1)
       local dat = All_Trim(file:read())
      while (Cabing >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (Projects, string.sub(dat, 2, -2))
         end
         dat = file:read()
         if dat then
          dat = All_Trim(dat)
        else
          return true
         end
         Cabing = Cabing - 1
       end
       end
      file:close()
    end
    return true
  end -- function end</nowiki>
----
===INI_AddNewProject===
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Appends a New Project to CabinetProjectQuestion.ini
  <nowiki>function INI_AddNewProject(xPath, xGroup)
    local filename = xPath .. "/ProjectList.ini"
    local file = io.open(filename, "a")
    if file then
      file:write("[" .. All_Trim(xGroup) .. "] \n")
      file:write("load_date = " .. StartDate(true) .. " \n")
      file:write("#====================================== \n")
      file:close()-- closes the open file
     end
     end
    -- Setup Fingers and Gaps
    Table.NoFingers0 = 1 + (Rounder(BoxJoint.MaterialLength / BoxJoint.MaterialThickness, 0))
    Table.NoFingers2 = Rounder(BoxJoint.NoFingers0 / 2, 0)
    Table.FingerSize = BoxJoint.MaterialLength /  BoxJoint.NoFingers0
    Table.NoFingers1 = BoxJoint.NoFingers0 - BoxJoint.NoFingers2
     return true
     return true
   end -- function end
   end -- function end</nowiki>
-- =====================================================]]
----
function GetMaterialSettings(Table)
 
  local MaterialBlock = MaterialBlock()
===INI_StdHeaderReader===
  Table.MaterialBlockThickness = MaterialBlock.Thickness
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  Table.xy_origin = MaterialBlock.XYOrigin
Gets the INI Header values of a ini file and uploads to "IniFile" Array
  if MaterialBlock.InMM then
 
    Table.Units  = "Drawing Units: mm"
  <nowiki>function INI_StdHeaderReader(xPath, Fname)
     Table.Unit = true
    local filename = xPath .. "\\" .. Fname .. ".ini"
    Table.Cal = 25.4
     local file = io.open(filename, "r")
  else
     if file then
    Table.Units  = "Drawing Units: inches"
      local WallMilling = (LengthOfFile(filename) - 1)
     Table.Unit = false
      local dat = All_Trim(file:read())
    Table.Cal = 1.0
      while (WallMilling >= 0) do
  end
        if "[" == string.sub(dat, 1, 1) then
  --local units
          table.insert (IniFile, string.sub(dat, 2, -2))
if MaterialBlock.Width > MaterialBlock.Height then
        end -- if end
    Table.Orantation = "H" -- Horizontal
        dat = file:read()
elseif MaterialBlock.Width < MaterialBlock.Height then
        if dat then
    Table.Orantation = "V"  -- Vertical
          dat = All_Trim(dat)
  else
        else
    Table.Orantation = "S" -- Squair
          return true
end
        end -- if end
  if Table.xy_origin == MaterialBlock.BLC then
        WallMilling = WallMilling - 1
    Table.XYorigin = "Bottom Left Corner"
      end -- while end
  elseif Table.xy_origin == MaterialBlock.BRC then
      file:close()
    Table.XYorigin = "Bottom Right Corner"
    end
  elseif Table.xy_origin == MaterialBlock.TRC then
    return true
    Table.XYorigin = "Top Right Corner"
  end -- function end</nowiki>
  else
----
    Table.XYorigin = "Top Left Corner"
 
  end -- if end
===INI_ReadProjectinfo===
  Table.UnitDisplay  = "Note: Units: (" .. Table.Units ..")"
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
  return true
Reads an ini files group and sets the table.names
end -- end function
 
-- =====================================================]]
  <nowiki>function INI_ReadProjectinfo(Table, xPath, xGroup, xFile)
function IsSingleSided(Table)
     Table.ProjectContactEmail      = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactEmail", "S")
     local SingleSided = Table.job.IsSingleSided
     Table.ProjectContactName        = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactName", "S")
     if not SingleSided then
     Table.ProjectContactPhoneNumber = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactPhoneNumber", "S")
      DisplayMessageBox("Error: Job must be a single sided job")
    Table.ProjectName              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectName", "S")
      return false
     Table.ProjectPath              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectPath", "S")
     end  -- if end
     Table.StartDate                = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.StartDate", "S")
  end --IsSingleSided function end
-- =====================================================]]
function IsDoubleSided(Table)
  if not Table.job.IsDoubleSided then
     DisplayMessageBox("Error: Job must be a Double Sided Project")
     return false
  else
     return true
     return true
   end -- if end
   end -- function end</nowiki>
end-- IsDoubleSided function
----
-- =====================================================]]
 
function ShowSetting(Table)
===INI_UpdateItem===
  local name = ""
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
      DisplayMessageBox(
Deletes old ini (.bak) file
    name .. " MaterialThickness = " .. tostring(Table.MaterialThickness) .."\n" ..
 
    name .. " BottleRad        = " .. tostring(Table.BottleRad)         .."\n" ..
Copys the .ini to a backup (.bak) new file
     name .. " SideLenght        = " .. tostring(Table.SideLenght)        .."\n" ..
 
    name .. " SideHight        = " .. tostring(Table.SideHight)        .."\n" ..
Reads the new backup file and writes a new file to the xGroup
     name .. " EndLenght        = " .. tostring(Table.EndLenght)        .."\n" ..
 
    name .. " EndHight          = " .. tostring(Table.EndHight)          .."\n" ..
Writes new xValue for the for the xItem
     name .. " TopLenght        = " .. tostring(Table.TopLenght)         .."\n" ..
 
     name .. " TopWidht          = " .. tostring(Table.TopWidht)         .."\n" ..
Reads and writes a new file to end of file
    name .. " HandleLenght      = " .. tostring(Table.HandleLenght)     .."\n" ..
 
    name .. " HandleWidht       = " .. tostring(Table.HandleWidht)      .."\n" ..
  <nowiki>function INI_UpdateItem(xPath, xFile, xGroup, xItem, xValue)
    name .. " HandleRad         = " .. tostring(Table.HandleRad)         .."\n" ..
     local NfileName = xPath .. "\\" .. xFile .. ".ini"
    name .. " MillingBitRad    = " .. tostring(Table.MillingBitRad)    .."\n" ..
     local OfileName = xPath .. "\\" .. xFile .. ".bak"
    "\n")
     os.remove(OfileName)
end -- ShowSettings function end
     if CopyFileFromTo(NfileName, OfileName) then-- makes backup file
-- =====================================================]]
      local fileR = io.open(OfileName)
function MakeLayers()
       local fileW = io.open(NfileName,  "w")
  local Red, Green, Blue = 0, 0, 0
       if fileR and fileW then
  local function GetColor(str) -- returns color value for a Color Name
         local groups = false
    local sx = str
         local txt = ""
    local Red = 0
        for Line in fileR:lines() do
    local Green = 0
          txt = Line
    local Blue = 0
          if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then -- Group
    local Colors = {}
            groups = true
    Colors.Black = "0,0,0"
          end -- if end
    Colors.Red = "255,0,0"
          if xItem == string.sub(Line, 1, string.len(xItem)) then  -- Item
    Colors.Blue = "0,0,255"
            if groups then
    Colors.Yellow = "255,255,0"
              txt = xItem .. " = " .. xValue
    Colors.Cyan = "0,255,255"
              groups = false
    Colors.Magenta = "255,0,255"
            end -- if end
    Colors.Green = "0,128,0"
          end -- if end
    if "" == str then
           fileW:write(txt .. "\n")
      DisplayMessageBox("Error: Empty string passed")
           txt = ""
    else
         end -- for end
      str = Colors[str]
         os.remove(OfileName)
      if "string" == type(str) then
         fileR:close()
        if string.find(str, ",") then
         fileW:close()
          Red  = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          str  = string.sub(str, assert(string.find(str, ",") + 1))
           Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
           Blue  = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
         end
      else
         DisplayMessageBox("Error: Color " .. sx .. " not Found" )
         Red = 0
         Green = 0
        Blue = 0
       end
       end
     end
     end
     return Red, Green, Blue
     return true
  end
   end -- function end</nowiki>
  local layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackPocket)
----
        Red, Green, Blue = GetColor(Milling.LNBackPocketColor)
        layer:SetColor (Red, Green, Blue)
        layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackProfile)
        Red, Green, Blue = GetColor(Milling.LNBackProfileColor)
        layer:SetColor (Red, Green, Blue)
  return true
end -- function end
  -- =====================================================]]
function MyLayerClear(LayerName)
   local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
    if Mylayer.IsEmpty then
        Milling.job.LayerManager:RemoveLayer(Mylayer)
    end -- if end
  return true
end -- function end
-- =====================================================]]
function LayerClear()                                  --  calling MyLayerClear
  MyLayerClear(Milling.LNBackPocket  .. "-Wall")
  MyLayerClear(Milling.LNBackPocket  .. "-Base")
  MyLayerClear(Milling.LNBackProfile .. "-Wall")
  MyLayerClear(Milling.LNBackProfile .. "-Base")
  MyLayerClear("PartLabels")
  return true
end -- function end
-- =====================================================]]


-- =====================================================]]
===INI_ReadProject===
end -- Job Tools end
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Reads the ini file for project data


</nowiki>
  <nowiki>function INI_ReadProject(xPath, xFile, xGroup)
  -- Milling = {}
    Milling.LayerNameBackPocket          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameBackPocket", "S")
    Milling.LayerNameTopBottomCenterDado = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameTopBottomCenterDado", "S")
    Milling.LayerNameDrawNotes          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawNotes", "S")
    Milling.LayerNameDrawFaceFrame      = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawFaceFrame", "S")
    Milling.BackPocketDepthWall          = GetIniValue(xPath, xFile, xGroup, "Milling.BackPocketDepthWall", "N")
    Milling.BlindDadoSetbackWall        = GetIniValue(xPath, xFile, xGroup, "Milling.BlindDadoSetbackWall", "N")
    Milling.CabDepthWall                = GetIniValue(xPath, xFile, xGroup, "Milling.CabDepthWall", "N")
    return true
  end -- function end</nowiki>
----


==Logic and Test Tools==
===INI_TestDeleteDups===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|30px|link=JimAndi Toolbox]]
Reads the ini file for dups and deletes


<nowiki>  
  <nowiki>function INI_TestDeleteDups()
    --[[ Requires 3 global variables
-- =====================================================]]
    clean = {}
╔═╗╔═╗╦╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
     dups   = {}
║  ║ ║║ ╦║║     ║ ║ ║║ ║║  ╚═╗
    Names  = {}
╩═╝╚═╝╚═╝╩╚═╝   ╩ ╚═╝╚═╝╩═╝╚═╝
    ]]
function LogicTools()
    local myPath = "C:\\Users\\CNC\\Documents\\test"
-- =====================================================]]
     local myName = "Tester"
function DialogStringChecks()
     local myfile = "C:\\Users\\CNC\\Documents\\test\\Tester.ini"
  local MyTrue = false
     INI_ReadGroups(myfile, Names)
  if Milling.LNBottomProfile == "" then
     FindDups(Names, dups, clean)
    MessageBox("Error: Bottom Profile layer name cannot be blank")
     for i,v in ipairs(dups) do
     OnLuaButton_InquiryLayers()
      INI_DeleteGroup(myPath, myName, v)
  elseif  Milling.LNSideProfile  == "" then
     end
     MessageBox("Error: Side Profile layer name cannot be blank")
     return true
    OnLuaButton_InquiryLayers()
  end -- function end</nowiki>
  elseif  Milling.LNSidePocket  == "" then
 
     MessageBox("Error: Side Pocket layer name cannot be blank")
==Data Import Tools==
     OnLuaButton_InquiryLayers()
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
  elseif Milling.LNFrontProfile == "" then
This object is used to import data to a gadget.
     MessageBox("Error: Front Profile layer name cannot be blank")
 
    OnLuaButton_InquiryLayers()
===Read_CSV===
  elseif Milling.LNFrontPocket  == "" then
Reads a CSV file based on header and format (Requires modifications per usage)
     MessageBox("Error: Front Pocket layer name cannot be blank")
<nowiki> function Read_CSV(xFile, Header)
     OnLuaButton_InquiryLayers()
   --Read_CSV(Door.CSVFile, true)
  elseif Milling.LNBackProfile == "" then
  local fileR = io.open(xFile)
    MessageBox("Error: Back Profile layer name cannot be blank")
   local xLine = ""
    OnLuaButton_InquiryLayers()
   local result = {}
  elseif Milling.LNBackPocket == "" then
   if fileR then
    MessageBox("Error: Back Pocket layer name cannot be blank")
     for Line in fileR:lines() do
    OnLuaButton_InquiryLayers()
      xLine = Line
  elseif Milling.LNDrawNotes == "" then
      if Header then
    MessageBox("Error: Draw Notes layer name cannot be blank")
        Header = false
    OnLuaButton_InquiryLayers()
      else
   elseif Milling.LNPartLabels == "" then
        xLine = All_Trim(Line)
    MessageBox("Error: Part Lables layer name cannot be blank")
        for match in (xLine..","):gmatch("(.-)"..",") do
    OnLuaButton_InquiryLayers()
          table.insert(result, match)
   elseif Milling.LNBlume == "" then
        end -- for end
    MessageBox("Error: Blume layer name cannot be blank")
        Door.Count    = tonumber(result[1])
    OnLuaButton_InquiryLayers()
        Door.Height   = tonumber(result[2])
   elseif Project.ProjectName == "" then
        Door.Width     = tonumber(result[3])
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
   elseif Project.ContactEmail  == "" then
     MessageBox("Error: Contact Email cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactName == "" then
    MessageBox("Error: Contact Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactPhoneNumber == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.DrawerID == "" then
    MessageBox("Error: Contact Phone Number cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ProjectPath == "" then
    MessageBox("Error: Project Path cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  else
    MyTrue = true
  end -- if end
  return MyTrue
end -- function end
-- =====================================================]]
function CheckNumber(num)
  if type(num) == "number" then
    return true
  else
   return false
  end -- if end
end -- function end
-- =====================================================]]
function AboveZero(num)
  if (type(num) == "number") and (num > 0.0)then
     return true
  else
  return false
  end -- if end
end -- function end
-- =====================================================]]
end -- LogicTools function end


</nowiki>
        result = {}
        while Door.Count > 0 do
          if      Door.Style == StyleA.Name then
            DoorStyleA()
          elseif  Door.Style == StyleB.Name then
            DoorStyleB()
          elseif  Door.Style == StyleC.Name then
            DoorStyleC()
          elseif  Door.Style == StyleE.Name then
            DoorStyleE()
          elseif  Door.Style == StyleF.Name then
            DoorStyleF()
          elseif  Door.Style == StyleG.Name then
            DoorStyleG()
          else
            DisplayMessageBox("No Style Select!")
          end --if end
          Door.Count =  Door.Count - 1
        end -- for end
      end --if end
      Door.Record = Door.Record + 1
      MyProgressBar:SetPercentProgress(ProgressAmount(Door.Record))
    end --for end
  end --if end
  return true
end -- function end </nowiki>
----


==File Logging Tools==
==Job Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


  <nowiki>  
  <nowiki>function ValidJob()
   -- A better error message
-- =====================================================]]
     local job = VectricJob()
╦  ╔═╗╔═╗╔═╗╦╔╗╔╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
     if not job.Exists then
║  ║ ║║ ╦║ ╦║║║║║ ╦  ║ ║ ║║ ║║  ╚═╗
       DisplayMessageBox("Error: Cannot run Gadget, no drawing found \n" ..
╩═╝╚═╝╚═╝╚═╝╩╝╚╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
                        "Please create a new file (drawing) and \n" ..
function LoggingTools()
                        "specify the material dimensions \n"
-- =====================================================]]
       )
  function LogWriter(xPath, xFile, xText)
      return false
   -- Writes new xText Line to a log file
     else
    local LogName = xPath .. "\\" .. xFile .. ".txt"
      return true
     local fileW = io.open(LogName,  "a")
    end -- if end
     if fileW then
  end -- ValidJob end
       fileW:write(xText .. "\n")
      fileW:close()
    end
    return true
  end -- function end
  -- =====================================================]]
  function LogWriter(LogName, xText)
  -- Adds a new xText Line to a app log file
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
    local fileW = io.open(LogName,  "a")
    if fileW then
      fileW:write(xText .. "\n")
       fileW:close()
    end -- if end
     Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
    return true
  end -- function end
-- =====================================================]]
end -- Logging Tools Function End
 
</nowiki>
</nowiki>


==Math Tools==
----
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


<nowiki>
===MoveSetectedVectors===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- =====================================================]]
  <nowiki>function MoveSetectedVectors(job, NewBasePoint)
╔╦╗╔═╗╔╦╗╦ ╦ ╔╦╗╔═╗╔═╗╦  ╔═╗
    local Selection = job.Selection
║║║╠═╣ ║ ╠═╣  ║ ║ ║║ ║║  ╚═╗
    if Selection.IsEmpty then
╩ ╩╩ ╩ ╩ ╩ ╩  ╩ ╚═╝╚═╝╩═╝╚═╝
      MessageBox("LayoutImportedVectors: No vectors selected!")
function MathTools()
      return false
-- =====================================================]]
    end
function ArcSegment (p1, p2, Rad)                       -- Returns the Arc Segment
    local MySelection = Selection:GetBoundingBox();
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
    if not NewBasePoint then
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
      NewBasePoint = Point2D(0,0)
  return segment
    end
end -- function end
    local MyNewLocatioin = BasePoint - MySelection.BLC
-- =====================================================]]
    local Txform = TranslationMatrix2D(MyNewLocatioin)
function D(x)                                          -- Returns double the value
    Selection:Transform(Txform)
  return x * 2.0
    return true
end -- function end
  end </nowiki>
-- =====================================================]]
----
function H(x)                                           -- Returns half the value
 
  return x * 0.5
===FixPath===
end -- function end
  <nowiki>function FixPath(path)                               -- Lua Returns a fixed path
-- =====================================================]]
    return path:gsub("%\\", "/")
function C(x)                                          -- Returns scale value
   end -- function end
  return x * Project.Cal
 
end -- function end
----
-- =====================================================]]
 
function ChordSag2Radius (Chr, Seg)                     -- Returns the Rad from Chord and Seg
  function FixPath(myPath) {                            -- JavaScript Tool Returns a fixed path
  local rad = ((((Chr * Chr)/(Seg * 4)) + Seg) / 2.0)
    /* myPath  = "C:\\User\\Bob\\Home\\Drawings"; */
   return rad
    /* NewPath = "C:/User/Bob/Home/Drawings"; */
end -- function end
    var NewPath = "";
-- =====================================================]]
    var myLetter = "";
function RadSag2Chord(Rad, Seg)                         -- Returns the Chord from Rad and Seg
    var CheckPathLen = myPath.length;
  local Ang = 2 * math.acos(1 - (Seg/Rad))
    for (let i = 0; i < myPath.length; i++) {
  local Chord = (2 * Rad) * math.sin(Ang * 0.5)
      myLetter = myPath.charAt(i)
  return Chord
      if myLetter.charCodeAt(0) == 92 {
end -- function end
        NewPath = NewPath + "/";
-- =====================================================]]
      } else {
function RadChord2Segment (Rad, Chord)      -- Returns the Arc Segment from Rad and Chord
        NewPath = NewPath + myLetter;
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - Chord^2))))
      }
  return segment
     }
end -- function end
     return NewPath;
-- =====================================================]]
  }</nowiki>
function RoundTo(Num, Per)                  -- Returns the number from
 
  local Head = Num < 0 and math.ceil(Num) or math.floor(Num)
----
  local Tail = Num - Head
 
  local Value = Head + tonumber(string.sub(tostring(Tail), 1, Per + 2))
===RotateSetectedVectors===
  return Value
 
end -- function end
   <nowiki>function RotateSetectedVectors(job, NewBasePoint, NewAngle)
-- =====================================================]]
    local Selection = job.Selection
function Round(x)
     if not NewBasePoint then
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
       NewBasePoint = Point2D(0,0)
end
     end -- if end
-- =====================================================]]
     if not NewAngle then
function DecimalPlaces(Dnum, Plac)
       NewAngle = 0.0
  return tonumber(string.sub(tostring(Dnum)  .. "000000000000000000000000000000000000",1, string.len(tostring(math.floor(Dnum))) + 1 + Plac))
     end -- if end
end
     if Selection.IsEmpty then
-- =====================================================]]
       MessageBox("Error: Rotation function: No vectors selected!")
function tointeger( x )
       return false
     local num = tonumber( x )
    end -- if end
     return num < 0 and math.ceil( num ) or math.floor( num )
     local MySelection = Selection:GetBoundingBox();
end
    local MyNewLocatioin = BasePoint - MySelection.BLC
-- =====================================================]]
    local Txform = RotationMatrix2D(NewBasePoint, NewAngle)
-- ===TrigIt===
    Selection:Transform(Txform)
-- Finds all 5 properties of a triangle
     return true
   function TrigIt(A, B, AB, AC, BC)
  end </nowiki>
-- Sub Function to help other functions
 
-- Call = A, B, AB, AC, BC = Trig(A, B, AB, AC, BC)
----
-- C is the corner, A = small ang and B is the big angle
 
-- returns all values
===GetUnits===
-- A, B = angles
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- C = 90.0 Deg
<nowiki>function GetUnits(UTable)                               -- returns Drawing Units data
-- B to C (BC) is Run - Base - adjacent
     local mtl_block = MaterialBlock()
-- A to C (AC) is Rise - Height - opposite
     if mtl_block.InMM then
-- A to B (AB) is Slope - hypotenuse
       UTable.Units  = "Drawing Units: mm"
     if (B > 0.0) and (A == 0.0) then
       UTable.Unit = true
       A = math.deg(math.rad(90) - math.rad(B))
      UTable.UnitCheck = {"metric", "kilometer", "kilometers", "kh", "meter", "meters", "m", "decimeter", "decimeters", "dm", "centimeter", "centimeters", "cm", "millimeter", "millimeters", "mm"}
     end
       UTable.Cal = 25.4
     if (A > 0.0) and (B == 0.0) then
       B = math.deg(math.rad(90) - math.rad(A))
     end
     if (AC > 0.0) and (BC > 0.0) then
       AB = math.sqrt((AC ^ 2) + (BC ^ 2))
       A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
     elseif (AB > 0.0) and (BC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (BC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
     elseif (AB > 0.0) and (AC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (AC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
     elseif (A > 0.0) and (AC > 0.0) then
      AB = AC / math.cos(math.rad(A))
      BC = AB * math.sin(math.rad(A))
     elseif (A > 0.0) and (BC > 0.0) then
       AB = BC / math.sin(math.rad(A))
       AC = AB * math.cos(math.rad(A))
    elseif (A > 0.0) and (AB > 0.0) then
       BC = AB * math.sin(math.rad(A))
      AC = AB * math.cos(math.rad(A))
     else
     else
       MessageBox("Error: No Missing Value")
       UTable.Units  = "Drawing Units: inches"
    end -- if end
      UTable.Unit = false
    return A, B, AB, AC, BC
      UTable.UnitCheck = {"imperial", "miles", "mile", "mi", "yards", "yard", "yd", "feet", "foot", "ft", "inches", "inch", "in", "fractions", "fraction"}
  end
       UTable.Cal = 1.0
-- =====================================================]]
  function Maximum (a)                                  -- Returns the Max number from an array
-- print(maximum({8,10,23,12,5}))    --> 23  3
    local mi = 1 -- maximum index
    local m = a[mi]  -- maximum value
    for i,val in ipairs(a)  do
       if val > m then
        mi = i
        m = val
      end -- if end
     end
     end
    return m, mi
  end  -- function end
-- =====================================================]]
  function IsEven(IsEven_Number)                        -- Returns True/False if number is even
    if (IsEven_Number % 2 == 0) then
      return true
    else
      return false
    end -- if end
  end -- function end
-- =====================================================]]
  function IsOdd(IsOdd_Number)                            -- Returns True/False if number is odd
    if(IsOdd_Number%2 == 0) then
      return false
    end -- end if
     return true
     return true
   end -- function end
   end -- end function</nowiki>
-- =====================================================]]
end -- Math Tools function End


</nowiki>
----


==Registry Read and Write Tools==
===CheckTheUnits===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function CheckTheUnits(UTable, Value)                    -- Checks if the unit of messure in of drawing units
  local goodtogo = false
  for i=1, #UTable.UnitCheck  do
    if string.upper(Value) == string.upper(UTable.UnitCheck[i]) then
      goodtogo = true
      break
    end -- if end
  end -- for end
  if goodtogo then
    return true
  else
    return false
  end -- if end
end -- function end</nowiki>
 
----


<nowiki>
===GetMatlBlk===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- =====================================================]]
<nowiki>function GetMatlBlk(Table)
╦═╗╔═╗╔═╗╦╔═╗╔╦╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
    local mtl_block = MaterialBlock()
╠╦╝║╣ ║ ╦║╚═╗ ║ ╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
    if mtl_block.InMM then
╩╚═╚═╝╚═╝╩╚═╝ ╩ ╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
      Table.Units = "Drawing Units: mm"
function RegistryTools()
      Table.Unit = true
-- =====================================================]]
    else
function DocVarChk(Name, Value)
      Table.Units = "Drawing Units: inches"
  local job = VectricJob()
      Table.Unit = false
  local document_variable_list = job.DocumentVariables
    end
  return document_variable_list:DocumentVariableExists(Name)
    if mtl_block.Width> mtl_block.Height then
end -- function end
      Table.MaterialThickness = mtl_block.Height
-- =====================================================]]
      Table.MaterialLength = mtl_block.Width
function DocVarGet(Name)
      Table.Orantation = "H"
  local job = VectricJob()
    else
  local document_variable_list = job.DocumentVariables
      Table.MaterialThickness = mtl_block.Width
  return document_variable_list:GetDocumentVariable(Name, 0.0)
      Table.MaterialLength = mtl_block.Height
end -- function end
      Table.Orantation = "V"
-- =====================================================]]
    end
function DocVarSet(Name, Value)
    Table.FrontThickness = Dovetail.MaterialThickness
  local job = VectricJob()
    Table.SideThickness = Dovetail.MaterialThickness
  local document_variable_list = job.DocumentVariables
    if mtl_block.Height == mtl_block.Width then
  return document_variable_list:SetDocumentVariable(Name, Value)
        MessageBox("Error! Material block cannot square")
end -- function end
    end
-- =====================================================]]
    return true
function RegistryReadMaterial()                -- Read from Registry Material values for LUA Bit
  end -- end function</nowiki>
  local RegistryRead              = Registry("Material")
  Milling.SafeZGap                = Rounder(RegistryRead:GetString("SafeZGap",              "0.500"), 4)
  Milling.StartZGap              = Rounder(RegistryRead:GetString("StartZGap",            "0.500"), 4)
  Milling.HomeX                  = Rounder(RegistryRead:GetString("HomeX",                "0.000"), 4)
  Milling.HomeY                  = Rounder(RegistryRead:GetString("HomeY",                "0.000"), 4)
  Milling.HomeZGap                = Rounder(RegistryRead:GetString("HomeZGap",              "0.750"), 4)
  return true
end -- function end
-- =====================================================]]
function RegistryLastTenFiles(FileName)        -- Adds to the top ten Log file list
  local Registry = Registry(RegName)
  LogFile.File10 = Registry:GetString("LogFile.File09", "No Log Yet" )
  LogFile.File09 = Registry:GetString("LogFile.File08", "No Log Yet" )
  LogFile.File08 = Registry:GetString("LogFile.File07", "No Log Yet" )
  LogFile.File07 = Registry:GetString("LogFile.File06", "No Log Yet" )
  LogFile.File06 = Registry:GetString("LogFile.File05", "No Log Yet" )
  LogFile.File05 = Registry:GetString("LogFile.File04", "No Log Yet" )
  LogFile.File04 = Registry:GetString("LogFile.File03", "No Log Yet" )
  LogFile.File03 = Registry:GetString("LogFile.File02", "No Log Yet" )
  LogFile.File02 = Registry:GetString("LogFile.File01", "No Log Yet" )
  LogFile.File01 = FileName
  return FileName
end -- function end
-- =====================================================]]
function RegistryRead()                        -- Read from Registry values
  local RegistryRead = Registry("RegName")
  local Yes_No      = RegistryRead:GetBool("BaseDim.Yes_No", ture)
  local CabHeight    = RegistryRead:GetDouble("BaseDim.CabHeight", 35.500)
  local CabCount    = RegistryRead:GetInt("BaseDim.CabCount", 36)
  local Name        = RegistryRead:GetString("BaseDim.Name", "Words")


  Milling.MillTool1.FeedRate                = RegistryRead:GetDouble("Milling.MillTool1.FeedRate",              30.000)
----
  Milling.MillTool1.InMM                    = RegistryRead:GetBool("Milling.MillTool1.InMM ",                  false)
  Milling.MillTool1.Name                    = RegistryRead:GetString("Milling.MillTool1.Name",                  "No Tool Selected")
  Milling.MillTool1.BitType                = RegistryRead:GetString("Milling.MillTool1.BitType",              "END_MILL") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool1.RateUnits              = RegistryRead:GetInt("Milling.MillTool1.RateUnits",                4)
  Milling.MillTool1.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool1.SpindleSpeed",            20000)
  Milling.MillTool1.ToolNumber              = RegistryRead:GetInt("Milling.MillTool1.ToolNumber",              1)
  Milling.MillTool1.Stepdown                = RegistryRead:GetDouble("Milling.MillTool1.Stepdown",              0.2000)
  Milling.MillTool1.Stepover                = RegistryRead:GetDouble("Milling.MillTool1.Stepover",              0.0825)
  Milling.MillTool1.ToolDia                = RegistryRead:GetDouble("Milling.MillTool1.ToolDia",              0.1250)
  Milling.MillTool1.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool1.PlungeRate",            15.000)


  Milling.MillTool2.FeedRate                = RegistryRead:GetDouble("Milling.MillTool2.FeedRate",              30.000)
===GetBoxJointMaterialSettings===
  Milling.MillTool2.InMM                    = RegistryRead:GetBool("Milling.MillTool2.InMM ",                  false)
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  Milling.MillTool2.Name                    = RegistryRead:GetString("Milling.MillTool2.Name",                  "No Tool Selected")
<nowiki>function GetBoxJointMaterialSettings(Table)
  Milling.MillTool2.BitType                = RegistryRead:GetString("Milling.MillTool2.BitType",              "BALL_NOSE") -- BALL_NOSE, END_MILL, VBIT
    local mtl_block = MaterialBlock()
  Milling.MillTool2.RateUnits              = RegistryRead:GetInt("Milling.MillTool2.RateUnits",                4)
    --local units
  Milling.MillTool2.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool2.SpindleSpeed",            20000)
    if mtl_block.InMM then
  Milling.MillTool2.ToolNumber              = RegistryRead:GetInt("Milling.MillTool2.ToolNumber",              2)
      Table.Units = "Drawing Units: mm"
  Milling.MillTool2.Stepdown                = RegistryRead:GetDouble("Milling.MillTool2.Stepdown",              0.2000)
      Table.Unit = true
  Milling.MillTool2.Stepover                = RegistryRead:GetDouble("Milling.MillTool2.Stepover",              0.0825)
    else
  Milling.MillTool2.ToolDia                = RegistryRead:GetDouble("Milling.MillTool2.ToolDia",              0.1250)
      Table.Units = "Drawing Units: inches"
  Milling.MillTool2.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool2.PlungeRate",            15.000)
      Table.Unit = false
 
    end
  Milling.MillTool3.FeedRate                = RegistryRead:GetDouble("Milling.MillTool3.FeedRate",              30.000)
    if mtl_block.Width > mtl_block.Height then
  Milling.MillTool3.InMM                    = RegistryRead:GetBool("Milling.MillTool3.InMM",                    false)
      Table.MaterialThickness = mtl_block.Height
  Milling.MillTool3.Name                    = RegistryRead:GetString("Milling.MillTool3.Name",                  "No Tool Selected")
      Table.MaterialLength = mtl_block.Width
  Milling.MillTool3.BitType                = RegistryRead:GetString("Milling.MillTool3.BitType",              "END_MILL")  -- BALL_NOSE, END_MILL, VBIT
      Table.Orantation = "H"
  Milling.MillTool3.RateUnits              = RegistryRead:GetInt("Milling.MillTool3.RateUnits",                4)
    else
  Milling.MillTool3.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool3.SpindleSpeed",            20000)
      Table.MaterialThickness = mtl_block.Width
  Milling.MillTool3.ToolNumber              = RegistryRead:GetInt("Milling.MillTool3.ToolNumber",              3)
      Table.MaterialLength = mtl_block.Height
  Milling.MillTool3.Stepdown                = RegistryRead:GetDouble("Milling.MillTool3.Stepdown",              0.2000)
      Table.Orantation = "V"
  Milling.MillTool3.Stepover                = RegistryRead:GetDouble("Milling.MillTool3.Stepover",              0.0825)
    end
  Milling.MillTool3.ToolDia                = RegistryRead:GetDouble("Milling.MillTool3.ToolDia",              0.1250)
    if mtl_block.Height == mtl_block.Width then
  Milling.MillTool3.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool3.PlungeRate",            15.000)
      MessageBox("Error! Material block cannot square")
 
    end
  Milling.MillTool4.FeedRate                = RegistryRead:GetDouble("Milling.MillTool4.FeedRate",              30.000)
    -- Display material XY origin
  Milling.MillTool4.InMM                    = RegistryRead:GetBool("Milling.MillTool4.InMM ",                  false)
    local xy_origin_text = "invalid"
  Milling.MillTool4.Name                    = RegistryRead:GetString("Milling.MillTool4.Name",                  "No Tool Selected")
    local xy_origin = mtl_block.XYOrigin
  Milling.MillTool4.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool4.PlungeRate",            15.000)
    if  xy_origin == MaterialBlock.BLC then
  Milling.MillTool4.RateUnits              = RegistryRead:GetInt("Milling.MillTool4.RateUnits",                4)
        Table.xy_origin_text = "Bottom Left Corner"
  Milling.MillTool4.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool4.SpindleSpeed",            20000)
      if Table.Orantation == "V" then
  Milling.MillTool4.Stepdown                = RegistryRead:GetDouble("Milling.MillTool4.Stepdown",              0.2000)
        Table.Direction1 = 90.0
  Milling.MillTool4.Stepover                = RegistryRead:GetDouble("Milling.MillTool4.Stepover",              0.0825)
        Table.Direction2 = 0.0
  Milling.MillTool4.ToolDia                = RegistryRead:GetDouble("Milling.MillTool4.ToolDia",              0.1250)
        Table.Direction3 = 270.0
  Milling.MillTool4.ToolNumber              = RegistryRead:GetInt("Milling.MillTool4.ToolNumber",              5)
        Table.Direction4 = 180.0
 
        Table.Bulge = 1.0
  Milling.MillTool5.FeedRate                = RegistryRead:GetDouble("Milling.MillTool5.FeedRate",              30.000)
      else
  Milling.MillTool5.InMM                    = RegistryRead:GetBool("Milling.MillTool5.InMM ",                  false)
        Table.Direction1 = 0.0
  Milling.MillTool5.Name                    = RegistryRead:GetString("Milling.MillTool5.Name",                  "No Tool Selected")
        Table.Direction2 = 90.0
  Milling.MillTool5.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool5.PlungeRate",            15.000)
        Table.Direction3 = 180.0
  Milling.MillTool5.RateUnits              = RegistryRead:GetInt("Milling.MillTool5.RateUnits",                4)
        Table.Direction4 = 270.0
  Milling.MillTool5.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool5.SpindleSpeed",            20000)
        Table.Bulge = -1.0
  Milling.MillTool5.Stepdown                = RegistryRead:GetDouble("Milling.MillTool5.Stepdown",              0.2000)
      end
  Milling.MillTool5.Stepover                = RegistryRead:GetDouble("Milling.MillTool5.Stepover",              0.0825)
    elseif xy_origin == MaterialBlock.BRC then
  Milling.MillTool5.ToolDia                = RegistryRead:GetDouble("Milling.MillTool5.ToolDia",              0.1250)
      Table.xy_origin_text = "Bottom Right Corner"
  Milling.MillTool5.ToolNumber              = RegistryRead:GetInt("Milling.MillTool5.ToolNumber",              6)
      if Table.Orantation == "V" then
  return true
        Table.Direction1 = 90.0
end -- function end
        Table.Direction2 = 180.0
-- =====================================================]]
        Table.Direction3 = 270.0
function RegistryWrite()                      -- Write to Registry values
        Table.Direction4 = 0.0
  local RegistryWrite = Registry("RegName")
        Table.Bulge = -1.0
  local RegValue
      else
  RegValue = RegistryWrite:SetBool("ProjectQuestion.CabinetName", true)
        Table.Direction1 = 180.0
  RegValue = RegistryWrite:SetDouble("BaseDim.CabDepth", 23.0000)
        Table.Direction2 = 90.0
  RegValue = RegistryWrite:SetInt("BaseDim.CabHeight", 35)
        Table.Direction3 = 0.0
  RegValue = RegistryWrite:SetString("BaseDim.CabLength", "Words")
        Table.Direction4 = 270.0
 
        Table.Bulge = 1.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.FeedRate" ,    Milling.MillTool1.FeedRate)
      end
  RegValue = RegistryWrite:SetBool("Milling.MillTool1.InMM",            Milling.MillTool1.InMM)
    elseif xy_origin == MaterialBlock.TRC then
  RegValue = RegistryWrite:SetString("Milling.MillTool1.Name",          Milling.MillTool1.Name)
      Table.xy_origin_text = "Top Right Corner"
  RegValue = RegistryWrite:SetString("Milling.MillTool1.BitType",       Milling.MillTool1.BitType)
      if Table.Orantation == "V" then
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.PlungeRate" ,  Milling.MillTool1.PlungeRate)
        Table.Direction1 = 270.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.RateUnits",        Milling.MillTool1.RateUnits)
        Table.Direction2 = 180.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.SpindleSpeed",    Milling.MillTool1.SpindleSpeed)
        Table.Direction3 = 90.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepdown" ,    Milling.MillTool1.Stepdown)
        Table.Direction4 = 0.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepover" ,    Milling.MillTool1.Stepover)
        Table.Bulge = 1.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.ToolDia" ,      Milling.MillTool1.ToolDia)
      else
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.ToolNumber",       Milling.MillTool1.ToolNumber)
        Table.Direction1 = 180.0
 
        Table.Direction2 = 270.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.FeedRate" ,    Milling.MillTool2.FeedRate)
        Table.Direction3 = 0.0
  RegValue = RegistryWrite:SetBool("Milling.MillTool2.InMM",            Milling.MillTool2.InMM)
        Table.Direction4 = 90.0
  RegValue = RegistryWrite:SetString("Milling.MillTool2.Name",          Milling.MillTool2.Name)
        Table.Bulge = -1.0
  RegValue = RegistryWrite:SetString("Milling.MillTool2.BitType",       Milling.MillTool2.BitType)
      end
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.PlungeRate" ,  Milling.MillTool2.PlungeRate)
    elseif xy_origin == MaterialBlock.TLC then
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.RateUnits",        Milling.MillTool2.RateUnits)
      Table.xy_origin_text = "Top Left Corner"
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.SpindleSpeed",     Milling.MillTool2.SpindleSpeed)
      if Table.Orantation == "V" then
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepdown" ,    Milling.MillTool2.Stepdown)
        Table.Direction1 = 270.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepover" ,    Milling.MillTool2.Stepover)
        Table.Direction2 = 0.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.ToolDia" ,      Milling.MillTool2.ToolDia)
        Table.Direction3 = 90.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.ToolNumber",       Milling.MillTool2.ToolNumber)
        Table.Direction4 = 180.0
 
        Table.Bulge = -1.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.FeedRate" ,    Milling.MillTool3.FeedRate)
      else
  RegValue = RegistryWrite:SetBool("Milling.MillTool3.InMM",            Milling.MillTool3.InMM)
        Table.Direction1 = 0.0
  RegValue = RegistryWrite:SetString("Milling.MillTool3.Name",          Milling.MillTool3.Name)
        Table.Direction2 = 270.0
  RegValue = RegistryWrite:SetString("Milling.MillTool3.BitType",       Milling.MillTool3.BitType)
        Table.Direction3 = 180.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.PlungeRate",   Milling.MillTool3.PlungeRate)
        Table.Direction4 = 90.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.RateUnits",       Milling.MillTool3.RateUnits)
        Table.Bulge = 1.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.SpindleSpeed",     Milling.MillTool3.SpindleSpeed)
       end
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepdown" ,     Milling.MillTool3.Stepdown)
    elseif xy_origin == MaterialBlock.CENTRE then  -- NOTE: English spelling for Centre!
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepover" ,     Milling.MillTool3.Stepover)
      Table.xy_origin_text = "Center"
   RegValue = RegistryWrite:SetDouble("Milling.MillTool3.ToolDia" ,      Milling.MillTool3.ToolDia)
      if Table.Orantation == "V" then
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.ToolNumber",      Milling.MillTool3.ToolNumber)
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = 1.0
       else
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = -1.0
       end
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
     else
        Table.xy_origin_text = "Unknown XY origin value!"
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
       if Table.Orantation == "V" then
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
      else
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
       end
    end
    -- Setup Fingers and Gaps
    Table.NoFingers0 = 1 + (Rounder(BoxJoint.MaterialLength / BoxJoint.MaterialThickness, 0))
    Table.NoFingers2 = Rounder(BoxJoint.NoFingers0 / 2, 0)
     Table.FingerSize = BoxJoint.MaterialLength /  BoxJoint.NoFingers0
     Table.NoFingers1 = BoxJoint.NoFingers0 - BoxJoint.NoFingers2
     return true
   end -- function end</nowiki>
 
----


  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.FeedRate" ,    Milling.MillTool4.FeedRate)
===GetMaterialSettings===
  RegValue = RegistryWrite:SetBool("Milling.MillTool4.InMM",            Milling.MillTool4.InMM)
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
   RegValue = RegistryWrite:SetString("Milling.MillTool4.Name",          Milling.MillTool4.Name)
<nowiki>function GetMaterialSettings(Table)
   RegValue = RegistryWrite:SetDouble("Milling.MillTool4.PlungeRate" ,   Milling.MillTool4.PlungeRate)
   local MaterialBlock = MaterialBlock()
   RegValue = RegistryWrite:SetInt("Milling.MillTool4.RateUnits",        Milling.MillTool4.RateUnits)
   Table.MaterialBlockThickness = MaterialBlock.Thickness
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.SpindleSpeed",     Milling.MillTool4.SpindleSpeed)
   Table.xy_origin = MaterialBlock.XYOrigin
   RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepdown" ,     Milling.MillTool4.Stepdown)
   if MaterialBlock.InMM then
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepover" ,     Milling.MillTool4.Stepover)
    Table.Units  = "Drawing Units: mm"
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.ToolDia" ,      Milling.MillTool4.ToolDia)
    Table.Unit = true
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.ToolNumber",      Milling.MillTool4.ToolNumber)
     Table.Cal = 25.4
   return true
   else
end -- function end
     Table.Units  = "Drawing Units: inches"
-- =====================================================]]
     Table.Unit = false
function REG_CheckRegistryBool()              -- Checks Registry for Bool values
    Table.Cal = 1.0
  local RegistryRead = Registry("RegName")
   end
  if RegistryRead:BoolExists("ProjectQuestion.Runtool") then
  --local units
     DisplayMessageBox("Alert: The Runtool value is saved.")
if MaterialBlock.Width > MaterialBlock.Height then
    Table.Orantation = "H" -- Horizontal
elseif MaterialBlock.Width < MaterialBlock.Height then
     Table.Orantation = "V" -- Vertical
   else
   else
     DisplayMessageBox("Alert: The Runtool value is not saved.")
     Table.Orantation = "S" -- Squair
  end -- if end
end
   return true
   if Table.xy_origin == MaterialBlock.BLC then
end -- function end
    Table.XYorigin = "Bottom Left Corner"
-- =====================================================]]
  elseif Table.xy_origin == MaterialBlock.BRC then
function REG_CheckRegistryDouble()            -- Checks Registry for Double values
    Table.XYorigin = "Bottom Right Corner"
  local RegistryRead = Registry("RegName")
   elseif Table.xy_origin == MaterialBlock.TRC then
   if RegistryRead:DoubleExists("ProjectQuestion.ProjectCost") then
     Table.XYorigin = "Top Right Corner"
     DisplayMessageBox("Alert: The project cost is saved.")
   else
   else
     DisplayMessageBox("Alert: The Project Cost is not saved.")
     Table.XYorigin = "Top Left Corner"
   end -- if end
   end -- if end
  Table.UnitDisplay  = "Note: Units: (" .. Table.Units ..")"
   return true
   return true
end -- function end
end -- end function</nowiki>
-- =====================================================]]
 
function REG_CheckRegistryInt()                -- Checks Registry for Int values
----
  local RegistryRead = Registry("RegName")
 
   if RegistryRead:IntExists("ProjectQuestion.ProjectCount") then
===IsSingleSided===
     DisplayMessageBox("Alert: The Project Count is saved.")
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function IsSingleSided(Table)
    local SingleSided = Table.job.IsSingleSided
    if not SingleSided then
      DisplayMessageBox("Error: Job must be a single sided job")
      return false
    end  -- if end
  end -- function end</nowiki>
 
----
 
===IsDoubleSided===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function IsDoubleSided(Table)
   if not Table.job.IsDoubleSided then
     DisplayMessageBox("Error: Job must be a Double Sided Project")
    return false
   else
   else
     DisplayMessageBox("Alert: The Project Count is not saved.")
     return true
   end -- if end
   end -- if end
  return true
end-- function end</nowiki>
end -- function end
 
-- =====================================================]]
----
function REG_CheckRegistryString()            -- Checks Registry for String values
  local RegistryRead = Registry("RegName")
  if RegistryRead:StringExists("ProjectQuestion.ProjectPath") then
    DisplayMessageBox("Alert: The Project path is saved.")
  else
    DisplayMessageBox("Alert: The Project path is not saved.")
  end
  return true
end -- function end
-- =====================================================]]
end -- Registry end


</nowiki>
===ShowSetting===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function ShowSetting(Table)
  local name = ""
      DisplayMessageBox(
    name .. " MaterialThickness = " .. tostring(Table.MaterialThickness) .."\n" ..
    name .. " BottleRad        = " .. tostring(Table.BottleRad)        .."\n" ..
    name .. " SideLenght        = " .. tostring(Table.SideLenght)        .."\n" ..
    name .. " SideHight        = " .. tostring(Table.SideHight)        .."\n" ..
    name .. " EndLenght        = " .. tostring(Table.EndLenght)        .."\n" ..
    name .. " EndHight          = " .. tostring(Table.EndHight)          .."\n" ..
    name .. " TopLenght        = " .. tostring(Table.TopLenght)        .."\n" ..
    name .. " TopWidht          = " .. tostring(Table.TopWidht)          .."\n" ..
    name .. " HandleLenght      = " .. tostring(Table.HandleLenght)      .."\n" ..
    name .. " HandleWidht      = " .. tostring(Table.HandleWidht)      .."\n" ..
    name .. " HandleRad        = " .. tostring(Table.HandleRad)        .."\n" ..
    name .. " MillingBitRad    = " .. tostring(Table.MillingBitRad)    .."\n" ..
    "\n")
end -- function end</nowiki>


==String Tools==
----
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


<nowiki>
===MakeLayers===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- =====================================================]]
  <nowiki>function MakeLayers()
╔═╗╔╦╗╦═╗╦╔╗╔╔═╗ ╔╦╗╔═╗╔═╗╦  ╔═╗
   local Red, Green, Blue = 0, 0, 0
╚═╗ ║ ╠╦╝║║║║║ ╦   ║ ║ ║║ ║║  ╚═╗
   local function GetColor(str) -- returns color value for a Color Name
╚═╝ ╩ ╩╚═╩╝╚╝╚═╝   ╩ ╚═╝╚═╝╩═╝╚═╝
    local sx = str
function StringTools()
    local Red = 0
-- =====================================================]]
    local Green = 0
function StringToArraySplit(s, delimiter)
    local Blue = 0
--[[
    local Colors = {}
split_string = StringToArraySplit("Hello World,Jim,Bill,Tom", ",")
    Colors.Black = "0,0,0"
Returns = array
    Colors.Red = "255,0,0"
-- split_string[1] = "Hello World,)
    Colors.Blue = "0,0,255"
-- split_string[2] = "Jim"
    Colors.Yellow = "255,255,0"
]]
    Colors.Cyan = "0,255,255"
  result = {};
    Colors.Magenta = "255,0,255"
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
    Colors.Green = "0,128,0"
       table.insert(result, match)
    if "" == str then
  end
       DisplayMessageBox("Error: Empty string passed")
  return result
    else
end
      str = Colors[str]
-- =====================================================]]
      if "string" == type(str) then
function WrapString(Str, Wid)                           -- wraps text at the nearest space and puts a return char in the space location
        if string.find(str, ",") then
  --[[  How to use:
           Red   = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
  Call WrapString(string, Number)
          str  = string.sub(str, assert(string.find(str, ",") + 1))
WrapString("Jim is a tall man that lives in Texas. He was raised in North East Texas on 1000 acres from 1970 to 1982. This is a man that knows numbers of great people from a round the world.", 40)
           Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
returns "Jim is a tall man that lives in Texas.\n
           Blue  = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
           He was raised in North East Texas on\n
          1000 acres from 1970 to 1982. This is a man\n
          that knows numbers of great people from\n
          a round the world."
]]
   local Wider = Wid
  local Posx = string.len(Str)
  local StrLen = string.len(Str)
  local pt = 0
  local function FindSpace(MyStr)
  local Pos = string.len(MyStr)
  local str = MyStr
    if string.find(MyStr, " ") ~= nil then
      while Pos>0 do
        Pos = Pos - 1
           if (string.byte(string.sub(str,-1)) == 32) then
            break
           else
            str = string.sub(str, 1, Pos)
          end
         end
         end
      else
        DisplayMessageBox("Error: Color " .. sx .. " not Found" )
        Red = 0
        Green = 0
        Blue = 0
      end
     end
     end
     return Pos
     return Red, Green, Blue
   end
   end
   if StrLen > Wider then
   local layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackPocket)
    while Wider < Posx do
        Red, Green, Blue = GetColor(Milling.LNBackPocketColor)
      pt = FindSpace(string.sub(Str,1, Wider))
        layer:SetColor (Red, Green, Blue)
      Str = string.sub(Str, 1, pt) .. "\n" .. string.sub(Str, pt +2)
        layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackProfile)
      Wider = Wider + Wid
        Red, Green, Blue = GetColor(Milling.LNBackProfileColor)
    end
        layer:SetColor (Red, Green, Blue)
   end
  return true
   return Str
end -- function end</nowiki>
 
----
 
===MyLayerClear===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function MyLayerClear(LayerName)
  local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
    if Mylayer.IsEmpty then
        Milling.job.LayerManager:RemoveLayer(Mylayer)
    end -- if end
  return true
end -- function end</nowiki>
 
----
 
===LayerClear===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function LayerClear()                      --  calling MyLayerClear
  MyLayerClear(Milling.LNBackPocket  .. "-Wall")
  MyLayerClear(Milling.LNBackPocket  .. "-Base")
  MyLayerClear(Milling.LNBackProfile .. "-Wall")
  MyLayerClear(Milling.LNBackProfile .. "-Base")
   MyLayerClear("PartLabels")
   return true
end -- function end
end -- function end
-- =====================================================]]
</nowiki>
function CleanString(inStr)                            -- Check for ascii letters below 127
 
  local outStr, str1 = ""
==Logic and Test Tools==
  local inStrLen = string.len(inStr)
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
  for i = 1, inStrLen ,1 do
These functions are named as per there function or action.
    str1 = string.sub(inStr, i, i)
 
    if string.byte(str1) <= 127 then
----
    outStr=outStr .. str1
 
    end
===CheckNumber===
  end
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  return outStr
<nowiki>function CheckNumber(num)
end -- function end
   if type(num) == "number" then
  -- =====================================================]]
     return true
function CheckString(YourStr)                         -- Check string for specal bite chars for HTML
  else
   local function FindLetter(TheStr, TestChar)
  return false
    local outStr = false
  end -- if end
    local strChar = ""
end -- function end</nowiki>
     local TheStrLen = string.len(TheStr)
 
    for i = 1, TheStrLen ,1 do
----
      strChar = string.sub(TheStr, i, i)
 
      if string.byte(strChar) == string.byte(TestChar) then
===AboveZero===
        outStr = true
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
        break
<nowiki>function AboveZero(num)
      end
   if (type(num) == "number") and (num > 0.0)then
    end
    return true
    return outStr
   else
  end -- function end
  return false
-- =====================================================]]
  end -- if end
  local StrTest = false
  StrTest = SwitchLetter(YourStr,  "&") -- Non frendly File Name letters
   StrTest = SwitchLetter(YourStr,  "#")
  StrTest = SwitchLetter(YourStr,  "@")
  StrTest = SwitchLetter(YourStr,  "^")
   StrTest = SwitchLetter(YourStr,  "$")
    return outStr
end -- function end
end -- function end
-- =====================================================]]
 
function MakeHTMLReady(MyStr)                          -- fixs string with specal bite chars for HTML
</nowiki>
   local function SwitchLetter(MyStr, MyChar, NewStr)
 
  local outStr, str1 = ""
----
  local inStrLen = string.len(MyStr)
 
  for i = 1, inStrLen ,1 do
 
    str1 = string.sub(MyStr, i, i)
===IsNumber()===
     if string.byte(str1) == string.byte(MyChar) then
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    outStr=outStr .. NewStr
<nowiki>function IsNumber(Val)                    --Return true if Val is number
    else
    if tonumber(x) ~= nil then
        outStr=outStr .. str1
      return true
    end
    end -- if end
  end
    return false
  return outStr
  end -- end function</nowiki>
end -- function end
 
-- =====================================================]]
----
   local outStr = ""
 
   outStr = SwitchLetter(MyStr, "!", "&#33;")
===IsEven()===
   outStr = SwitchLetter(outStr, "#", "&#35;")
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  outStr = SwitchLetter(outStr, "$", "&#36;")
<nowiki>function IsEven(IsEven_Number)            -- Returns True/False if number is even
  outStr = SwitchLetter(outStr, "%", "&#37;")
    if (IsEven_Number % 2 == 0) then
  outStr = SwitchLetter(outStr, "&", "&#38;")
      return true
  outStr = SwitchLetter(outStr, "'", "&#39;")
    else
  outStr = SwitchLetter(outStr, "(", "&#40;")
      return false
  outStr = SwitchLetter(outStr, ")", "&#41;")
    end -- if end
  outStr = SwitchLetter(outStr, "*", "&#42;")
   end -- function end</nowiki>
   outStr = SwitchLetter(outStr, "+", "&#43;")
 
   outStr = SwitchLetter(outStr, ",", "&#44;")
----
  outStr = SwitchLetter(outStr, "-", "&#45;")
 
  outStr = SwitchLetter(outStr, ".", "&#46;")
===IsOdd()===
  outStr = SwitchLetter(outStr, "/", "&#47;")
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  outStr = SwitchLetter(outStr, ":", "&#58;")
<nowiki>function IsOdd(IsOdd_Number)                         -- Returns True/False if number is odd
   outStr = SwitchLetter(outStr, ";", "&#59;")
    if(IsOdd_Number%2 == 0) then
  outStr = SwitchLetter(outStr, "<", "&#60;")
      return false
  outStr = SwitchLetter(outStr, "=", "&#61;")
     end -- end if
  outStr = SwitchLetter(outStr, ">", "&#62;")
    return true
  outStr = SwitchLetter(outStr, "?", "&#63;")
  end -- function end</nowiki>
  outStr = SwitchLetter(outStr, "@", "&#64;")
 
  outStr = SwitchLetter(outStr, "[", "&#91;")
----
   outStr = SwitchLetter(outStr, "]", "&#93;")
 
  outStr = SwitchLetter(outStr, "^", "&#94;")
===IsNegative()===
  outStr = SwitchLetter(outStr, "_", "&#95;")
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  outStr = SwitchLetter(outStr, "`", "&#96;")
<nowiki>function IsNegative(x)                    -- Returns True/False if number is a negative number 
  outStr = SwitchLetter(outStr, "{", "&#123")
  if x >=0.0 then
  outStr = SwitchLetter(outStr, "|", "&#124")
    return false
   outStr = SwitchLetter(outStr, "}", "&#125")
  else
  outStr = SwitchLetter(outStr, "~", "&#126")
    return true
    return outStr
  end -- if end
end -- function end
end -- function end</nowiki>
-- =====================================================]]
 
function SwitchLetter(MyStr, MyChar, NewStr)           -- swwap a leter for another letter
----
   local outStr, str1 = ""
===IsAllNumber()===
  local inStrLen = string.len(MyStr)
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  for i = 1, inStrLen ,1 do
 
    str1 = string.sub(MyStr, i, i)
<nowiki>function IsAllNumber(str)                  -- Returns True/False if finds all numbers in string
    if string.byte(str1) == string.byte(MyChar) then
   local out = true                                   
    outStr=outStr .. NewStr
   local let = ""
    else
   for i = 1, #str do
        outStr=outStr .. str1
    let = str:byte(i)
    end
    if (let ~= 48) and (let ~= 49) and (let ~= 50) and (let ~= 51) and
  end
      (let ~= 52) and (let ~= 53) and (let ~= 54) and (let ~= 55) and
   return outStr
      (let ~= 56) and (let ~= 57) and (let ~= 46) then
end -- function end
      out = false
-- =====================================================]]
    end -- if end
function PadC(str, lenth)                       -- Adds spaces to front and back to center text in lenth
   end -- for end
-- Local Word = PadC("K", 12) -- returns "    K      "
   return out        -- send out the return
  if type(str) ~= "string" then
end  -- function end</nowiki>
    str = tostring(str)
 
   end
----
  if string.len(str) < lenth then
 
  local a = math.floor(lenth - string.len(str) * 0.5) - 2
===NonNumber()===
  local b = math.ceil(lenth - string.len(str) * 0.5) - 2
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
   --print ("a = " .. a)
<nowiki>function NonNumber(Val)                    -- Return true if val is not number
   for _ = 1, a, 1 do
    if tonumber(x) ~= nil then
    str = " " .. str
      return false
   end
    end -- if end
  for _ = 1, b, 1 do
    return true
    str =  str .. " "
   end -- end function</nowiki>
  end
 
  --print ("str len = " .. #str)
----
  end
 
  return str
===NumberType()===
end -- function end
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- =====================================================]]
<nowiki>function NumberType(Val)                   -- Return true if val is not number
function PadR(str, len)                       -- Adds spaces to Back of string
    if math.type(x) == "integer" then
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "KPSDFKSPSK  "
      return "integer"
  if type(str) ~= "string" then
    else
    str = tostring(str)
      return "float"
  end
    end -- if end
  while string.len(str) < len do
   end -- end function</nowiki>
     str = str .. " "
 
  end
----
  return str
 
end -- function end
==Math Tools==
-- =====================================================]]
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
function PadL(str, len)             -- Adds spaces to Front of string
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "  KPSDFKSPSK"
 
  if type(str) ~= "string" then
----
    str = tostring(str)
 
  end
===ArcSegment()===
  while string.len(str) < len do
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    str = " " .. str
<nowiki>function ArcSegment(p1, p2, Rad)                       -- Returns the Arc Segment
  end
   local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
  return str
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
end -- function end
  return segment
-- =====================================================]]
end -- function end</nowiki>
function NumberPad(str, front, back) -- Adds spaces to front and zeros to the back of string
 
  local mychar
----
  local  a,b,c,d = 0,0,0,0
 
  local x,y,z = "","",""
===D(x) Doubles x===
  if type(str) ~= "string" then
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    str = tostring(str)
<nowiki>function D(x)                                          -- Returns double the value
  end
  return x * 2.0
  c = string.len(str)
end -- function end</nowiki>
  for i = 1, c, 1 do
 
    mychar = string.byte(string.sub(str, i,i))
----
    if mychar == 46 then
 
      b = i
===H(x) Halfs x===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function H(x)                                           -- Returns half the value
   return x * 0.5
end -- function end</nowiki>
 
----
 
===C(x) Returns x by scale===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function C(x)                                           -- Returns scale value
   return x * Project.Cal
end -- function end</nowiki>
 
----
 
===ChordSag2Radius()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function ChordSag2Radius (Chr, Seg)                    -- Returns the Rad from Chord and Seg
  local rad = ((((Chr * Chr)/(Seg * 4)) + Seg) / 2.0)
  return rad
end -- function end</nowiki>
 
----
 
===RadSag2Chord()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function RadSag2Chord(Rad, Seg)                        -- Returns the Chord from Rad and Seg
  local Ang = 2 * math.acos(1 - (Seg/Rad))
  local Chord = (2 * Rad) * math.sin(Ang * 0.5)
  return Chord
end -- function end</nowiki>
 
----
 
===RadChord2Segment()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function RadChord2Segment (Rad, Chord)       -- Returns the Arc Segment from Rad and Chord
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - Chord^2))))
   return segment
end -- function end</nowiki>
 
----
 
===RoundTo()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function RoundTo(Num, Per)                  -- Returns the number from
   local Head = Num < 0 and math.ceil(Num) or math.floor(Num)
   local Tail = Num - Head
  local Value = Head + tonumber(string.sub(tostring(Tail), 1, Per + 2))
   return Value
end -- function end</nowiki>
 
----
 
===Round()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function Round(x)
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end</nowiki>
 
----
 
===DecimalPlaces()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function DecimalPlaces(Dnum, Plac)
  return tonumber(string.sub(tostring(Dnum)  .. "000000000000000000000000000000000000",1, string.len(tostring(math.floor(Dnum))) + 1 + Plac))
end</nowiki>
 
----
 
===ToInteger()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function ToInteger( x )
     local num = tonumber( x )
    return num < 0 and math.ceil( num ) or math.floor( num )
end </nowiki>
 
----
 
===TrigIt===
Finds all 5 properties of a triangle
 
<nowiki>function TrigIt(A, B, AB, AC, BC)
-- Sub Function to help other functions
-- Call = A, B, AB, AC, BC = Trig(A, B, AB, AC, BC)
-- C is the corner, A = small ang and B is the big angle
-- returns all values
-- A, B = angles
-- C = 90.0 Deg
-- B to C (BC) is Run - Base - adjacent
-- A to C (AC) is Rise - Height - opposite
-- A to B (AB) is Slope - hypotenuse
    if (B > 0.0) and (A == 0.0) then
      A = math.deg(math.rad(90) - math.rad(B))
    end
    if (A > 0.0) and (B == 0.0) then
      B = math.deg(math.rad(90) - math.rad(A))
     end
     end
  end
    if (AC > 0.0) and (BC > 0.0) then
-- print("b = " .. b)
      AB = math.sqrt((AC ^ 2) + (BC ^ 2))
  if b == 0 then
      A = math.deg(math.atan(BC/AC))
    str = str .. "."
      B = math.deg(math.rad(90) - math.rad(A))
    c = c + 1
    elseif (AB > 0.0) and (BC > 0.0) then
    b = c
      AB = math.sqrt((AB ^ 2) - (BC ^ 2))
  end -- if loc
      A = math.deg(math.atan(BC/AC))
  x = string.sub(str, 1, b-1)
       B = math.deg(math.rad(90) - math.rad(A))
  y = string.sub(str, b+1)
     elseif (AB > 0.0) and (AC > 0.0) then
  a = c - b
      AB = math.sqrt((AB ^ 2) - (AC ^ 2))
  a = #x
      A = math.deg(math.atan(BC/AC))
  d = #y
      B = math.deg(math.rad(90) - math.rad(A))
  if a < front then
    elseif (A > 0.0) and (AC > 0.0) then
    front = front - (a - 1)
      AB = AC / math.cos(math.rad(A))
    for _ = 1, front -1 do
      BC = AB * math.sin(math.rad(A))
       x = " " .. x
    elseif (A > 0.0) and (BC > 0.0) then
    end -- end for front
      AB = BC / math.sin(math.rad(A))
  end
      AC = AB * math.cos(math.rad(A))
  back = back - (c - b)
    elseif (A > 0.0) and (AB > 0.0) then
  for i = 1, back  do
      BC = AB * math.sin(math.rad(A))
     y = y .. "0"
      AC = AB * math.cos(math.rad(A))
  end -- end for back
     else
  str =   x .. "." .. y
      MessageBox("Error: No Missing Value")
  return str
     end -- if end
end -- function end
    return A, B, AB, AC, BC
-- =====================================================]]
  end</nowiki>
function All_Trim(s)                           -- Trims spaces off both ends of a string
  return s:match( "^%s*(.-)%s*$" )
end -- function end
-- =====================================================]]
function Make_Proper_Case(str)
  local str=string.gsub(string.lower(str),"^(%w)", string.upper)
  return string.gsub(str,"([^%w]%w)", string.upper)
end
-- =====================================================]]
function ifT(x)                               -- Converts Boolean True or False to String "Yes" or "No"
-- ===ifT(x)===
  if x then
    return "Yes"
  else
    return "No"
  end-- if end
end -- function end
-- =====================================================]]
function ifY(x)                               -- Converts String "Yes" or "No" to Boolean True or False
-- ===ifY(x)===
  if string.upper(x) == "YES" then
     return true
  else
     return false
  end-- if end
end -- function end
-- =***************************************************=]]
end -- String function end


</nowiki>
----


==Seed Documents==
==Registry Read and Write Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


<nowiki>
----
 
-- =====================================================]]
===DocVarChk()===
╔═╗╔═╗╔═╗╔╦╗  ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
╚═╗║╣ ║╣  ║║  ╠╣ ║ ║║║║║  ║ ║║ ║║║║
<nowiki>function DocVarChk(Name, Value)
╚═╝╚═╝╚═╝═╩╝  ╚  ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝
  local job = VectricJob()
function SeedTool()
  local document_variable_list = job.DocumentVariables
-- =====================================================]]
  return document_variable_list:DocumentVariableExists(Name)
  -- VECTRIC LUA SCRIPT
end -- function end</nowiki>
-- =====================================================]]
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.
-- Permission is granted to anyone to use this software for any purpose,
-- including commercial applications, and to alter it and redistribute it freely,
-- subject to the following restrictions:
-- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
-- 2. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.
-- 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-- 4. This notice may not be removed or altered from any source distribution.
-- Easy Seed Gadget Master is written by Jim Anderson of Houston Texas 2020
-- =====================================================]]
-- require("mobdebug").start()
-- require "strict"
local Tools
-- Global Variables --
local Ver = "1.0"  -- Version 7: Aug 2021 - Clean Up and added Ver to Dialog
 
-- Table Names
Milling = {}
Project = {}
-- =====================================================]]
function main(script_path)
--[[
Gadget Notes: Dec 2019 - My New Gadget


  ]]
----
-- Localized Variables --


-- Job Validation --
===DocVarGet()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function DocVarGet(Name)
   local job = VectricJob()
   local job = VectricJob()
   if not job.Exists then
   local document_variable_list = job.DocumentVariables
    DisplayMessageBox("Error: No job loaded")
  return document_variable_list:GetDocumentVariable(Name, 0.0)
    return false
end -- function end</nowiki>
  end


  Tools = assert(loadfile(script_path .. "\\EasyGearToolsVer" .. Ver .. ".xlua")) (Tools) -- Load Tool Function
----
-- Get Data --


-- Calculation --
===DocVarSet()===
 
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- Do Something --
<nowiki>function DocVarSet(Name, Value)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:SetDocumentVariable(Name, Value)
end -- function end</nowiki>


----


===RegistryReadMaterial()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function RegistryReadMaterial()                -- Read from Registry Material values for LUA Bit
  local RegistryRead              = Registry("Material")
  Milling.SafeZGap                = Rounder(RegistryRead:GetString("SafeZGap",              "0.500"), 4)
  Milling.StartZGap              = Rounder(RegistryRead:GetString("StartZGap",            "0.500"), 4)
  Milling.HomeX                  = Rounder(RegistryRead:GetString("HomeX",                "0.000"), 4)
  Milling.HomeY                  = Rounder(RegistryRead:GetString("HomeY",                "0.000"), 4)
  Milling.HomeZGap                = Rounder(RegistryRead:GetString("HomeZGap",              "0.750"), 4)
   return true
   return true
end -- function end
end -- function end</nowiki>
-- ==================== End ============================]]
-- =====================================================]]
end -- Seed Tools function end


</nowiki>
----


==Setup Tools==
===RegistryLastTenFiles()===
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function RegistryLastTenFiles(FileName)        -- Adds to the top ten Log file list
  local Registry = Registry(RegName)
  LogFile.File10 = Registry:GetString("LogFile.File09", "No Log Yet" )
  LogFile.File09 = Registry:GetString("LogFile.File08", "No Log Yet" )
  LogFile.File08 = Registry:GetString("LogFile.File07", "No Log Yet" )
  LogFile.File07 = Registry:GetString("LogFile.File06", "No Log Yet" )
  LogFile.File06 = Registry:GetString("LogFile.File05", "No Log Yet" )
  LogFile.File05 = Registry:GetString("LogFile.File04", "No Log Yet" )
  LogFile.File04 = Registry:GetString("LogFile.File03", "No Log Yet" )
  LogFile.File03 = Registry:GetString("LogFile.File02", "No Log Yet" )
  LogFile.File02 = Registry:GetString("LogFile.File01", "No Log Yet" )
  LogFile.File01 = FileName
  return FileName
end -- function end</nowiki>


<nowiki>
----
-- =====================================================]]
╔═╗╔═╗╔╦╗╦ ╦╔═╗
╚═╗║╣  ║ ║ ║╠═╝
╚═╝╚═╝ ╩ ╚═╝╩
function SetupAndLetter Seeds()
-- =====================================================]]
  function LUA_Seed()
    -- VECTRIC LUA SCRIPT
    -- ==============================================================================
    --  Gadgets are an entirely optional add-in to Vectric's core software products.
    --  They are provided 'as-is', without any express or implied warranty, and you
    --  make use of them entirely at your own risk.
    --  In no event will the author(s) or Vectric Ltd. be held liable for any damages
    --  arising from their use.
    --  Permission is granted to anyone to use this software for any purpose,
    --  including commercial applications, and to alter it and redistribute it freely,
    --  subject to the following restrictions:
    --  1. The origin of this software must not be misrepresented;
    --    you must not claim that you wrote the original software.
    --    If you use this software in a product, an acknowledgement in the product
    --    documentation would be appreciated but is not required.
    --  2. Altered source versions must be plainly marked as such, and
    --    must not be misrepresented as being the original software.
    --  3. This notice may not be removed or altered from any source distribution.
    -- ==============================================================================
    -- "AppName Here" was written by JimAndi Gadgets of Houston Texas
    -- ==============================================================================
    -- =====================================================]]
    -- require("mobdebug").start()
    -- require "strict"
    -- =====================================================]]
    -- Global variables
    -- =====================================================]]
  end -- lua function
-- =====================================================]]
  function Install_letter()
  -- Steps to Install:


  -- 1. Download the gadget x.zip that is attached to this post.
===RegistryRead()===
   -- 2. Rename it from x.zip to x.vgadget
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
   -- 3. In Vectric Pro or Aspire click on Gadgets -> Install Gadget and navigate to where you downloaded the file to, select it and click Ok.
<nowiki>function RegistryRead()                        -- Read from Registry values
  local RegistryRead = Registry("RegName")
  local Yes_No      = RegistryRead:GetBool("BaseDim.Yes_No", ture)
  local CabHeight    = RegistryRead:GetDouble("BaseDim.CabHeight", 35.500)
   local CabCount    = RegistryRead:GetInt("BaseDim.CabCount", 36)
   local Name        = RegistryRead:GetString("BaseDim.Name", "Words")


   -- It should give you a pop up saying the gadget was installed and you should see x in the Gadgets menu.
   Milling.MillTool1.FeedRate                = RegistryRead:GetDouble("Milling.MillTool1.FeedRate",              30.000)
  Milling.MillTool1.InMM                    = RegistryRead:GetBool("Milling.MillTool1.InMM ",                  false)
  Milling.MillTool1.Name                    = RegistryRead:GetString("Milling.MillTool1.Name",                  "No Tool Selected")
  Milling.MillTool1.BitType                = RegistryRead:GetString("Milling.MillTool1.BitType",              "END_MILL") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool1.RateUnits              = RegistryRead:GetInt("Milling.MillTool1.RateUnits",                4)
  Milling.MillTool1.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool1.SpindleSpeed",            20000)
  Milling.MillTool1.ToolNumber              = RegistryRead:GetInt("Milling.MillTool1.ToolNumber",              1)
  Milling.MillTool1.Stepdown                = RegistryRead:GetDouble("Milling.MillTool1.Stepdown",              0.2000)
  Milling.MillTool1.Stepover                = RegistryRead:GetDouble("Milling.MillTool1.Stepover",              0.0825)
  Milling.MillTool1.ToolDia                = RegistryRead:GetDouble("Milling.MillTool1.ToolDia",              0.1250)
  Milling.MillTool1.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool1.PlungeRate",            15.000)


   -- Image Here
   Milling.MillTool2.FeedRate                = RegistryRead:GetDouble("Milling.MillTool2.FeedRate",              30.000)
  Milling.MillTool2.InMM                    = RegistryRead:GetBool("Milling.MillTool2.InMM ",                  false)
  Milling.MillTool2.Name                    = RegistryRead:GetString("Milling.MillTool2.Name",                  "No Tool Selected")
  Milling.MillTool2.BitType                = RegistryRead:GetString("Milling.MillTool2.BitType",              "BALL_NOSE") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool2.RateUnits              = RegistryRead:GetInt("Milling.MillTool2.RateUnits",                4)
  Milling.MillTool2.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool2.SpindleSpeed",            20000)
  Milling.MillTool2.ToolNumber              = RegistryRead:GetInt("Milling.MillTool2.ToolNumber",              2)
  Milling.MillTool2.Stepdown                = RegistryRead:GetDouble("Milling.MillTool2.Stepdown",              0.2000)
  Milling.MillTool2.Stepover                = RegistryRead:GetDouble("Milling.MillTool2.Stepover",              0.0825)
  Milling.MillTool2.ToolDia                = RegistryRead:GetDouble("Milling.MillTool2.ToolDia",              0.1250)
  Milling.MillTool2.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool2.PlungeRate",            15.000)


   -- Steps for Use:
   Milling.MillTool3.FeedRate                = RegistryRead:GetDouble("Milling.MillTool3.FeedRate",              30.000)
   -- 1. Select a layer that you want to calculate for
  Milling.MillTool3.InMM                    = RegistryRead:GetBool("Milling.MillTool3.InMM",                    false)
   -- 2. Enter the cut depth
  Milling.MillTool3.Name                    = RegistryRead:GetString("Milling.MillTool3.Name",                  "No Tool Selected")
   -- 3. Enter the percentage of coverage for the area that will be filled in
   Milling.MillTool3.BitType                = RegistryRead:GetString("Milling.MillTool3.BitType",              "END_MILL")  -- BALL_NOSE, END_MILL, VBIT
   -- 4. Enter the hardner to resin percentage
  Milling.MillTool3.RateUnits              = RegistryRead:GetInt("Milling.MillTool3.RateUnits",                4)
   -- 5. Click the Calculate Button and the results will be displayed below in the Results Pane.
   Milling.MillTool3.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool3.SpindleSpeed",            20000)
   end -- install function
   Milling.MillTool3.ToolNumber              = RegistryRead:GetInt("Milling.MillTool3.ToolNumber",              3)
  Milling.MillTool3.Stepdown                = RegistryRead:GetDouble("Milling.MillTool3.Stepdown",              0.2000)
   Milling.MillTool3.Stepover                = RegistryRead:GetDouble("Milling.MillTool3.Stepover",              0.0825)
   Milling.MillTool3.ToolDia                = RegistryRead:GetDouble("Milling.MillTool3.ToolDia",              0.1250)
   Milling.MillTool3.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool3.PlungeRate",            15.000)


end -- Header function
  Milling.MillTool4.FeedRate                = RegistryRead:GetDouble("Milling.MillTool4.FeedRate",              30.000)
-- =====================================================]]
  Milling.MillTool4.InMM                    = RegistryRead:GetBool("Milling.MillTool4.InMM ",                  false)
  Milling.MillTool4.Name                    = RegistryRead:GetString("Milling.MillTool4.Name",                  "No Tool Selected")
  Milling.MillTool4.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool4.PlungeRate",            15.000)
  Milling.MillTool4.RateUnits              = RegistryRead:GetInt("Milling.MillTool4.RateUnits",                4)
  Milling.MillTool4.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool4.SpindleSpeed",            20000)
  Milling.MillTool4.Stepdown                = RegistryRead:GetDouble("Milling.MillTool4.Stepdown",              0.2000)
  Milling.MillTool4.Stepover                = RegistryRead:GetDouble("Milling.MillTool4.Stepover",              0.0825)
  Milling.MillTool4.ToolDia                = RegistryRead:GetDouble("Milling.MillTool4.ToolDia",              0.1250)
  Milling.MillTool4.ToolNumber              = RegistryRead:GetInt("Milling.MillTool4.ToolNumber",              5)


</nowiki>
  Milling.MillTool5.FeedRate                = RegistryRead:GetDouble("Milling.MillTool5.FeedRate",              30.000)
  Milling.MillTool5.InMM                    = RegistryRead:GetBool("Milling.MillTool5.InMM ",                  false)
  Milling.MillTool5.Name                    = RegistryRead:GetString("Milling.MillTool5.Name",                  "No Tool Selected")
  Milling.MillTool5.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool5.PlungeRate",            15.000)
  Milling.MillTool5.RateUnits              = RegistryRead:GetInt("Milling.MillTool5.RateUnits",                4)
  Milling.MillTool5.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool5.SpindleSpeed",            20000)
  Milling.MillTool5.Stepdown                = RegistryRead:GetDouble("Milling.MillTool5.Stepdown",              0.2000)
  Milling.MillTool5.Stepover                = RegistryRead:GetDouble("Milling.MillTool5.Stepover",              0.0825)
  Milling.MillTool5.ToolDia                = RegistryRead:GetDouble("Milling.MillTool5.ToolDia",              0.1250)
  Milling.MillTool5.ToolNumber              = RegistryRead:GetInt("Milling.MillTool5.ToolNumber",              6)
  return true
end -- function end</nowiki>


==Toolpathing Tools==
----
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].


<nowiki>
===RegistryWrite()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
-- =====================================================]]
  <nowiki>function RegistryWrite()                       -- Write to Registry values
╔╦╗╔═╗╔═╗╦ ╔═╗╔═╗╔╦╗╦ ╦╔═╗
   local RegistryWrite = Registry("RegName")
║ ║ ║║ ║║  ╠═╝╠═╣ ║ ╠═╣╚═╗
  local RegValue
╩ ╚═╝╚═╝╩═╝╩  ╩ ╩ ╩ ╩ ╩╚═╝
  RegValue = RegistryWrite:SetBool("ProjectQuestion.CabinetName", true)
function Toolpaths()
  RegValue = RegistryWrite:SetDouble("BaseDim.CabDepth", 23.0000)
-- =====================================================]]
  RegValue = RegistryWrite:SetInt("BaseDim.CabHeight", 35)
   function CreateLayerProfileToolpath(name, layer_name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
  RegValue = RegistryWrite:SetString("BaseDim.CabLength", "Words")
    -- clear current selection
    local selection = job.Selection
    selection:Clear()
    -- get layer
    local layer = job.LayerManager:FindLayerWithName(layer_name)
    if layer == nil then
      DisplayMessageBox("No layer found with name = " .. layer_name)
      return false
    end
    -- select all closed vectors on the layer
    if not SelectVectorsOnLayer(layer, selection, true, false, true) then
      DisplayMessageBox("No closed vectors found on layer " .. layer_name)
      return false
    end
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT


     tool.InMM = tool_in_mm
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.FeedRate" ,     Milling.MillTool1.FeedRate)
     tool.ToolDia = tool_dia
  RegValue = RegistryWrite:SetBool("Milling.MillTool1.InMM",            Milling.MillTool1.InMM)
     tool.Stepdown = tool_stepdown
  RegValue = RegistryWrite:SetString("Milling.MillTool1.Name",          Milling.MillTool1.Name)
     tool.Stepover = tool_dia * 0.25
  RegValue = RegistryWrite:SetString("Milling.MillTool1.BitType",      Milling.MillTool1.BitType)
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.PlungeRate" ,  Milling.MillTool1.PlungeRate)
    tool.FeedRate = 30
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.RateUnits",        Milling.MillTool1.RateUnits)
    tool.PlungeRate = 10
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.SpindleSpeed",     Milling.MillTool1.SpindleSpeed)
     tool.SpindleSpeed = 20000
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepdown" ,     Milling.MillTool1.Stepdown)
     tool.ToolNumber = 1
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepover" ,     Milling.MillTool1.Stepover)
     tool.VBit_Angle = 90.0 -- used for vbit only
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.ToolDia" ,      Milling.MillTool1.ToolDia)
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.ToolNumber",      Milling.MillTool1.ToolNumber)
     -- Create object used to set home position and safez gap above material surface
 
    local pos_data = ToolpathPosData()
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.FeedRate" ,     Milling.MillTool2.FeedRate)
    pos_data:SetHomePosition(0, 0, 1.0)
  RegValue = RegistryWrite:SetBool("Milling.MillTool2.InMM",           Milling.MillTool2.InMM)
    pos_data.SafeZGap = 5.0
  RegValue = RegistryWrite:SetString("Milling.MillTool2.Name",         Milling.MillTool2.Name)
     -- Create object used to pass profile options
  RegValue = RegistryWrite:SetString("Milling.MillTool2.BitType",       Milling.MillTool2.BitType)
    local profile_data = ProfileParameterData()
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.PlungeRate" ,  Milling.MillTool2.PlungeRate)
     -- start depth for toolpath
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.RateUnits",        Milling.MillTool2.RateUnits)
    profile_data.StartDepth = start_depth
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.SpindleSpeed",     Milling.MillTool2.SpindleSpeed)
    -- cut depth for toolpath this is depth below start depth
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepdown" ,     Milling.MillTool2.Stepdown)
     profile_data.CutDepth = cut_depth
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepover" ,     Milling.MillTool2.Stepover)
    -- direction of cut - ProfileParameterData.
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.ToolDia" ,      Milling.MillTool2.ToolDia)
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.ToolNumber",      Milling.MillTool2.ToolNumber)
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
 
    -- side we machine on - ProfileParameterData.
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.FeedRate" ,     Milling.MillTool3.FeedRate)
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
  RegValue = RegistryWrite:SetBool("Milling.MillTool3.InMM",            Milling.MillTool3.InMM)
     -- ProfileParameterData.PROFILE_ON
  RegValue = RegistryWrite:SetString("Milling.MillTool3.Name",         Milling.MillTool3.Name)
     profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
  RegValue = RegistryWrite:SetString("Milling.MillTool3.BitType",       Milling.MillTool3.BitType)
     -- Allowance to leave on when machining
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.PlungeRate",    Milling.MillTool3.PlungeRate)
    profile_data.Allowance = 0.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.RateUnits",        Milling.MillTool3.RateUnits)
    -- true to preserve start point positions, false to reorder start
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.SpindleSpeed",     Milling.MillTool3.SpindleSpeed)
    -- points to minimise toolpath length
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepdown" ,    Milling.MillTool3.Stepdown)
    profile_data.KeepStartPoints = false
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepover" ,     Milling.MillTool3.Stepover)
    -- true if want to create 'square' external corners on toolpath
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.ToolDia" ,      Milling.MillTool3.ToolDia)
    profile_data.CreateSquareCorners = false
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.ToolNumber",      Milling.MillTool3.ToolNumber)
    -- true to perform corner sharpening on internal corners (only with v-bits)
 
    profile_data.CornerSharpen = false
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.FeedRate" ,     Milling.MillTool4.FeedRate)
     -- true to use tabs (position of tabs must already have been defined on vectors)
  RegValue = RegistryWrite:SetBool("Milling.MillTool4.InMM",            Milling.MillTool4.InMM)
     profile_data.UseTabs = false
  RegValue = RegistryWrite:SetString("Milling.MillTool4.Name",          Milling.MillTool4.Name)
    -- length for tabs if being used
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.PlungeRate" ,  Milling.MillTool4.PlungeRate)
    profile_data.TabLength = 5.0
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.RateUnits",       Milling.MillTool4.RateUnits)
    -- Thickness for tabs if being used
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.SpindleSpeed",     Milling.MillTool4.SpindleSpeed)
    profile_data.TabThickness = 1.0
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepdown" ,     Milling.MillTool4.Stepdown)
    -- if true then create 3d tabs else 2d tabs
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepover" ,     Milling.MillTool4.Stepover)
    profile_data.Use3dTabs = true
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.ToolDia" ,      Milling.MillTool4.ToolDia)
    -- if true in Aspire, project toolpath onto composite model
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.ToolNumber",      Milling.MillTool4.ToolNumber)
    profile_data.ProjectToolpath = false
  return true
    -- Create object used to control ramping
end -- function end</nowiki>
    local ramping_data = RampingData()
 
    -- if true we do ramping into toolpath
----
     ramping_data.DoRamping = false
 
     -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
===REG_CheckRegistryBool()===
    -- or RampingData.RAMP_SPIRAL
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
<nowiki>function REG_CheckRegistryBool()              -- Checks Registry for Bool values
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
  local RegistryRead = Registry("RegName")
    -- or RampingData.CONSTRAIN_ANGLE
  if RegistryRead:BoolExists("ProjectQuestion.Runtool") then
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
     DisplayMessageBox("Alert: The Runtool value is saved.")
    -- if we are constraining ramp by distance, distance to ramp over
  else
    ramping_data.RampDistance = 100.0
     DisplayMessageBox("Alert: The Runtool value is not saved.")
     -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
  end -- if end
     ramping_data.RampAngle = 25.0
  return true
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
end -- function end</nowiki>
    -- if zig zaging
 
    ramping_data.RampMaxAngleDist = 15
----
    -- if true we restrict our ramping to lead in section of toolpath
 
    ramping_data.RampOnLeadIn = false
===REG_CheckRegistryDouble()===
    -- Create object used to control lead in/out
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    local lead_in_out_data = LeadInOutData()
<nowiki>function REG_CheckRegistryDouble()            -- Checks Registry for Double values
    -- if true we create lead ins on profiles (not for profile on)
  local RegistryRead = Registry("RegName")
     lead_in_out_data.DoLeadIn = false
  if RegistryRead:DoubleExists("ProjectQuestion.ProjectCost") then
     -- if true we create lead outs on profiles (not for profile on)
     DisplayMessageBox("Alert: The project cost is saved.")
    lead_in_out_data.DoLeadOut = false
  else
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
     DisplayMessageBox("Alert: The Project Cost is not saved.")
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
  end -- if end
    -- length of lead to create
  return true
    lead_in_out_data.LeadLength = 10.0
end -- function end</nowiki>
    -- Angle for linear leads
 
    lead_in_out_data.LinearLeadAngle = 45
----
    -- Radius for circular arc leads
 
    lead_in_out_data.CirularLeadRadius = 5.0
===REG_CheckRegistryInt()===
    -- distance to 'overcut' (travel past start point) when profiling
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    lead_in_out_data.OvercutDistance = 0.0
<nowiki>function REG_CheckRegistryInt()                -- Checks Registry for Int values
    -- Create object which can be used to automatically select geometry
  local RegistryRead = Registry("RegName")
    local geometry_selector = GeometrySelector()
  if RegistryRead:IntExists("ProjectQuestion.ProjectCount") then
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
     DisplayMessageBox("Alert: The Project Count is saved.")
    local create_2d_previews = true
  else
    -- if this is true we will display errors and warning to the user
     DisplayMessageBox("Alert: The Project Count is not saved.")
    local display_warnings = true
  end -- if end
    -- Create our toolpath
  return true
    local toolpath_manager = ToolpathManager()
end -- function end</nowiki>
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
 
     if toolpath_id == nil then
----
       DisplayMessageBox("Error creating toolpath")
 
      return false
===REG_CheckRegistryString()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function REG_CheckRegistryString()            -- Checks Registry for String values
  local RegistryRead = Registry("RegName")
  if RegistryRead:StringExists("ProjectQuestion.ProjectPath") then
     DisplayMessageBox("Alert: The Project path is saved.")
  else
     DisplayMessageBox("Alert: The Project path is not saved.")
  end
  return true
end -- function end</nowiki>
 
==String Tools==
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
----
 
===StringToArraySplit===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function StringToArraySplit(s, delimiter)
--[[
split_string = StringToArraySplit("Hello World,Jim,Bill,Tom", ",")
Returns = array
-- split_string[1] = "Hello World,)
-- split_string[2] = "Jim"
]]
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
      table.insert(result, match)
  end
  return result
end
  </nowiki>
 
----
 
===WrapString===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>
function WrapString(Str, Wid)                          -- wraps text at the nearest space and puts a return char in the space location
  --[[  How to use:
  Call WrapString(string, Number)
WrapString("Jim is a tall man that lives in Texas. He was raised in North East Texas on 1000 acres from 1970 to 1982. This is a man that knows numbers of great people from a round the world.", 40)
returns "Jim is a tall man that lives in Texas.\n
          He was raised in North East Texas on\n
          1000 acres from 1970 to 1982. This is a man\n
          that knows numbers of great people from\n
          a round the world."
]]
  local Wider = Wid
  local Posx = string.len(Str)
  local StrLen = string.len(Str)
  local pt = 0
  local function FindSpace(MyStr)
  local Pos = string.len(MyStr)
  local str = MyStr
     if string.find(MyStr, " ") ~= nil then
       while Pos>0 do
        Pos = Pos - 1
          if (string.byte(string.sub(str,-1)) == 32) then
            break
          else
            str = string.sub(str, 1, Pos)
          end
        end
     end
     end
     return true
     return Pos
end -- end function
  end
-- =====================================================]]
   if StrLen > Wider then
   function CreateProfileToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
     while Wider < Posx do
     -- Create tool we will use to machine vectors
      pt = FindSpace(string.sub(Str,1, Wider))
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
      Str = string.sub(Str, 1, pt) .. "\n" .. string.sub(Str, pt +2)
    tool.InMM = tool_in_mm
      Wider = Wider + Wid
    tool.ToolDia = tool_dia
     end
    tool.Stepdown = tool_stepdown
  end
    tool.Stepover = tool_dia * 0.25
  return Str
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
end -- function end
    tool.FeedRate = 30
  </nowiki>
    tool.PlungeRate = 10
 
    tool.SpindleSpeed = 20000
----
    tool.ToolNumber = 1
 
    tool.VBit_Angle = 90.0 -- used for vbit only
===CleanString===
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    -- Create object used to set home position and safez gap above material surface
<nowiki>
    local pos_data = ToolpathPosData()
function CleanString(inStr)                         -- Check for ascii letters below 127
    pos_data:SetHomePosition(0, 0, 1.0)
  local outStr, str1 = ""
    pos_data.SafeZGap = 5.0
  local inStrLen = string.len(inStr)
     -- Create object used to pass profile options
  for i = 1, inStrLen ,1 do
    local profile_data = ProfileParameterData()
     str1 = string.sub(inStr, i, i)
    -- start depth for toolpath
     if string.byte(str1) <= 127 then
    profile_data.StartDepth = start_depth
    outStr=outStr .. str1
    -- cut depth for toolpath this is depth below start depth
     end
    profile_data.CutDepth = cut_depth
  end
    -- direction of cut - ProfileParameterData.
  return outStr
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
end -- function end
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
  </nowiki>
    -- side we machine on - ProfileParameterData.
 
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
----
    -- ProfileParameterData.PROFILE_ON
 
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
===GetDiameterAndCentre===
    -- Allowance to leave on when machining
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    profile_data.Allowance = 0.0
<nowiki>
    -- true to preserve start point positions, false to reorder start
function CheckString(YourStr)                         -- Check string for specal bite chars for HTML
    -- points to minimise toolpath length
  local function FindLetter(TheStr, TestChar)
    profile_data.KeepStartPoints = false
     local outStr = false
    -- true if want to create 'square' external corners on toolpath
     local strChar = ""
    profile_data.CreateSquareCorners = false
     local TheStrLen = string.len(TheStr)
    -- true to perform corner sharpening on internal corners (only with v-bits)
     for i = 1, TheStrLen ,1 do
    profile_data.CornerSharpen = false
      strChar = string.sub(TheStr, i, i)
    -- true to use tabs (position of tabs must already have been defined on vectors)
      if string.byte(strChar) == string.byte(TestChar) then
    profile_data.UseTabs = false
        outStr = true
    -- length for tabs if being used
        break
    profile_data.TabLength = 5.0
      end
    -- Thickness for tabs if being used
     end
    profile_data.TabThickness = 1.0
     return outStr
    -- if true then create 3d tabs else 2d tabs
  end -- function end
    profile_data.Use3dTabs = true
  </nowiki>
    -- if true in Aspire, project toolpath onto composite model
 
    profile_data.ProjectToolpath = false
----
    -- Create object used to control ramping
 
    local ramping_data = RampingData()
===GetDiameterAndCentre===
    -- if true we do ramping into toolpath
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    ramping_data.DoRamping = false
<nowiki>
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
  local StrTest = false
    -- or RampingData.RAMP_SPIRAL
  StrTest = SwitchLetter(YourStr,  "&") -- Non frendly File Name letters
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
  StrTest = SwitchLetter(YourStr, "#")
     -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
   StrTest = SwitchLetter(YourStr,  "@")
    -- or RampingData.CONSTRAIN_ANGLE
  StrTest = SwitchLetter(YourStr, "^")
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
  StrTest = SwitchLetter(YourStr,  "$")
    -- if we are constraining ramp by distance, distance to ramp over
     return outStr
    ramping_data.RampDistance = 100.0
end -- function end
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
  </nowiki>
     ramping_data.RampAngle = 25.0
 
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
----
    -- if zig zaging
 
    ramping_data.RampMaxAngleDist = 15
===MakeHTMLReady()===
    -- if true we restrict our ramping to lead in section of toolpath
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    ramping_data.RampOnLeadIn = false
<nowiki>
    -- Create object used to control lead in/out
function MakeHTMLReady(MyStr)                          -- fix's string with special bite chars for HTML
    local lead_in_out_data = LeadInOutData()
  local function SwitchLetter(MyStr, MyChar, NewStr)
    -- if true we create lead ins on profiles (not for profile on)
  local outStr, str1 = ""
    lead_in_out_data.DoLeadIn = false
  local inStrLen = string.len(MyStr)
    -- if true we create lead outs on profiles (not for profile on)
  for i = 1, inStrLen ,1 do
    lead_in_out_data.DoLeadOut = false
     str1 = string.sub(MyStr, i, i)
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
     if string.byte(str1) == string.byte(MyChar) then
     lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    outStr=outStr .. NewStr
    -- length of lead to create
    else
    lead_in_out_data.LeadLength = 10.0
        outStr=outStr .. str1
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
-- =====================================================]]
  function CreatePocketingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_stepover_percent, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
     tool.InMM = tool_in_mm
     tool.ToolDia = tool_dia
     tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * (tool_stepover_percent / 100)
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC,...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * (tool_stepover_percent / 100) -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass pocketing options
    local pocket_data = PocketParameterData()
    -- start depth for toolpath
    pocket_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    pocket_data.CutDepth = cut_depth
     -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or
     -- ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- Allowance to leave on when machining
    pocket_data.Allowance = 0.0
    -- if true use raster clearance strategy , else use offset area clearance
    pocket_data.DoRasterClearance = true
    -- angle for raster if using raster clearance
    pocket_data.RasterAngle = 0
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
    -- if true we ramp into pockets (always zig-zag)
    pocket_data.DoRamping = false
    -- if ramping, distance to ramp over
    pocket_data.RampDistance = 10.0
    -- if true in Aspire, project toolpath onto composite model
    pocket_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- if we are doing two tool pocketing define tool to use for area clearance
    local area_clear_tool = nill
    -- we just create a tool twice as large for testing here
    area_clear_tool = Tool("Lua Clearance End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    area_clear_tool.InMM = tool_in_mm
    area_clear_tool.ToolDia = tool_dia * 2
    area_clear_tool.Stepdown = tool_stepdown * 2
    area_clear_tool.Stepover = tool_dia * 2 *(tool_stepover_percent / 100)
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC..
    area_clear_tool.FeedRate = 30
    area_clear_tool.PlungeRate = 10
    area_clear_tool.SpindleSpeed = 20000
    area_clear_tool.ToolNumber = 1
    area_clear_tool.VBit_Angle = 90.0 -- used for vbit only
    area_clear_tool.ClearStepover = tool_dia*2*(tool_stepover_percent/100) -- used for vbit
   -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreatePocketingToolpath(name,tool,area_clear_tool,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nill then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
     return true
end -- end function
-- =====================================================]]
  function CreateDrillingToolpath(name, start_depth, cut_depth, retract_gap, tool_dia, tool_stepdown, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua Drill", Tool.THROUGH_DRILL) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local drill_data = DrillParameterData()
    -- start depth for toolpath
    drill_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    drill_data.CutDepth = cut_depth
    -- if true perform peck drilling
     drill_data.DoPeckDrill = retract_gap > 0.0
    -- distance to retract above surface when peck drilling
     drill_data.PeckRetractGap = retract_gap
    -- if true in Aspire, project toolpath onto composite model
    drill_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view,
    -- if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateDrillingToolpath(name,tool,drill_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
     end
     end
  end
  return outStr
end -- function end
  </nowiki>
----
===SwitchLetterTest===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function SwitchLetterTest(MyStr)
  local outStr = ""
  outStr = SwitchLetter(MyStr, "!", "&#33;")
  outStr = SwitchLetter(outStr, "#", "&#35;")
  outStr = SwitchLetter(outStr, "$", "&#36;")
  outStr = SwitchLetter(outStr, "%", "&#37;")
  outStr = SwitchLetter(outStr, "&", "&#38;")
  outStr = SwitchLetter(outStr, "'", "&#39;")
  outStr = SwitchLetter(outStr, "(", "&#40;")
  outStr = SwitchLetter(outStr, ")", "&#41;")
  outStr = SwitchLetter(outStr, "*", "&#42;")
  outStr = SwitchLetter(outStr, "+", "&#43;")
  outStr = SwitchLetter(outStr, ",", "&#44;")
  outStr = SwitchLetter(outStr, "-", "&#45;")
  outStr = SwitchLetter(outStr, ".", "&#46;")
  outStr = SwitchLetter(outStr, "/", "&#47;")
  outStr = SwitchLetter(outStr, ":", "&#58;")
  outStr = SwitchLetter(outStr, ";", "&#59;")
  outStr = SwitchLetter(outStr, "<", "&#60;")
  outStr = SwitchLetter(outStr, "=", "&#61;")
  outStr = SwitchLetter(outStr, ">", "&#62;")
  outStr = SwitchLetter(outStr, "?", "&#63;")
  outStr = SwitchLetter(outStr, "@", "&#64;")
  outStr = SwitchLetter(outStr, "[", "&#91;")
  outStr = SwitchLetter(outStr, "]", "&#93;")
  outStr = SwitchLetter(outStr, "^", "&#94;")
  outStr = SwitchLetter(outStr, "_", "&#95;")
  outStr = SwitchLetter(outStr, "`", "&#96;")
  outStr = SwitchLetter(outStr, "{", "&#123")
  outStr = SwitchLetter(outStr, "|", "&#124")
  outStr = SwitchLetter(outStr, "}", "&#125")
  outStr = SwitchLetter(outStr, "~", "&#126")
    return outStr
end -- function end
  </nowiki>
----
===SwitchLetter()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function SwitchLetter(MyStr, MyChar, NewStr)            -- swwap a leter for another letter
  local outStr, str1 = ""
  local inStrLen = string.len(MyStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(MyStr, i, i)
    if string.byte(str1) == string.byte(MyChar) then
    outStr=outStr .. NewStr
    else
        outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
  </nowiki>
----
===PadC===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function PadC(str, lenth)                        -- Adds spaces to front and back to center text in lenth
-- Local Word = PadC("K", 12) -- returns "    K      "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  if string.len(str) < lenth then
  local a = math.floor(lenth - string.len(str) * 0.5) - 2
  local b = math.ceil(lenth - string.len(str) * 0.5) - 2
  --print ("a = " .. a)
  for _ = 1, a, 1 do
    str =  " " .. str
  end
  for _ = 1, b, 1 do
    str =  str .. " "
  end
  --print ("str len = " .. #str)
  end
  return str
end -- function end
  </nowiki>
----
===PadR()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function PadR(str, len)                        -- Adds spaces to Back of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "KPSDFKSPSK  "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = str .. " "
  end
  return str
end -- function end</nowiki>
----
===PadL()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function PadL(str, len)              -- Adds spaces to Front of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "  KPSDFKSPSK"
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = " " .. str
  end
  return str
end -- function end</nowiki>
----
===NumberPad()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function NumberPad(str, front, back) -- Adds spaces to front and zeros to the back of string
  local mychar
  local  a,b,c,d = 0,0,0,0
  local x,y,z = "","",""
  if type(str) ~= "string" then
    str = tostring(str)
  end
  c = string.len(str)
  for i = 1, c, 1 do
    mychar = string.byte(string.sub(str, i,i))
    if mychar == 46 then
      b = i
    end
  end
--  print("b = " .. b)
  if b == 0 then
    str = str .. "."
    c = c + 1
    b = c
  end -- if loc
  x = string.sub(str, 1, b-1)
  y = string.sub(str, b+1)
  a = c - b
  a = #x
  d = #y
  if a < front then
    front = front - (a - 1)
    for _ = 1, front -1 do
      x = " " .. x
    end -- end for front
  end
  back = back - (c - b)
  for i = 1, back  do
    y = y .. "0"
  end -- end for back
  str =  x .. "." .. y
  return str
end -- function end
  </nowiki>
----
===All_Trim()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function All_Trim(s)                          -- Trims spaces off both ends of a string
  return s:match( "^%s*(.-)%s*$" )
end -- function end
  </nowiki>
----
===MakeProperCase()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function MakeProperCase(str)
  local str=string.gsub(string.lower(str),"^(%w)", string.upper)
  return string.gsub(str,"([^%w]%w)", string.upper)
end
  </nowiki>
----
===ifT()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function ifT(x)                                -- Converts Boolean True or False to String "Yes" or "No"
-- ===ifT(x)===
  if x then
    return "Yes"
  else
    return "No"
  end-- if end
end -- function end
  </nowiki>
----
===ifY()===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function ifY(x)                                -- Converts String "Yes" or "No" to Boolean True or False
-- ===ifY(x)===
  if string.upper(x) == "YES" then
     return true
     return true
end -- end function
  else
-- =====================================================]]
    return false
   function CreateVCarvingToolpath(name, start_depth, flat_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
  end-- if end
    --[[ -------------- CreateVCarvingToolpath --------------
end -- function end</nowiki>
    |
 
    | Create a VCarving toolpath within the program for the currently selected vectors
==Seed Documents==
    | Parameters:
[https://jimandi.com/SDK/index.php/JimAndi_Toolbox (top)]
    | name, -- Name for toolpath
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
    | start_depth -- Start depth for toolpath below surface of material
 
    | flat_depth -- flat depth - if 0.0 assume not doing flat bottom
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
    | vbit_angle -- angle of vbit to use
 
    | vbit_dia -- diameter of VBit to use
<nowiki>-- =====================================================]]
    | vbit_stepdown -- stepdown for tool
╔═╗╔═╗╔═╗╔╦╗  ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔
    | tool_stepover_percent - percentage stepover for tool
╚═╗║╣ ║╣  ║║  ╠╣ ║ ║║║║║   ║ ║║ ║║║║
    | tool_in_mm -- true if tool size and stepdown are in mm
╚═╝╚═╝╚═╝═╩╝  ╚  ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝
    |
-- =====================================================]]
    | Return Values:
  -- VECTRIC LUA SCRIPT
    | true if toolpath created OK else false
-- =====================================================]]
    |
-- Gadgets are an entirely optional add-in to Vectric's core software products.
  ]]
-- They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.
  -- Create tool we will use to machine vectors
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.
    local tool = Tool("Lua VBit",Tool.VBIT )-- BALL_NOSE, END_MILL, VBIT
-- Permission is granted to anyone to use this software for any purpose,
    tool.InMM = tool_in_mm
-- including commercial applications, and to alter it and redistribute it freely,
    tool.ToolDia = vbit_dia
-- subject to the following restrictions:
    tool.Stepdown = vbit_stepdown
-- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
    tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
-- 2. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
-- 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
    tool.FeedRate = 30
-- 4. This notice may not be removed or altered from any source distribution.
    tool.PlungeRate = 10
-- Easy Seed Gadget Master is written by Jim Anderson of Houston Texas 2020
    tool.SpindleSpeed = 20000
-- =====================================================]]
    tool.ToolNumber = 1
-- require("mobdebug").start()
    tool.VBit_Angle = 90.0 -- used for vbit only
-- require "strict"
    tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
local Tools
    -- Create object used to set home position and safez gap above material surface
-- Global Variables --
    local pos_data = ToolpathPosData()
local Ver = "1.0-- Version 7: Aug 2021 - Clean Up and added Ver to Dialog
    -- vcarve_data:SetHomePosition(0, 0, 1.0)
 
    vcarve_data:SetHomePosition(Milling.HomeX, Milling.HomeY, Milling.HomeZGap )
-- Table Names
    -- vcarve_data.SafeZGap = 0.5
Milling = {}
    vcarve_data.SafeZGap = Milling.SafeZGap
Project = {}
    -- Create object used to pass pocketing options - used for area clearance only
-- =====================================================]]
    local vcarve_data = VCarveParameterData()
function main(script_path)
    -- start depth for toolpath
--[[
    vcarve_data.StartDepth = start_depth
Gadget Notes: Dec 2019 - My New Gadget
    -- flag indicating if we are creating a flat bottomed toolpath
 
    vcarve_data.DoFlatBottom = flat_depth > 0.0
  ]]
    -- cut depth for toolpath this is depth below start depth
-- Localized Variables --
    vcarve_data.FlatDepth = flat_depth
 
    -- if true in Aspire, project toolpath onto composite model
-- Job Validation --
    vcarve_data.ProjectToolpath = false
  local job = VectricJob()
    -- set flag indicating we are using flat tool
  if not job.Exists then
    vcarve_data.UseAreaClearTool = true
     DisplayMessageBox("Error: No job loaded")
    -- Create object used to pass pocketing options - used for area clearance only
     return false
    local pocket_data = PocketParameterData()
  end
     -- start depth for toolpath
 
     pocket_data.StartDepth = start_depth
  Tools = assert(loadfile(script_path .. "\\EasyGearToolsVer" .. Ver .. ".xlua")) (Tools) -- Load Tool Function
    -- cut depth for toolpath this is depth below start depth
-- Get Data --
    pocket_data.CutDepth = flat_depth
 
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION
-- Calculation --
    -- or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
 
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
-- Do Something --
    -- if true use raster clearance strategy , else use offset area clearance
 
    pocket_data.DoRasterClearance = false
 
    -- set flag indicating we are using flat tool
  return true
    pocket_data.UseAreaClearTool = true
end  -- function end</nowiki>
    -- angle for raster if using raster clearance
 
    pocket_data.RasterAngle = 0
==Setup Tools==
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
 
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
<nowiki>-- =====================================================]]
    local create_2d_previews = true
╔═╗╔═╗╔╦╗╦ ╦╔═╗
    -- if this is true we will display errors and warning to the user
╚═╗║╣  ║ ║ ║╠═╝
    local display_warnings = true
╚═╝╚═╝ ╩ ╚═╝╩
    -- if we are doing two tool pocketing define tool to use for area clearance
function SetupAndLetter Seeds()
    local area_clear_tool = nil
    -- we just create a 10mm end mill
    area_clear_tool = Tool("Lua Clearance End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    area_clear_tool.InMM = true
    area_clear_tool.ToolDia = 10
    area_clear_tool.Stepdown = 3
    area_clear_tool.Stepover = 3
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    area_clear_tool.FeedRate = 30
    area_clear_tool.PlungeRate = 10
    area_clear_tool.SpindleSpeed = 20000
    area_clear_tool.ToolNumber = 2
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateVCarvingToolpath(name,tool,area_clear_tool,vcarve_data,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
-- =====================================================]]
-- =====================================================]]
   function CreatePrismToolpath(name, start_depth, cut_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
   function LUA_Seed()
  --[[ ------------------- CreatePrismToolpath -------------------
    -- VECTRIC LUA SCRIPT
  |
    -- ==============================================================================
  | Create a prism toolpath within the program for the currently selected vectors
    -- Gadgets are an entirely optional add-in to Vectric's core software products.
  | Parameters:
    -- They are provided 'as-is', without any express or implied warranty, and you
  | name, -- Name for toolpath
    -- make use of them entirely at your own risk.
  | start_depth -- Start depth for toolpath below surface of material
    -- In no event will the author(s) or Vectric Ltd. be held liable for any damages
  | cut_depth -- cut depth for drilling toolpath
    -- arising from their use.
  | vbit_angle -- angle of vbit to use
    -- Permission is granted to anyone to use this software for any purpose,
  | vbit_dia -- diameter of VBit to use
    -- including commercial applications, and to alter it and redistribute it freely,
  | vbit_stepdown -- stepdown for tool
    -- subject to the following restrictions:
  | tool_stepover_percent - percentage stepover for tool
    -- 1. The origin of this software must not be misrepresented;
  | tool_in_mm -- true if tool size and stepdown are in mm
    --     you must not claim that you wrote the original software.
  |
    --     If you use this software in a product, an acknowledgement in the product
  | Return Values:
     --     documentation would be appreciated but is not required.
  | true if toolpath created OK else false
     -- 2. Altered source versions must be plainly marked as such, and
  |
     --     must not be misrepresented as being the original software.
  ]]
     --  3. This notice may not be removed or altered from any source distribution.
     -- Create tool we will use to machine vectors
     -- ==============================================================================
     local tool = Tool("Lua VBit", Tool.VBIT ) -- BALL_NOSE, END_MILL, VBIT
     -- "AppName Here" was written by JimAndi Gadgets of Houston Texas
     tool.InMM = tool_in_mm
     -- ==============================================================================
     tool.ToolDia = vbit_dia
     -- =====================================================]]
     tool.Stepdown = vbit_stepdown
     -- require("mobdebug").start()
    tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
     -- require "strict"
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
     -- =====================================================]]
    tool.FeedRate = 30
     -- Global variables
    tool.PlungeRate = 10
     -- =====================================================]]
    tool.SpindleSpeed = 20000
  end -- lua function
    tool.ToolNumber = 1
-- =====================================================]]
     tool.VBit_Angle = 90.0 -- used for vbit only
  function Install_letter()
     tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
  -- Steps to Install:
     -- Create object used to set home position and safez gap above material surface
 
     local pos_data = ToolpathPosData()
  -- 1. Download the gadget x.zip that is attached to this post.
    pos_data:SetHomePosition(0, 0, 1.0)
  -- 2. Rename it from x.zip to x.vgadget
     pos_data.SafeZGap = 5.0
  -- 3. In Vectric Pro or Aspire click on Gadgets -> Install Gadget and navigate to where you downloaded the file to, select it and click Ok.
     -- Create object used to pass profile options
 
    local prism_data = PrismCarveParameterData()
  -- It should give you a pop up saying the gadget was installed and you should see x in the Gadgets menu.
     -- start depth for toolpath
 
     prism_data.StartDepth = start_depth
  -- Image Here
    -- cut depth for toolpath this is depth below start depth
 
    prism_data.CutDepth = cut_depth
  -- Steps for Use:
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION
  -- 1. Select a layer that you want to calculate for
    -- or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
  -- 2. Enter the cut depth
    prism_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
  -- 3. Enter the percentage of coverage for the area that will be filled in
    -- calculate the minimum cut depth to fully form the bevel on the current
  -- 4. Enter the hardner to resin percentage
    -- selection with the current tool
  -- 5. Click the Calculate Button and the results will be displayed below in the Results Pane.
    local min_bevel_depth = prism_data:CalculateMinimumBevelDepth(tool, true)
  end -- install function
    if min_bevel_depth > cut_depth then
 
      DisplayMessageBox("A prism will not be fully formed with a depth of " .. cut_depth .. "\r\n" ..
end -- Header function
                        "A depth of " .. min_bevel_depth .. " is required to fully form the prism"
                        )
    end -- if end
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreatePrismCarvingToolpath(name, tool, prism_data, pos_data, geometry_selector, create_2d_previews, display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end -- if end
    return true
end -- end function
-- =====================================================]]
-- =====================================================]]
  function CreateFlutingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
 
     --[[ ----------------- CreateFlutingToolpath -----------------
</nowiki>
  | Create a flutting toolpath within the program for the currently selected vectors
 
  | Parameters:
==Toolpathing Tools==
  | name, -- Name for toolpath
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
  | start_depth -- Start depth for toolpath below surface of material
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
  | cut_depth -- cut depth for toolpath
 
  | tool_dia -- diameter of tool to use
----
  | tool_stepdown -- stepdown for tool
 
  | tool_in_mm -- true if tool size and stepdown are in mm
===CreateLayerProfileToolpath===
  |
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  | Return Values:
<nowiki>function CreateLayerProfileToolpath(name, layer_name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
  | true if toolpath created OK else false
     -- clear current selection
  |
    local selection = job.Selection
  ]]
    selection:Clear()
    -- get layer
    local layer = job.LayerManager:FindLayerWithName(layer_name)
    if layer == nil then
      DisplayMessageBox("No layer found with name = " .. layer_name)
      return false
    end
    -- select all closed vectors on the layer
    if not SelectVectorsOnLayer(layer, selection, true, false, true) then
      DisplayMessageBox("No closed vectors found on layer " .. layer_name)
      return false
    end
     -- Create tool we will use to machine vectors
     -- Create tool we will use to machine vectors
     local tool = Tool("Lua Ball Nose", Tool.BALL_NOSE) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
     local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
 
     tool.InMM = tool_in_mm
     tool.InMM = tool_in_mm
     tool.ToolDia = tool_dia
     tool.ToolDia = tool_dia
     tool.Stepdown = tool_stepdown
     tool.Stepdown = tool_stepdown
     tool.Stepover = tool_dia * 0.25
     tool.Stepover = tool_dia * 0.25
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
     tool.FeedRate = 30
     tool.FeedRate = 30
     tool.PlungeRate = 10
     tool.PlungeRate = 10
Line 6,286: Line 6,143:
     pos_data:SetHomePosition(0, 0, 1.0)
     pos_data:SetHomePosition(0, 0, 1.0)
     pos_data.SafeZGap = 5.0
     pos_data.SafeZGap = 5.0
     -- Create object used to pass fluting options
     -- Create object used to pass profile options
     local fluting_data = FlutingParameterData()
     local profile_data = ProfileParameterData()
     -- start depth for toolpath
     -- start depth for toolpath
     fluting_data.StartDepth = start_depth
     profile_data.StartDepth = start_depth
     -- cut depth for toolpath this is depth below start depth
     -- cut depth for toolpath this is depth below start depth
     fluting_data.CutDepth = cut_depth
     profile_data.CutDepth = cut_depth
     -- type of fluting FULL_LENGTH, RAMP_START or RAMP_START_END
     -- direction of cut - ProfileParameterData.
     fluting_data.FluteType = FlutingParameterData.RAMP_START_END
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
     -- type of ramping RAMP_LINEAR, RAMP_SMOOTH
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
     fluting_data.RampType = FlutingParameterData.RAMP_LINEAR
    -- side we machine on - ProfileParameterData.
     -- if true use ratio field for controling ramp length else absolute length value
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
     fluting_data.UseRampRatio = false
     -- ProfileParameterData.PROFILE_ON
     -- length of ramp as ratio of flute length(range 0 - 1.0)
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
     -- (for start and end - ratio is of half length)
     -- Allowance to leave on when machining
     fluting_data.RampRatio = 0.2
     profile_data.Allowance = 0.0
     -- length to ramp over - if UseRampRatio == false
     -- true to preserve start point positions, false to reorder start
     fluting_data.RampLength = 15
    -- points to minimise toolpath length
     profile_data.KeepStartPoints = false
    -- true if want to create 'square' external corners on toolpath
    profile_data.CreateSquareCorners = false
     -- true to perform corner sharpening on internal corners (only with v-bits)
    profile_data.CornerSharpen = false
     -- true to use tabs (position of tabs must already have been defined on vectors)
     profile_data.UseTabs = false
     -- length for tabs if being used
    profile_data.TabLength = 5.0
    -- Thickness for tabs if being used
    profile_data.TabThickness = 1.0
    -- if true then create 3d tabs else 2d tabs
     profile_data.Use3dTabs = true
     -- if true in Aspire, project toolpath onto composite model
     -- if true in Aspire, project toolpath onto composite model
     fluting_data.ProjectToolpath = false
     profile_data.ProjectToolpath = false
    -- Create object used to control ramping
    local ramping_data = RampingData()
    -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
    -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
    -- or RampingData.CONSTRAIN_ANGLE
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
    -- if we are constraining ramp by distance, distance to ramp over
    ramping_data.RampDistance = 100.0
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
     -- Create object which can be used to automatically select geometry
     -- Create object which can be used to automatically select geometry
     local geometry_selector = GeometrySelector()
     local geometry_selector = GeometrySelector()
Line 6,313: Line 6,218:
     -- Create our toolpath
     -- Create our toolpath
     local toolpath_manager = ToolpathManager()
     local toolpath_manager = ToolpathManager()
     local toolpath_id = toolpath_manager:CreateFlutingToolpath(name, tool, fluting_data, pos_data, geometry_selector, create_2d_previews, display_warnings)
     local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
     if toolpath_id == nil then
     if toolpath_id == nil then
       DisplayMessageBox("Error creating toolpath")
       DisplayMessageBox("Error creating toolpath")
       return false
       return false
    else
      return true
     end
     end
    return true
end -- end function</nowiki>


    end -- end function
----
-- =====================================================]]
 
  function SelectVectorsOnLayer(layer, selection, select_closed, select_open, select_groups)
===CreateProfileToolpath===
     -- Please Note: SelectVectorsOnLayer is provided by Vectric and can be found in the SDK and Sample Gadget files.
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
     --[[  ---------------- SelectVectorsOnLayer ----------------
<nowiki>function CreateProfileToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
     -- |  SelectVectorsOnLayer("Stringer Profile", selection, true, falus, falus)
     -- Create tool we will use to machine vectors
     -- |  Add all the vectors on the layer to the selection
     local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
     -- |     layer,            -- layer we are selecting vectors on
    tool.InMM = tool_in_mm
     -- |     selection        -- selection object
    tool.ToolDia = tool_dia
     -- |     select_closed     -- if true select closed objects
    tool.Stepdown = tool_stepdown
     -- |     select_open      -- if true select open objects
    tool.Stepover = tool_dia * 0.25
     -- |     select_groups     -- if true select grouped vectors (irrespective of open / closed state of member objects)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
     -- |  Return Values:
    tool.FeedRate = 30
     -- |    true if selected one or more vectors|
    tool.PlungeRate = 10
     --]]
    tool.SpindleSpeed = 20000
     local objects_selected = false
    tool.ToolNumber = 1
     local warning_displayed = false
    tool.VBit_Angle = 90.0 -- used for vbit only
     local pos = layer:GetHeadPosition()
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
     while pos ~= nil do
    -- Create object used to set home position and safez gap above material surface
      local object
    local pos_data = ToolpathPosData()
      object, pos = layer:GetNext(pos)
    pos_data:SetHomePosition(0, 0, 1.0)
      local contour = object:GetContour()
    pos_data.SafeZGap = 5.0
      if contour == nil then
    -- Create object used to pass profile options
        if (object.ClassName == "vcCadObjectGroup") and select_groups then
    local profile_data = ProfileParameterData()
          selection:Add(object, true, true)
    -- start depth for toolpath
          objects_selected = true
    profile_data.StartDepth = start_depth
        else
    -- cut depth for toolpath this is depth below start depth
          if not warning_displayed then
    profile_data.CutDepth = cut_depth
            local message = "Object(s) without contour information found on layer - ignoring"
    -- direction of cut - ProfileParameterData.
            if not select_groups then
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
              message = message ..  "\r\n\r\n" ..
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
              "If layer contains grouped vectors these must be ungrouped for this script"
    -- side we machine on - ProfileParameterData.
            end -- if end
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
            DisplayMessageBox(message)
    -- ProfileParameterData.PROFILE_ON
            warning_displayed = true
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
          end -- if end
    -- Allowance to leave on when machining
        end -- if end
    profile_data.Allowance = 0.0
      else  -- contour was NOT nil, test if Open or Closed
     -- true to preserve start point positions, false to reorder start
        if contour.IsOpen and select_open then
     -- points to minimise toolpath length
          selection:Add(object, true, true)
    profile_data.KeepStartPoints = false
          objects_selected = true
     -- true if want to create 'square' external corners on toolpath
        elseif select_closed then
    profile_data.CreateSquareCorners = false
          selection:Add(object, true, true)
     -- true to perform corner sharpening on internal corners (only with v-bits)
          objects_selected = true
    profile_data.CornerSharpen = false
        end -- if end
     -- true to use tabs (position of tabs must already have been defined on vectors)
      end -- if end
    profile_data.UseTabs = false
     end -- while end
     -- length for tabs if being used
     -- to avoid excessive redrawing etc we added vectors to the selection in 'batch' mode
    profile_data.TabLength = 5.0
     -- tell selection we have now finished updating
     -- Thickness for tabs if being used
     if objects_selected then
     profile_data.TabThickness = 1.0
       selection:GroupSelectionFinished()
     -- if true then create 3d tabs else 2d tabs
     end -- if end
     profile_data.Use3dTabs = true
     return objects_selected
     -- if true in Aspire, project toolpath onto composite model
  end -- function end
    profile_data.ProjectToolpath = false
-- ====================================================[[Category:SDK]]
     -- Create object used to control ramping
==Table and Array Tools==
     local ramping_data = RampingData()
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
     -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
     -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
     -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
     -- or RampingData.CONSTRAIN_ANGLE
     ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
     -- if we are constraining ramp by distance, distance to ramp over
     ramping_data.RampDistance = 100.0
     -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
     local create_2d_previews = true
     -- if this is true we will display errors and warning to the user
    local display_warnings = true
     -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
     if toolpath_id == nil then
       DisplayMessageBox("Error creating toolpath")
      return false
     end
     return true
end -- end function</nowiki>


==== JimAndi Toolbox ====
----


</nowiki>
===CreatePocketingToolpath===
-- =====================================================]]
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
  <nowiki>
  <nowiki>function CreatePocketingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_stepover_percent, tool_in_mm)
 
   -- Create tool we will use to machine vectors
╔╦╗╔═╗╔╗ ╦  ╔═╗  ╔═╗╔╗╔╔╦╗  ╔═╗╦═╗╦═╗╔═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
    local tool = Tool("Lua End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
   ║ ╠═╣╠╩╗║  ║╣  ╠═╣║║║ ║║  ╠═╣╠╦╝╠╦╝╠═╣╚╦╝  ║ ║ ║║ ║║  ╚═╗
    tool.InMM = tool_in_mm
  ╩ ╩ ╩╚═╝╩═╝╚═╝  ╩ ╩╝╚╝═╩╝  ╩ ╩╩╚═╩╚═╩ ╩ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
    tool.ToolDia = tool_dia
function ArrayTools()
    tool.Stepdown = tool_stepdown
 
    tool.Stepover = tool_dia * (tool_stepover_percent / 100)
</nowiki>
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC,...
-- =====================================================]]
    tool.FeedRate = 30
<nowiki>
    tool.PlungeRate = 10
 
    tool.SpindleSpeed = 20000
  function ArrayClear(arrayName)
    tool.ToolNumber = 1
    for _,v in ipairs(arrayName) do
    tool.VBit_Angle = 90.0 -- used for vbit only
      table.remove(arrayName, i)
    tool.ClearStepover = tool_dia * (tool_stepover_percent / 100) -- used for vbit only
    end -- for end
    -- Create object used to set home position and safez gap above material surface
    return true
    local pos_data = ToolpathPosData()
  end -- function end
    pos_data:SetHomePosition(0, 0, 1.0)
 
    pos_data.SafeZGap = 5.0
</nowiki> 
    -- Create object used to pass pocketing options
-- =====================================================]]
    local pocket_data = PocketParameterData()
<nowiki>
    -- start depth for toolpath
 
    pocket_data.StartDepth = start_depth
  function NameCheck(Name, Defalt, ListName)              -- Checks if Name in in the list of it is default name
    -- cut depth for toolpath this is depth below start depth
    if Name ~= Defalt then
    pocket_data.CutDepth = cut_depth
      for i=1, ListName do
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or
        if Name == i then
    -- ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
          return true
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
        end
    -- Allowance to leave on when machining
      end
    pocket_data.Allowance = 0.0
      return false
    -- if true use raster clearance strategy , else use offset area clearance
    else
    pocket_data.DoRasterClearance = true
      return  true
    -- angle for raster if using raster clearance
    end
    pocket_data.RasterAngle = 0
  end -- NameCheck function end
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
 
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
</nowiki> 
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
-- =====================================================]]
    -- if true we ramp into pockets (always zig-zag)
<nowiki>
    pocket_data.DoRamping = false
 
    -- if ramping, distance to ramp over
  function RemoveDuplicates(tab, order)                   -- returns table of unique items in "A" acending or "D" decending
    pocket_data.RampDistance = 10.0
    local hashSet = {}
    -- if true in Aspire, project toolpath onto composite model
    local new = {}
    pocket_data.ProjectToolpath = false
    local value
    -- Create object which can be used to automatically select geometry
    for i = 1, #tab do
    local geometry_selector = GeometrySelector()
      value = (tab[i])
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
      if hashSet[value] == nil then
    local create_2d_previews = true
        table.insert(new, value)
    -- if this is true we will display errors and warning to the user
        hashSet[value] = true
    local display_warnings = true
      end
    -- if we are doing two tool pocketing define tool to use for area clearance
    end
    local area_clear_tool = nill
    if string.upper(order) =="A" then
    -- we just create a tool twice as large for testing here
      table.sort(new)
    area_clear_tool = Tool("Lua Clearance End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    else
    area_clear_tool.InMM = tool_in_mm
      table.sort(new, function(a, b) return a > b end)
    area_clear_tool.ToolDia = tool_dia * 2
    end
    area_clear_tool.Stepdown = tool_stepdown * 2
    return new
    area_clear_tool.Stepover = tool_dia * 2 *(tool_stepover_percent / 100)
  end
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC..
 
    area_clear_tool.FeedRate = 30
</nowiki>    
    area_clear_tool.PlungeRate = 10
-- =====================================================]]
    area_clear_tool.SpindleSpeed = 20000
<nowiki>
    area_clear_tool.ToolNumber = 1
 
    area_clear_tool.VBit_Angle = 90.0 -- used for vbit only
  function RemoveTableItem(tabName, tabItem)
    area_clear_tool.ClearStepover = tool_dia*2*(tool_stepover_percent/100) -- used for vbit
    for x = 1 in ipairs(tabName) do
   -- Create our toolpath
      if tabName[x] == tabItem then
    local toolpath_manager = ToolpathManager()
          table.remove(tabName, i)
    local toolpath_id = toolpath_manager:CreatePocketingToolpath(name,tool,area_clear_tool,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
      end
    if toolpath_id == nill then
    end -- for end
      DisplayMessageBox("Error creating toolpath")
    return true
      return false
  end -- function end
    end
    return true
end -- end function</nowiki>


</nowiki> 
----
-- =====================================================]]
<nowiki>


  function TableLength(tbl)                              -- tbl returns table count
===CreateDrillingToolpath===
    -- tbl = {7, 6, 5, 4, 3, 2, 1}
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    local count = 0
<nowiki>function CreateDrillingToolpath(name, start_depth, cut_depth, retract_gap, tool_dia, tool_stepdown, tool_in_mm)
    for _ in pairs(tbl) do
  -- Create tool we will use to machine vectors
      count = count + 1
    local tool = Tool("Lua Drill", Tool.THROUGH_DRILL) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
    end
    tool.InMM = tool_in_mm
    return count
    tool.ToolDia = tool_dia
  end
    tool.Stepdown = tool_stepdown
 
    tool.Stepover = tool_dia * 0.25
</nowiki> 
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
-- =====================================================]]
    tool.FeedRate = 30
<nowiki>
    tool.PlungeRate = 10
 
    tool.SpindleSpeed = 20000
  function FindDups(checktbl, duptbl, cleantbl)           -- Find all duplicate items and returns both dup and clean tables
    tool.ToolNumber = 1
    function tLength(tbl) -- tLength returns table count
    tool.VBit_Angle = 90.0 -- used for vbit only
      local count = 0
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
      for _ in pairs(tbl) do
    -- Create object used to set home position and safez gap above material surface
        count = count + 1
    local pos_data = ToolpathPosData()
      end
    pos_data:SetHomePosition(0, 0, 1.0)
      return count
    pos_data.SafeZGap = 5.0
    end
    -- Create object used to pass profile options
    -- =================================
    local drill_data = DrillParameterData()
    local trip = false
    -- start depth for toolpath
    for i=1, tLength(checktbl) do
    drill_data.StartDepth = start_depth
      for x=1, tLength(cleantbl) do
    -- cut depth for toolpath this is depth below start depth
        if cleantbl[x] == checktbl[i] then
    drill_data.CutDepth = cut_depth
          trip = true
    -- if true perform peck drilling
        end
    drill_data.DoPeckDrill = retract_gap > 0.0
      end
    -- distance to retract above surface when peck drilling
      if trip then
    drill_data.PeckRetractGap = retract_gap
        table.insert(duptbl,   checktbl[i])
    -- if true in Aspire, project toolpath onto composite model
      else
    drill_data.ProjectToolpath = false
        table.insert(cleantbl, checktbl[i])
    -- Create object which can be used to automatically select geometry
      end
    local geometry_selector = GeometrySelector()
      trip = false
    -- if this is true we create 2d toolpaths previews in 2d view,
    end
    -- if false we dont
    return table.sort(duptbl), table.sort(cleantbl) -- returns both dup and clean table
    local create_2d_previews = true
  end -- function end
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateDrillingToolpath(name,tool,drill_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function</nowiki>


</nowiki> 
----
-- =====================================================]]
<nowiki>


  function ReverseTable(tbl)                              -- Reverse table order
===CreateVCarvingToolpath===
    --tbl = {7, 6, 7, A, 5, 4, 3, A, 2, 1}
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
    local n = #tbl
  <nowiki>function CreateVCarvingToolpath(name, start_depth, flat_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
    local i = 1
    --[[ -------------- CreateVCarvingToolpath --------------
    while i < n do
    |
      tbl[i],tbl[n] = tbl[n],tbl[i]
    | Create a VCarving toolpath within the program for the currently selected vectors
      i = i + 1
    | Parameters:
      n = n - 1
    | name, -- Name for toolpath
    end
    | start_depth -- Start depth for toolpath below surface of material
    return tbl
    | flat_depth -- flat depth - if 0.0 assume not doing flat bottom
  end
    | vbit_angle -- angle of vbit to use
 
    | vbit_dia -- diameter of VBit to use
  </nowiki>  
    | vbit_stepdown -- stepdown for tool
-- =====================================================]]
    | tool_stepover_percent - percentage stepover for tool
<nowiki>
    | tool_in_mm -- true if tool size and stepdown are in mm
 
    |
end -- ArrayTools function end
    | Return Values:
    | true if toolpath created OK else false
 
    |
==Conversion Tools==
   ]]
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
   -- Create tool we will use to machine vectors
 
    local tool = Tool("Lua VBit",Tool.VBIT )-- BALL_NOSE, END_MILL, VBIT
<nowiki>
    tool.InMM = tool_in_mm
    tool.ToolDia = vbit_dia
 
    tool.Stepdown = vbit_stepdown
</nowiki>
     tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
-- =====================================================]]
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
<nowiki>
     tool.FeedRate = 30
 
     tool.PlungeRate = 10
╔═╗╔═╗╔╗╔╦  ╦╔═╗╦═╗╔╦╗╦╔═╗╔╗╔  ╔╦╗╔═╗╔═╗╦  ╔═╗
     tool.SpindleSpeed = 20000
║  ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ ║║ ║║║║   ║ ║ ║║ ║║  ╚═╗
     tool.ToolNumber = 1
╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ╩╚═╝╝╚╝   ╩ ╚═╝╚═╝╩═╝╚═╝
     tool.VBit_Angle = 90.0 -- used for vbit only
function ConvertingTools()
     tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
-- ====================================================]]
function bool2S(x)                                    -- Converts true or false to text
  if x then
    return "true"
  else
    return "false"
  end
end --function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function D2S8(d)                                        --  Converts a Number (Double) to a String with 8 places
  return string.format("%.8f", d)
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function D2S4(d)                                        --  Converts a Number (Double) to a String with 4 places
  return string.format("%.4f", d)
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function toint(number)
  return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Rounder(num, idp)                              --  Rounds a Number (Double) up or down
  return tonumber(string.format("%." .. (idp or 0) .. "f", num))
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RUsame(num, comp)                              --  Rounds a Number (Double) up or down
  local function toint(number)
    return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
  end
  local function Rounder(num, idp)                      --  Rounds a Number (Double) up or down
    return tonumber(string.format("%." .. (idp or 0) .. "f", num))
  end -- end function
        num = math.abs(num)
  local idp = #comp
  local Mynum = Rounder(num, idp)
  local Myint = toint(Mynum)
  local Myval = tonumber(tostring(Myint) .. "." .. comp)
  if (Mynum == Myval) then
    return true
  else
    return false
  end -- if end
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function WithIn(Num, Mat, Tol)                          --  Retuns true if number is within tolerance with match
  if ((Num >= (Mat - Tol)) and (Num <= (Mat + Tol))) then
    return true
  end -- if end
  return false
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Double2Fraction(Num)                          --  Converts a Measurement (Double) to a Fractional String
  local Frac = "Error"
  if Num then
    Frac = tostring(Num)
  end
  if (not Milling.Unit) and Num then
    local AmountValuex = math.floor(math.abs(Num))
    local DicValue    = Num - AmountValuex
    local AmountValue = tostring(AmountValuex)
    Frac              = tostring(DicValue)
 
    if Project.Fractions == "No Fractions" then
      Frac = tostring(Num)
 
    elseif Project.Fractions == "1/8" then
      if    DicValue >= 0.9375 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.8125 then Frac = "7/8" .. string.char(34)
      elseif DicValue >= 0.6875 then Frac = "3/4" .. string.char(34)
      elseif DicValue >= 0.5625 then Frac = "5/8" .. string.char(34)
      elseif DicValue >= 0.4375 then Frac = "1/2" .. string.char(34)
      elseif DicValue >= 0.3125 then Frac = "3/8" .. string.char(34)
      elseif DicValue >= 0.1875 then Frac = "1/4" .. string.char(34)
      elseif DicValue >= 0.0625 then Frac = "1/8" .. string.char(34)
      else
        Frac = "0"
      end
    elseif Project.Fractions == "1/16" then
      if    DicValue >= 0.96875 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.90625 then Frac = "15/16" .. string.char(34)
      elseif DicValue >= 0.84375 then Frac = "7/8"  .. string.char(34)
      elseif DicValue >= 0.78125 then Frac = "13/16" .. string.char(34)
      elseif DicValue >= 0.71875 then Frac = "3/4"  .. string.char(34)
      elseif DicValue >= 0.65625 then Frac = "11/16" .. string.char(34)
      elseif DicValue >= 0.59375 then Frac = "5/8"  .. string.char(34)
      elseif DicValue >= 0.53125 then Frac = "9/16"  .. string.char(34)
      elseif DicValue >= 0.46875 then Frac = "1/2"  .. string.char(34)
      elseif DicValue >= 0.40625 then Frac = "7/16"  .. string.char(34)
      elseif DicValue >= 0.34375 then Frac = "3/8"  .. string.char(34)
      elseif DicValue >= 0.28125 then Frac = "5/16"  .. string.char(34)
      elseif DicValue >= 0.21875 then Frac = "1/4"  .. string.char(34)
      elseif DicValue >= 0.15625 then Frac = "3/16"  .. string.char(34)
      elseif DicValue >= 0.09375 then Frac = "1/8"  .. string.char(34)
      elseif DicValue >= 0.03125 then Frac = "1/16"  .. string.char(34)
      else
        Frac = "0"
      end -- If end
    elseif Project.Fractions == "1/32" then
      if    DicValue >= 0.984375 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.953126 then Frac = "31/32" .. string.char(34)
      elseif DicValue >= 0.921876 then Frac = "15/16" .. string.char(34)
      elseif DicValue >= 0.890626 then Frac = "29/32" .. string.char(34)
      elseif DicValue >= 0.859376 then Frac = "7/8"  .. string.char(34)
      elseif DicValue >= 0.828126 then Frac = "27/32" .. string.char(34)
      elseif DicValue >= 0.796876 then Frac = "13/16" .. string.char(34)
      elseif DicValue >= 0.765626 then Frac = "25/32" .. string.char(34)
      elseif DicValue >= 0.737376 then Frac = "3/4"  .. string.char(34)
      elseif DicValue >= 0.703126 then Frac = "23/32" .. string.char(34)
      elseif DicValue >= 0.671876 then Frac = "11/16" .. string.char(34)
      elseif DicValue >= 0.640626 then Frac = "21/32" .. string.char(34)
      elseif DicValue >= 0.609376 then Frac = "5/8"  .. string.char(34)
      elseif DicValue >= 0.578126 then Frac = "19/32" .. string.char(34)
      elseif DicValue >= 0.541260 then Frac = "9/16"  .. string.char(34)
      elseif DicValue >= 0.515626 then Frac = "17/32" .. string.char(34)
      elseif DicValue >= 0.484376 then Frac = "1/2"  .. string.char(34)
      elseif DicValue >= 0.468760 then Frac = "15/32" .. string.char(34)
      elseif DicValue >= 0.421876 then Frac = "7/16"  .. string.char(34)
      elseif DicValue >= 0.390626 then Frac = "13/32" .. string.char(34)
      elseif DicValue >= 0.359376 then Frac = "3/8"  .. string.char(34)
      elseif DicValue >= 0.328126 then Frac = "11/32" .. string.char(34)
      elseif DicValue >= 0.296876 then Frac = "5/16"  .. string.char(34)
      elseif DicValue >= 0.265626 then Frac = "9/32"  .. string.char(34)
      elseif DicValue >= 0.234376 then Frac = "1/4"  .. string.char(34)
      elseif DicValue >= 0.203126 then Frac = "7/32"  .. string.char(34)
      elseif DicValue >= 0.171876 then Frac = "3/16"  .. string.char(34)
      elseif DicValue >= 0.140626 then Frac = "5/32"  .. string.char(34)
      elseif DicValue >= 0.109376 then Frac = "1/8"  .. string.char(34)
      elseif DicValue >= 0.078126 then Frac = "3/32"  .. string.char(34)
      elseif DicValue >= 0.046876 then Frac = "1/16"  .. string.char(34)
      elseif DicValue >= 0.015626 then Frac = "1/32"  .. string.char(34)
      else
        Frac = "0"
      end -- If end
    elseif Project.Fractions == "1/64" then
      if    DicValue >= 0.9921875 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
        elseif DicValue >= 0.9765625 then Frac = "62/64" .. string.char(34)
        elseif DicValue >= 0.9609375 then Frac = "31/32" .. string.char(34)
        elseif DicValue >= 0.9453125 then Frac = "61/64" .. string.char(34)
        elseif DicValue >= 0.9296875 then Frac = "15/16" .. string.char(34)
        elseif DicValue >= 0.9140625 then Frac = "59/64" .. string.char(34)
        elseif DicValue >= 0.8984375 then Frac = "29/32" .. string.char(34)
        elseif DicValue >= 0.8828125 then Frac = "57/64" .. string.char(34)
        elseif DicValue >= 0.8671875 then Frac = "7/8"  .. string.char(34)
        elseif DicValue >= 0.8515625 then Frac = "55/64" .. string.char(34)
        elseif DicValue >= 0.8359375 then Frac = "27/32" .. string.char(34)
        elseif DicValue >= 0.8203125 then Frac = "53/64" .. string.char(34)
        elseif DicValue >= 0.8046875 then Frac = "13/16" .. string.char(34)
        elseif DicValue >= 0.7890625 then Frac = "51/64" .. string.char(34)
        elseif DicValue >= 0.7734375 then Frac = "25/32" .. string.char(34)
        elseif DicValue >= 0.7578125 then Frac = "49/64" .. string.char(34)
        elseif DicValue >= 0.7421875 then Frac = "3/4"  .. string.char(34)
        elseif DicValue >= 0.7265625 then Frac = "47/64" .. string.char(34)
        elseif DicValue >= 0.7109375 then Frac = "23/32" .. string.char(34)
        elseif DicValue >= 0.6953125 then Frac = "45/64" .. string.char(34)
        elseif DicValue >= 0.6796875 then Frac = "11/16" .. string.char(34)
        elseif DicValue >= 0.6640625 then Frac = "43/64" .. string.char(34)
        elseif DicValue >= 0.6484375 then Frac = "21/32" .. string.char(34)
        elseif DicValue >= 0.6328125 then Frac = "41/64" .. string.char(34)
        elseif DicValue >= 0.6171875 then Frac = "5/8"  .. string.char(34)
        elseif DicValue >= 0.6015625 then Frac = "39/64" .. string.char(34)
        elseif DicValue >= 0.5859375 then Frac = "19/32" .. string.char(34)
        elseif DicValue >= 0.5703125 then Frac = "37/64" .. string.char(34)
        elseif DicValue >= 0.5546875 then Frac = "9/16"  .. string.char(34)
        elseif DicValue >= 0.5390625 then Frac = "35/64" .. string.char(34)
        elseif DicValue >= 0.5234375 then Frac = "17/32" .. string.char(34)
        elseif DicValue >= 0.5078125 then Frac = "33/64" .. string.char(34)
        elseif DicValue >= 0.4921875 then Frac = "1/2"  .. string.char(34)
        elseif DicValue >= 0.4765625 then Frac = "31/64" .. string.char(34)
        elseif DicValue >= 0.4609375 then Frac = "15/32" .. string.char(34)
        elseif DicValue >= 0.4453125 then Frac = "29/32" .. string.char(34)
        elseif DicValue >= 0.4296875 then Frac = "7/16"  .. string.char(34)
        elseif DicValue >= 0.4140625 then Frac = "27/64" .. string.char(34)
        elseif DicValue >= 0.3984375 then Frac = "13/32" .. string.char(34)
        elseif DicValue >= 0.3828125 then Frac = "25/64" .. string.char(34)
        elseif DicValue >= 0.3671875 then Frac = "3/8"  .. string.char(34)
        elseif DicValue >= 0.3515625 then Frac = "23/64" .. string.char(34)
        elseif DicValue >= 0.3359375 then Frac = "11/32" .. string.char(34)
        elseif DicValue >= 0.3203125 then Frac = "21/64" .. string.char(34)
        elseif DicValue >= 0.3046875 then Frac = "5/16"  .. string.char(34)
        elseif DicValue >= 0.2890625 then Frac = "19/64" .. string.char(34)
        elseif DicValue >= 0.2734375 then Frac = "9/32"  .. string.char(34)
        elseif DicValue >= 0.2578125 then Frac = "17/64" .. string.char(34)
        elseif DicValue >= 0.2421875 then Frac = "1/4"  .. string.char(34)
        elseif DicValue >= 0.2265625 then Frac = "15/64" .. string.char(34)
        elseif DicValue >= 0.2109375 then Frac = "7/32"  .. string.char(34)
        elseif DicValue >= 0.1953125 then Frac = "13/64" .. string.char(34)
        elseif DicValue >= 0.1796875 then Frac = "3/16"  .. string.char(34)
        elseif DicValue >= 0.1640625 then Frac = "11/64" .. string.char(34)
        elseif DicValue >= 0.1484375 then Frac = "5/32"  .. string.char(34)
        elseif DicValue >= 0.1328125 then Frac = "9/64"  .. string.char(34)
        elseif DicValue >= 0.1171875 then Frac = "1/8"  .. string.char(34)
        elseif DicValue >= 0.1015625 then Frac = "7/64"  .. string.char(34)
        elseif DicValue >= 0.0859375 then Frac = "3/32"  .. string.char(34)
        elseif DicValue >= 0.0703125 then Frac = "5/64"  .. string.char(34)
        elseif DicValue >= 0.0546875 then Frac = "1/16"  .. string.char(34)
        elseif DicValue >= 0.0390625 then Frac = "3/64"  .. string.char(34)
        elseif DicValue >= 0.0234375 then Frac = "1/32"  .. string.char(34)
        elseif DicValue >= 0.0078125 then Frac = "1/64"  .. string.char(34)
        else
          Frac = "0"
        end -- If end
      end
    if Project.Fractions == "No Fractions" then
      Frac = tostring(Num)
    else
      if Frac == "0" then
        Frac = AmountValue .. string.char(34)
      else
        if AmountValue ~= "0" then
          Frac = AmountValue .. "-" .. Frac
        end
      end
    end
  end
  return Frac
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Convert Tools end
 
</nowiki>
 
==Time and Date Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╦╔╦╗╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║ ║║║║║╣    ║ ║ ║║ ║║  ╚═╗
╩ ╩╩ ╩╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DateTimeTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function StartDateTime(LongShort)
--[[ Date Value Codes
--  |  %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %B  full month name (e.g., September)
--  |    %c  date and time (e.g., 09/16/98 23:48:10)
--  |    %d  day of the month (16) [01-31]
--  |    %H  hour, using a 24-hour clock (23) [00-23]
--  |    %I  hour, using a 12-hour clock (11) [01-12]
--  |    %M  minute (48) [00-59]
--  |    %m  month (09) [01-12]
--  |    %p  either "am" or "pm" (pm)
--  |    %S  second (10) [00-60]
--  |    %w  weekday (3) [0-6 = Sunday-Saturday]
--  |    %x  date (e.g., 09/16/98)
--  |    %X  time (e.g., 23:48:10)
--  |    %Y  full year (e.g., 1998)
--  |    %y  two-digit year (98) [00-99]
--  |    %%  the character `%´ ]]
    if LongShort then
      return os.date("%b %d, %Y") .. " - " .. os.date("%I") .. ":" .. os.date("%m") .. os.date("%p")
    else
      return os.date("%Y%m%d%H%M")
    end
  end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function StartDate(LongShort)
--[[ Date Value Codes
--  |  %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %B  full month name (e.g., September)
--  |    %c  date and time (e.g., 09/16/98 23:48:10)
--  |    %d  day of the month (16) [01-31]
--  |    %H  hour, using a 24-hour clock (23) [00-23]
--  |    %I  hour, using a 12-hour clock (11) [01-12]
--  |    %M  minute (48) [00-59]
--  |    %m  month (09) [01-12]
--  |    %p  either "am" or "pm" (pm)
--  |    %S  second (10) [00-60]
--  |    %w  weekday (3) [0-6 = Sunday-Saturday]
--  |    %x  date (e.g., 09/16/98)
--  |    %X  time (e.g., 23:48:10)
--  |    %Y  full year (e.g., 1998)
--  |    %y  two-digit year (98) [00-99]
--  |    %%  the character `%´ ]]
 
    if LongShort then
      return os.date("%b %d, %Y")  -- "Sep 01, 2022"
    else
      return os.date("%Y%m%d")    -- "20220901"
    end
  end
-- ====================================================]]
function Wait(time)
    local duration = os.time() + time
    while os.time() < duration do end
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Date Time Tools function end
 
</nowiki>
 
==Debugging Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╔═╗╔╗ ╦ ╦╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╣ ╠╩╗║ ║║ ╦  ║ ║ ║║ ║║  ╚═╗
═╩╝╚═╝╚═╝╚═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DebugTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function DMark(Note, Pt)
  --[[-- ==MarkPoint==
    | Code sourced from Vectric Lua Interface for Gadgets, version 2.05, published September 12, 2018. by Vectric Ltd.
    | Draws mark on the drawing
    | call = DebugMarkPoint("Note: Hi", Pt1)
    ]]
    local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
  --[[ draws a circle based on user inputs
    | job - current validated job unique ID
    | Cpt - (2Dpoint) center of the circle
    | CircleRadius - radius of the circle
    | Layer - layer name to draw circle (make layer if not exist)
    ]]
      local pa  = Polar2D(Cpt, 180.0, CircleRadius)
      local pb  = Polar2D(Cpt,  0.0, CircleRadius)
      local line = Contour(0.0)
      line:AppendPoint(pa); line:ArcTo(pb,1); line:ArcTo(pa,1)
      local layer = job.LayerManager:GetLayerWithName(LayerName)
      layer:AddObject(CreateCadContour(line), true)
      return true
    end -- function end
  -- ====]]
    local BubbleSize = 1.25
    if not Project.DebugAngle then
      Project.DebugAngle = 0.0
    end
    Project.DebugAngle = Project.DebugAngle + 2.0
    if Project.DebugAngle >= 90.0 and Project.DebugAngle <= 358.0 then
      Project.DebugAngle = 272.0
    elseif Project.DebugAngle >= 360.0 then
      Project.DebugAngle = 2.0
    end
    if Pt then
      local job = VectricJob()
      local Pt1 = Polar2D(Pt, Project.DebugAngle, BubbleSize)
      local Pt2 = Polar2D(Pt1, 0.0, BubbleSize * 0.25)
      local Pt3 = Polar2D(Pt2, 315.0, BubbleSize * 0.0883883476483188 * 4.0)
      local line = Contour(0.0)
      local layer = job.LayerManager:GetLayerWithName("Debug")
      line:AppendPoint(Pt)
      line:LineTo(Pt1)
      line:LineTo(Pt2)
      layer:AddObject(CreateCadContour(line), true)
      DrawWriter(Note, Pt3, BubbleSize * 0.5, "Debug", 0.0)
      DrawCircle(job, Pt, BubbleSize * 0.5, "Debug")
    else
      DisplayMessageBox("Issue with Point for - " .. Note)
    end
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function StatusMessage(Type, Header, Question, ErrorNumber)
  --[[
  Useage:          type    Header Info              Question or Message                                  Err No.
    StatusMessage("Error", "Base Cabinet Settings", "Face Frame Bottom Rail Width - value cannot be 0.", "(9000)")
    Note: if the debug flag is on (true) a message box shows the message length, dialog size and error number
  ]]
  local dialog
  local X = 460
  local Y = 124
  local step = 35
  Question = WrapString(Question, step)
  local QL = string.len(Question)
  if (QL > step) and (QL < step * 2) then
    Y = Y + 12
  elseif (QL > (step * 2) +1) and (QL < 105) then
    Y = Y + 24
  elseif (QL > (step * 3) +1) and (QL < (step * 4)) then
    Y = Y + 36
  elseif (QL > (step * 4) +1) and (QL < (step * 5)) then
    Y = Y + 48
  elseif (QL > (step * 5) +1) and (QL < (step * 6)) then
    Y = Y + 60
  elseif (QL > (step * 6) +1) and (QL < (step * 7)) then
    Y = Y + 72
  elseif (QL > (step * 7) +1) and (QL < (step * 8)) then
    Y = Y + 84
  elseif (QL > (step * 8) +1) and (QL < (step * 9)) then
    Y = Y + 96
  elseif (QL > (step * 9) +1) and (QL < (step * 10)) then
    Y = Y + 108
  elseif (QL > (step * 10) +1) and (QL < (step * 11)) then
    Y = Y + 120
  else
    Y = Y + 150
  end
  if Project.Debugger then
    Queston = Question .. " - " .. ErrorNumber
  end
  if Type == "Alert" then
    dialog = HTML_Dialog(true, DialogWindow.myHtml16, X, Y, Header)
  else -- "Error"
    dialog = HTML_Dialog(true, DialogWindow.myHtml17, X, Y, Header)
  end -- if end
  if Project.Debugger then
    Question = Question .. " " .. ErrorNumber
  end
  dialog:AddLabelField("Question", Type .. ": " .. Question)
  dialog:ShowDialog()
  if Project.Debugger then
    DisplayMessageBox("Question Len " .. " = " .. tostring(string.len(Question)) .. ": \nWindow = " .. tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight))
  end
  return true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function DebugMarkPoint(Note, Pt, Size, LayerName)
  --[[-- ==MarkPoint==
  | Code sourced from Vectric Lua Interface for Gadgets, version 2.05, published September 12, 2018. by Vectric Ltd.
  | Draws mark on the drawing
  | call = DebugMarkPoint("Note: Hi", Pt1, 0.125, "Jim")
  ]]
    if Size == nil then
      Size = 0.125
    end
    if LayerName == nil then
      LayerName = "Debug"
    end
    local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
  -- | draws a circle based on user inputs
  -- | job - current validated job unique ID
  -- | Cpt - (2Dpoint) center of the circle
  -- | CircleRadius - radius of the circle
  -- | Layer - layer name to draw circle (make layer if not exist)
      local pa = Polar2D(Cpt, 180.0, CircleRadius)
      local pb = Polar2D(Cpt,  0.0, CircleRadius)
      local line = Contour(0.0)
      line:AppendPoint(pa); line:ArcTo(pb,1);  line:ArcTo(pa,1)
      local layer = job.LayerManager:GetLayerWithName(LayerName)
      layer:AddObject(CreateCadContour(line), true)
      return true
    end -- function end
  -- ====]]
    local job = VectricJob()
    local Pt1 = Polar2D(Pt, Project.DebugAngle, Size * 2.0)
    local Pt2 = Polar2D(Pt1, 0.0, 0.500 * Size)
    local Pt3 = Polar2D(Pt2, 315.0, (0.500 * Size) * 1.4142135623731)
    local line = Contour(0.0)
    local layer = job.LayerManager:GetLayerWithName(LayerName)
    line:AppendPoint(Pt)
    line:LineTo(Pt1)
    line:LineTo(Pt2)
    layer:AddObject(CreateCadContour(line), true)
    DrawWriter(Note, Pt3, Size, LayerName, 0.0)
    DrawCircle(job, Pt, Size, LayerName)
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function ShowDialogSize()                            -- Returns Dialog X and Y size
    DisplayMessageBox(tostring(dialog.WindowWidth) .. " x " ..  tostring(dialog.WindowHeight))
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- End Debug
 
</nowiki>
 
==Dialog and Menu Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╦╔═╗╦  ╔═╗╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╠═╣║  ║ ║║ ╦  ║ ║ ║║ ║║  ╚═╗
═╩╝╩╩ ╩╩═╝╚═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DialogTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DialogSize(Str)                                -- Returns the X and Y value of the dialogue
  local InText = string.find(string.upper(Str) , "X")
  local DialogX = All_Trim(string.sub(Str, 1, InText - 1))
  local DialogY = All_Trim(string.sub(Str, InText + 1))
  return tonumber(DialogX), tonumber(DialogY)
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ProgressBarAmount(TotalRecords, Record)        -- Calculates the percent amount of progression based on total process
  --[[
  local MyProgressBar
    MyProgressBar = ProgressBar("Working", ProgressBar.LINEAR)                -- Setup Type of progress bar
    MyProgressBar:SetPercentProgress(0)                                      -- Sets progress bar to zero
    MyProgressBar:SetPercentProgress(ProgressAmount(Door.Records, myRecord))  -- sends percent of process progress bar (adds to the bar)
    MyProgressBar:SetPercentProgress(ProgressAmount(12000, 416))              -- sends percent of process progress bar (adds to the bar)
    MyProgressBar:SetText("Compete")                                          -- Sets the label to Complete
    MyProgressBar:Finished()                                                  -- Close Progress Bar
  ]]
  local X1 = (100.0 / TotalRecords)
  local X2 = X1 * Record
  local X3 = math.abs(X2)
  local X4 = (math.floor(X3))
  return (math.floor(math.abs((100.0 / TotalRecords) * Record)))
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function OnLuaButton_InquiryGearCalulate(dialog)
  Gear.Addendum        = dialog:GetDoubleField("Gear.Addendum")
  Gear.Dedendum        = dialog:GetDoubleField("Gear.Dedendum")
  Gear.AddendumDiameter = dialog:GetDoubleField("Gear.AddendumDiameter")
  Gear.DedendumDiameter = dialog:GetDoubleField("Gear.DedendumDiameter")
  Gear.ToothTickness    = dialog:GetDoubleField("Gear.ToothTickness")
  Gear.Slotwidth        = dialog:GetDoubleField("Gear.Slotwidth")
  Gear.PitchAmount      = dialog:GetDoubleField("Gear.PitchAmount")
  Gear.FilletRadius    = dialog:GetDoubleField("Gear.FilletRadius")
  Gear.ToplandAmount    = dialog:GetDoubleField("Gear.ToplandAmount")
  Gear.FaceFlankRadius  = dialog:GetDoubleField("Gear.FaceFlankRadius")
  Gear.ToothCount      = dialog:GetDropDownListValue("Gear.ToothCount")
  Gear.ShowLines        = dialog:GetDropDownListValue("Gear.ShowLines")
 
  dialog:UpdateDoubleField("Gear.Addendum",                      Gear.Addendum)
  dialog:UpdateDoubleField("Gear.Dedendum",                      Gear.Dedendum)
  dialog:UpdateDoubleField("Gear.AddendumDiameter",              Gear.AddendumDiameter)
  dialog:UpdateDoubleField("Gear.DedendumDiameter",              Gear.DedendumDiameter)
  dialog:UpdateDoubleField("Gear.ToothTickness",                Gear.ToothTickness)
  dialog:UpdateDoubleField("Gear.Slotwidth",                    Gear.Slotwidth)
  dialog:UpdateDoubleField("Gear.PitchAmount",                  Gear.PitchAmount)
  dialog:UpdateDoubleField("Gear.FilletRadius",                  Gear.FilletRadius)
  dialog:UpdateDoubleField("Gear.ToplandAmount",                Gear.ToplandAmount)
  dialog:UpdateDoubleField("Gear.FaceFlankRadius",              Gear.FaceFlankRadius)
 
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryDropList(Header, Quest, DX, DY, DList)
--[[
    Drop list foe user input
    Caller: local y = InquiryDropList("Cabinet Maker", "Select Cabinet Style", 290, 165, IniFile)
    Dialog Header = "Cabinet Maker"
    Quest = "Select Cabinet Style"
    Selection Array = IniFile
    Returns = String
]]
    local myHtml = [[<!DOCTYPE HTML><html lang="en"><head><title>My List Box</title><style>.FormButton{font-weight:700;width:75px;font-size:12px;white-space:nowrap;font-family:Arial,Helvetica,sans-serif font-size: 12px}.h1-l{font-size:12px;font-weight:700;text-align:left;white-space:nowrap}.h1-c{font-size:12px;font-weight:700;text-align:center;white-space:nowrap}table{width:100%;border:0}body,td,th{background-color:#3a4660;background-position:center;overflow:hidden;font-family:arial,helvetica,sans-serif;font-size:12px;color:#fff;background-image:url(']].. DialogWindow.myBackGround ..[[')}html{overflow:hidden}</style></head><body><table><tr><td class="h1-l" id="Questions"><strong class="h2">Message Here</strong></td></tr><tr><td class="h1-c"><select name="DList" size="10" class="h1-c" id="ListBox"><option>My Default 1</option><option selected="selected">My Default 2</option><option>My Default 3</option><option>My Default 4</option></select></td></tr><tr><th class="h1-l" colspan="3" id="QuestionID"></th></tr></table><table><tr><td class="h1-c"><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td></td><td class="h1-c"><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]] ;
 
    local dialog = HTML_Dialog(true, myHtml, DX, DY, Header)
          dialog:AddLabelField("Questions", Quest)
          dialog:AddDropDownList("ListBox", "DEFAULT")
          dialog:AddDropDownListValue("ListBox", "DEFAULT")
    for index, value in pairs(DList) do
        dialog:AddDropDownListValue("ListBox", value)
    end
    if not dialog:ShowDialog() then
      return "."
    else
      return dialog:GetDropDownListValue("ListBox")
    end
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryFileBox(Header, Quest, DefaltPath)
--[[
    Dialog Box for user to pick a file
    Caller: local X = InquiryFileBox("Select File", "Where is the file location?", "C:\\")
    Dialog Header = "File Name"
    User Question = "Path name?"
    Default Value = "C:\\"
    Returns = String
  ]]
  local myHtml = [[<html> <head> <title>Easy Tools</title> <style type = "text/css">  html {overflow: hidden; } body {
            background-color: #EBEBEB; overflow:hidden; font-family: Arial, Helvetica, sans-serif; font-size: 12px; } body, td,
            th {font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; color: #000 ; } .FormButton {font-weight: bold ;
            width: 100% ; font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; } body { background-color: #EBEBEB; }
            </style> </head> <body bgcolor = "#EBEBEB" text = "#000000"> <table width = "470" border = "0" cellpadding = "0">
            <tr> <th align = "left" valign = "top" bgcolor = "#EBEBEB" id = "QuestionID"><strong>Message Here</strong></th>
            <th align = "left" valign = "middle" bgcolor = "#EBEBEB">&nbsp;</th> </tr> <tr>
            <th width = "381" align = "right" valign = "middle" bgcolor = "#EBEBEB" id = "QuestionID">
            <input name = "ReadFile" type = "text" id = "ReadFile" size = "60"></th>
            <th width = "83" align = "center" valign = "middle" bgcolor = "#EBEBEB"> <span style="width: 15%">
            <input id = "FilePicker" class = "FilePicker" name = "FilePicker" type = "button" value = "Path">
            </span></th> </tr> <tr> <td colspan = "2" align = "center" valign = "middle" bgcolor = "#EBEBEB">
            <table border = "0" width = "100%"> <tr align = "right"> <td style = "width: 20%"> </td>
            <td style = "width: 20%"></td> <td style = "width: 25%"></td> <td style = "width: 15%">
            <input id = "ButtonCancel" class = "FormButton" name = "ButtonCancel" type = "button" value = "Cancel"> </td>
            <td style = "width: 15%"> <input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK">
            </td> </tr> </table> </td> </tr> </table> </body>  </html>]]
  -- =============================================
  local dialog = HTML_Dialog(true, myHtml, 505, 150, Header)
    dialog:AddLabelField("QuestionID", Quest)
    dialog:AddTextField("ReadFile", DefaltPath )
    dialog:AddFilePicker(true, "FilePickerButton", "ReadFile", true)
    if not dialog:ShowDialog() then
      return ""
    else
      return dialog:GetTextField("ReadFile")
    end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryPathBox(Header, Quest, DefaltPath)
--[[
    Number Box for user input with default value
    Caller: local X = InquiryPathBox("Select Path", "Where is the file location?", "C:\\")
    Dialog Header = "Tool Name"
    User Question = "Path name?"
    Default Value = "C:\\"
    Returns = String
  ]]
  local myHtml = [[ <html> <head> <title>Easy Tools</title> <style type = "text/css">  html {overflow: hidden; } body {
            background-color: #EBEBEB; overflow:hidden; font-family: Arial, Helvetica, sans-serif; font-size: 12px; } body, td,
            th {font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; color: #000 ; } .FormButton {font-weight: bold ;
            width: 100% ; font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; } body { background-color: #EBEBEB; }
            </style> </head> <body bgcolor = "#EBEBEB" text = "#000000"> <table width = "470" border = "0" cellpadding = "0">
            <tr> <th align = "left" valign = "top" bgcolor = "#EBEBEB" id = "QuestionID"><strong>Message Here</strong></th>
            <th align = "left" valign = "middle" bgcolor = "#EBEBEB">&nbsp;</th> </tr> <tr>
            <th width = "381" align = "right" valign = "middle" bgcolor = "#EBEBEB" id = "QuestionID">
            <input name = "DInput" type = "text" id = "DInput" size = "60"></th>
            <th width = "83" align = "center" valign = "middle" bgcolor = "#EBEBEB"> <span style="width: 15%">
            <input id = "DirectoryPicker" class = "DirectoryPicker" name = "DirectoryPicker" type = "button" value = "Path">
            </span></th> </tr> <tr> <td colspan = "2" align = "center" valign = "middle" bgcolor = "#EBEBEB">
            <table border = "0" width = "100%"> <tr align = "right"> <td style = "width: 20%"> </td>
            <td style = "width: 20%"></td> <td style = "width: 25%"></td> <td style = "width: 15%">
            <input id = "ButtonCancel" class = "FormButton" name = "ButtonCancel" type = "button" value = "Cancel"> </td>
            <td style = "width: 15%"> <input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK">
            </td> </tr> </table> </td> </tr> </table> </body>  </html>]]
  -- =============================================
  local dialog = HTML_Dialog(true, myHtml, 505, 150, Header)
    dialog:AddLabelField("QuestionID", Quest)
    dialog:AddTextField("DInput", DefaltPath )
    dialog:AddDirectoryPicker("DirectoryPicker",  "DInput",  true)
    if not dialog:ShowDialog() then
      return ""
    else
      return dialog:GetTextField("DInput")
    end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryAreYouSureYesNo(Header, Question1, Question2)
--[[
    Drop list for user to input project info
    Caller = local y = InquiryAreYouSureYesNo("Pie Question", "Do you want free pie")
    Dialog Header = "Pie Question"
    User Question1 = "Do you want a Free Pie"
    User Question2 = "You only get one"
    Returns = true / false
  ]]
    local myHtml = [[ <html><head><title>Yes or No Question</title>]] .. DialogWindow.Style ..[[</head><body><table><tr><td colspan="3" class="h2-lw" id="Question1">Question1</td></tr><tr><td colspan="3" class="h2-lw" id="Question2">Question2</td></tr><tr><td class="h2-l">&nbsp;</td></tr><tr><td colspan="3" class="h2-l">Are you sure?</td></tr><tr><td class="h2-l">&nbsp;</td></tr></table><table><tr><td colspan="3"><h2><span></span></h2></td></tr>
  <tr><td class="h1-l"><input id="ButtonOK" class="FormButton FormBut" name="ButtonOK" type="button" value="  Yes  "> </td> <td class="h1-r"> <input id="ButtonCancel" class="FormButton FormBut" name="ButtonCancel" type="button" value="  No  "></td></tr></table></body></html>]]
-- =========================================================
    local dialog = HTML_Dialog(true, myHtml, 440, 218, Header)
    dialog:AddLabelField("Question1", Question1)
    dialog:AddLabelField("Question2", Question2)
    if not dialog:ShowDialog() then
      return false
    else
      return true
    end
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryDoubleBox(Header, Quest, DefaltN)
--[[
-- nquiryNumberBox for user input with default number value
-- Caller: local x = InquiryNumberBox("Cabinet Maker", "Enter the cabinet height", 30.0)
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the cabinet height"
-- Default value = 30.0
-- Returns = double
]]
  local myHtml = [[<html><head><title>Get Double Value</title><style type="text/css">html{overflow:hidden}body{background-color:#ebebeb;overflow:hidden;font-family:Arial,Helvetica,sans-serif;font-size:12px;text:#000}.h1-l{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:left;white-space:nowrap}.h1-r{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:right;white-space:nowrap}.h1-c{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:center;white-space:nowrap}table{width:100%;border:0;cellpadding:0}.FilePicker{font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:12px;width:50px}.FormButton{font-weight:700;width:65px;font-family:Arial,Helvetica,sans-serif;font-size:12px}</style></head><body><table><tr><td id="QuestionID" class="h1-r"><strong>Message Here</strong></td><td><input type="text" id="NumberInput" size="5"></td></tr><tr><td colspan="2"></td></tr></table><table><tr class="h1-c"><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 260, 125, Header)
  dialog:AddLabelField("QuestionID", Quest) ;
  dialog:AddDoubleField("NumberInput", DefaltN) ;
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetDoubleField("NumberInput")
  end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryIntegerBox(Header, Quest, DefaltI)
--[[
-- InquiryIntegerBox for user input with default number value
-- Caller: local x = InquiryIntegerBox("Cabinet Maker", "Enter the door count", 4)
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the door count"
-- Default value = 4
-- Returns = integer
]]
  local myHtml = [[<html><head><title>Get Integer</title><style type="text/css">html{overflow:auto}body{background-color:#ebebeb}table{width:100%;border:0}body,td,th{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000}.FormButton{font-weight:700;width:85px;font-family:Arial,Helvetica,sans-serif;font-size:12px}body{background-color:#ebebeb;text:#000}</style></head><body><table><tr><td id="QuestionID"><strong>Message Here</strong></td><td><input type="text" id="IntegerInput" size="10"></td></tr><tr><td colspan="2"></td></tr></table><table><tr><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 505, 140, Header)
  dialog:AddLabelField("QuestionID", Quest)
  dialog:AddIntegerField("IntegerInput", DefaltI)
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetIntegerField("IntegerInput")
  end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InquiryTextgBox(Header, Quest, DefaltS)
--[[
-- InquiryStringBox for user input with default number value
-- Caller: local x = InquiryTextgBox("Cabinet Maker", "Enter the cabinet Name", "Jim")
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the cabinet Name"
-- Default value = Jim
-- Returns = string
]]
  local myHtml = [[<html><head><title>Get Number</title><style type="text/css">html{overflow:auto}body{background-color:#ebebeb}table{width:100%;border:0}body,td,th{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000}.FormButton{font-weight:700;width:85px;font-family:Arial,Helvetica,sans-serif;font-size:12px}body{background-color:#ebebeb;text:#000}</style></head><body><table><tr><td id="QuestionID"><strong>Message Here</strong></td><td><input type="text" id="StringInput" size="10"></td></tr><tr><td colspan="2"></td></tr></table><table><tr><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 505, 140, Header)
  dialog:AddLabelField("QuestionID", Quest)
  dialog:AddTextField("StringInput", DefaltS)
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetTextField("NumberInput")
  end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function OnLuaButton_InquiryError(Message)
    --[[
    Provides user information on an Error
    Caller = local ItWorked = OnLuaButton_InquiryError("No number found")
    Dialog Header = "Something Error"
    User Message = "No Number etc..."
    Returns = True
  ]]
  local myHtml = [[<html><head><title>Error</title><style type = "text/css">.FormButton{font-weight:bold;width:75px;font-family:Arial,Helvetica,sans-serif;font-size:12px;white-space:nowrap}.Error{font-family:Arial,Helvetica,sans-serif;font-size:18px;font-weight:bold;color:#F00;text-align:left;white-space:nowrap;padding-right:4px;padding-left:10px;padding-top:4px;padding-bottom:4px}.ErrorMessage{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000;font-weight:bold;text-align:left;white-space:nowrap;padding-right:4px;padding-left:10px;padding-top:4px;padding-bottom:4px}.ErrorTable{background-color:#FFF white-space:nowrap}html{overflow:hidden}</style></head><body text = "#000000"><table width="100%" border="0" cellpadding="0" class="ErrorTable"><tr><th align="center" nowrap="nowrap" class="Error">Error!</th></tr><tr><td id="ErrorMessage"><label class="ErrorMessage">-</label></tr><tr><td width="30%" align="right" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "Exit"></td></tr></table></body></html>]]
  local dialogWide =  (#Message + 300)
  local dialog = HTML_Dialog(true, myHtml, 250, dialogWide, "Gadget Error")
  dialog:AddLabelField("ErrorMessage",  Message)
  dialog:ShowDialog()
  Dovetail.InquiryErrorX = Dialog.WindowWidth
  Dovetail.InquiryErrorY = Dialog.WindowHeight
  WriteRegistry()
  return  true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function PresentMessage(Header, Type, Line)
    --[[
    Provides user information on an Error
    Caller = local ItWorked = OnLuaButton_InquiryError("No number found")
    Dialog Header = "Something Error"
    User Message = "No Number etc..."
    Returns = True
  ]]
  local myHtml = [[<html><head><title>Error</title>]] .. DialogWindow.Style ..[[</head><body>
  <table><tr><th valign="top" id="MessageType" class="Error">-</th><td id="MessageLine"><label class="ErrorMessage">-</label><td></tr>
<tr><td></td><td align="right"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td></tr>
</table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 500, 150, Header)
  dialog:AddLabelField("MessageType", Type .. ": ")
  dialog:AddLabelField("MessageLine", Line)
  dialog:ShowDialog()
  return  true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function OnLuaButton_InquiryAbout()
local myHtml = [[<html><head><title>About</title>]] .. DialogWindow.Style ..[[</head><body text = "#000000"><table width="680" border="0" cellpadding="0"> <tr> <td align="center" nowrap="nowrap" class="header1-c" id="SysName">Easy Cabinet Maker</td> </tr> <tr> <td align="center" nowrap="nowrap" id="Version" class="ver-c">Version</td> </tr> <tr> <td align="center" nowrap="nowrap"><hr></td> </tr> <tr> <td align="center" nowrap="nowrap" class="header2-c">Disclaimer</td> </tr> <tr> <td align="center" class="p1-l"><p class="p1-l">The ]] .. Dovetail.AppName .. [[ Gadget is a plugin for Vectric software, V-Carve Pro and Aspire.<br> Gadgets are an entirely optional add-in to Vectric's core software products.<br> They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.<br> In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.<br> <br> Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:<br> 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.<br> * If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.<br> 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.<br> 3. This notice may not be removed or altered from any source distribution.<br> <br>The author heavily utilized the SDK documentation and supplied code samples in addition to the outstanding user community on the Vectric User forum.</p></td> </tr> <tr> <td align="center"><a href="https://forum.vectric.com" class="webLink-c">Vectric User Forum</a></td> </tr> <tr> <td align="center"><span class="header2-c">JimAndi</span></td> </tr> <tr> <td align="center"><span class="h1-c">Houston, TX.</span></td> </tr> <tr> <td><hr></td> </tr> <tr> <td width="30%" align="center" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td> </tr></table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 720, 468, "About")
  dialog:AddLabelField("SysName", Project.ProgramName)
  dialog:AddLabelField("Version", "Version: " .. Project.ProgramVersion)
  dialog:ShowDialog()
  Project.AboutXY = tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight)
  return  true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Color_HTML ()
  MessageBox(" X = " .. tostring(dialog.WindowWidth) ..
            " Y = " .. tostring(dialog.WindowHeight)
)
 
</nowiki>
-- =====================================================]]
<nowiki>
 
--[[ -- begin HTML for Layer Color
<table>
  <tr>
    <td width="200" align="right" valign="middle" nowrap class="h1-rp">Layer Name</td>
    <td width="300" align="right" valign="middle" nowrap class="h1-l" id="ValueTable">
      <input name="Panel.PinHole" type="text" class="h1-l" id="Panel.PinHole" size="50" maxlength="50"/>
      </td>
    <td width="150"align="right" valign="middle" nowrap class="h1-l"><label for="Panel.LineColor01">Color</label>
      <select name="Panel.LineColor01" id="Panel.LineColor01">
        <option selected="selected">Black</option>
        <option>Blue</option>
        <option>Brown</option>
        <option>Cyan</option>
        <option>Gray</option>
        <option>Green</option>
        <option>Lime</option>
        <option>Magenta</option>
        <option>Maroon</option>
        <option>Navy</option>
        <option>Olive</option>
        <option>Orange</option>
        <option>Purple</option>
        <option>Red</option>
        <option>Silver</option>
        <option>Teal</option>
        <option>White</option>
        <option>Yellow</option>
    </select></td>
  </tr>
</table>
<table width="101%" border="0" id="ButtonTable">
</table>
]] -- end HTML
end -- HTML Function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Style ()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
DialogWindow.Style = [[ <style>
.DirectoryPicker {
  font-weight: bold;
  font-size: 12px;
  white-space: nowrap;
  background-color: #663300;
  color: #FFFFFF;
}
.FormButton {
font-weight: bold;
width: 75px;
font-size: 12px;
white-space: nowrap;
background-color: #663300;
color: #FFFFFF;
}
.FormButton-Help {
font-weight: bold;
width: 75px;
font-size: 12px;
white-space: nowrap;
background-color: #663300;
color: #FFFFFF;
padding-left: 10;
padding-right: 10;
}
.LuaButton {
font-weight: bold;
font-size: 12px;
background-color: #663300;
color: #FFFFFF;
}
.ToolNameLabel {
font-weight: bolder;
font-size: 12px;
text-align: left;
color: #000;
width: 70%;
}
.ToolPicker {
font-weight: bold;
text-align: center;
font-size: 12px;
text-align: center;
width: 50px;
background-color: #663300;
color: #FFFFFF;
}
.alert-c {
font-size: 14px;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.alert-l {
font-size: 14px;
font-weight: bold;
text-shadow: 5px 5px 10px #FFF;
text-align: left;
width: 100%;
white-space: nowrap;
}
.alert-r {
font-size: 14px;
font-weight: bold;
text-align: right;
white-space: nowrap;
}
.error {
font-size: 18px;
font-weight: bold;
color: #FF0000;
text-align: left;
white-space: nowrap;
padding-right: 4px;
padding-left: 10px;
padding-top: 4px;
padding-bottom: 4px;
}
.errorMessage {
font-size: 12px;
color: #000;
font-weight: bold;
text-align: left;
white-space: nowrap;
padding-right: 4px;
padding-left: 10px;
padding-top: 4px;
padding-bottom: 4px;
}
.errorTable {
background-color: #FFFFFF;
white-space: nowrap;
}
.p1-l {
font-size: 12px;
text-align: left;
}
.h1-c {
font-size: 12px;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.h1-cOk {
font-size: 12px;
font-weight: bold;
text-align: center;
white-space: nowrap;
width: 15%;
}
.h1-l {
font-size: 12px;
font-weight: bold;
text-align: left;
white-space: nowrap;
}
.h1-r {
font-size: 12px;
font-weight: bold;
text-align: right;
white-space: nowrap;
}
.h1-rP {
font-size: 12px;
font-weight: bold;
text-align: right;
white-space: nowrap;
padding-right: 4px;
padding-left: 4px;
}
.h1-rPx {
font-size: 12px;
font-weight: bold;
text-align: right;
white-space: nowrap;
padding-right: 8px;
padding-left: 8px;
}
.h2-c {
font-size: 14px;
font-weight: bold;
text-align: center;
white-space: nowrap;
text-shadow: 2px 2px white;
}
.h2-l {
font-size: 14px;
font-weight: bold;
color: #663300;
text-align: left;
white-space: nowrap;
text-shadow: 2px 2px white;
}
.h2-r {
font-size: 14px;
font-weight: bold;
color: #663300;
text-align: right;
white-space: nowrap;
text-shadow: 2px 2px white;
}
.h3-bc {
font-size: 16px;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.h3-c {
font-size: 16px;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.h3-l {
font-size: 16px;
font-weight: bold;
text-align: left;
white-space: nowrap;
}
.h3-r {
font-size: 16px;
font-weight: bold;
text-align: right;
white-space: nowrap;
}
.h4-c {
font-size: 18px;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.h4-l {
font-size: 18px;
font-weight: bold;
text-align: left;
white-space: nowrap;
}
.h4-r {
font-size: 18px;
font-weight: bold;
text-align: right;
white-space: nowrap;
}
.help_But {
width: 45px;
}
.MyCenter{
text-align:center;
width:10;
}
.MyLeft{
text-align:left;
width:10;
}
.MyRight{
text-align:right;
width:10;
}
.helplabel-r {
cursor: pointer;
white-space: nowrap;
text-align: right;
}
.helplabel-rp {
cursor: pointer;
white-space: nowrap;
text-align: right;
padding-right: 8px;
}
.jsTag-no-vis {
font-size: 10px;
display: none;
text-align: center;
color: #00F;
visibility: hidden;
}
.jsbutton {
background-color: #663300;
border: 2px solid #999;
border-right-color: #000;
border-bottom-color: #000;
border-top-color: #FFF;
border-left-color: #FFF;
text-align: center;
text-decoration: none;
font-size: 12px;
margin: 1px 1px;
color: #FFFFFF;
}
.p1-c {
font-size: 12px;
text-align: center;
}
.p1-r {
font-size: 12px;
text-align: right;
}
.ver-c {
font-size: 10px;
font-weight: bold;
text-align: center;
white-space: nowrap;
color: #ffd9b3;
}
.webLink-c {
font-size: 16px;
font-weight: bold;
background-color: yellow;
text-align: center;
white-space: nowrap;
}
body {
background-color: #3a4660;
background-position: center;
overflow: hidden;
font-family: arial, helvetica, sans-serif;
font-size: 12px;
color: #FFFFFF;
background-image: url(]].. DialogWindow.myBackGround ..[[);
}
html {
overflow: hidden
}
table {
width: 100%;
border: 0;
}
</style>]]
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Orgin ()                                      -- Anchor Point
-- ================================
  DialogWindow.Orgin = [[<table><tr><td colspan="2" class="h2-l">Anchor Point</td></tr><tr class="MyLeft"><td class="MyLeft"><table class="MyCenter"><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V1"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V2"></td></tr><tr><td class="auto-style9">|</td><td><input type="radio" name="DrawingOrigin" checked="checked" value="V3"></td><td valign="top">|</td></tr><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V4"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V5"></td></tr></table></td><td width="81%"><table><tr class="MyLeft"><td>X</td><td><input name="OriginX0" type="text" id="OriginX" size="8" maxlength="8"></td></tr><tr class="MyLeft"><td>Y</td><td><input name="OriginY0" type="text" id="OriginY" size="8" maxlength="8"></td></tr></table></td></tr></table>]]
end -- HTML Function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetColor(str)                                  -- returns the RGB value for the standard color names
-- str = "Purple"
-- returns = 128 0 128
    local Colors = {}
    Colors.Black  = "0,0,0";      Colors.White  = "255,255,255"; Colors.Red    = "255,0,0"
    Colors.Lime  = "0,255,0";    Colors.Blue  = "0,0,255";    Colors.Yellow = "255,255,0"
    Colors.Cyan  = "0,255,255";  Colors.Magenta = "255,0,255";  Colors.Silver = "192,192,192"
    Colors.Gray  = "128,128,128"; Colors.Maroon = "128,0,0";    Colors.Olive  = "128,128,0"
    Colors.Green  = "0,128,0";    Colors.Purple = "128,0,128";  Colors.Teal  = "0,128,128"
    Colors.Navy  = "0,0,128"
    local Red, Green, Blue = 0
    if "" == str then
      DisplayMessageBox("Error: Empty string passed")
    else
      str = Colors[str]
      if "string" == type(str) then
        if string.find(str, ",") then
          Red  = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          str = string.sub(str, assert(string.find(str, ",") + 1))
          Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          Blue = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
        end
      else
        DisplayMessageBox("Error: Color Not Found")
        Red = 0
        Green = 0
        Blue = 0
      end
    end
    return Red, Green, Blue
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function StatusMessage(Type, Header, Question, length) -- Standardize messaging dialogues
  -- StatusMessage("Alert",    "Alert Test",    "This is a test of Alert",    165)
  -- StatusMessage("Question", "Question Test",  "This is a test of Question", 165)
  -- StatusMessage("Tick",    "Tick Test",      "This is a test of Tick",    165)
  -- StatusMessage("Minus",    "Minus Test",    "This is a test of Minus",    165)
  -- StatusMessage("Error",    "Error Test",    "This is a test of Error",    165)
  -- StatusMessage("Success",  "Success Test",  "This is a test of Success",  165)
  -- StatusMessage("Blank",    "Blank Test",    "This is a test of Blank",    165)
  local Image = ""
  if    Type == "Alert" then
    Image = AlertImage()
  elseif Type == "Question" then
    Image = QuestionImage()
  elseif Type == "Tick" then
    Image = TickImage()
  elseif Type == "Minus" then
    Image = MinusImage()
  elseif Type == "Error" then
    Image = ErrorImage()
  elseif Type == "Success" then
    Image = SuccessImage()
  else -- "Status"
    Image = TickImage()
  end -- if end
  local help = [[<html><head><title>]] .. Header ..[[</title><style>
.FormButton {font-family: Arial, Helvetica, sans-serif;font-weight: bold;font-size: 12px;white-space: nowrap;background-color: #663300;color: #FFFFFF;width: 75px;
}table {width: 100%;border: 0;}.h2-lm {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: left;}.h2-r {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: right;white-space: nowrap;}.h2-l {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: left;white-space: nowrap;}body {background-color: #3a4660;background-position: center;overflow: hidden;font-family: arial, helvetica, sans-serif;font-size: 12px;color: #FFFFFF;background-image: url(]] .. myBackGround() .. [[);}html {overflow: hidden}</style></head><body><table> <tr>  <td class="h2-l"><]] .. Image .. [[" width="60" height="60"></td>
    <td class="h2-lm" id="Question">]] .. Question .. [[</td></tr><tr><td colspan=2><h2><span></span></h2></td>
    </tr></table><table><tr><td class="h2-r"><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td>
    </tr></table></body></html>]]
  local dialog = HTML_Dialog(true, help , 550,  length, Header)
  dialog:ShowDialog()
  return true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Dialog Tools function end
 
 
</nowiki>
 
==Directory and File Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╠╦╝║╣ ║  ║ ║ ║╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function DirectoryTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function MakeFolder(xPath)
    os.execute( "mkdir  " .. xPath)
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function PathFix(xPath)
    return string.gsub(xPath, "\\", "/")
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function FileExists(name)
-- FileExists(name
-- DisplayMessageBox(name)
    local f=io.open(name,"r")
    if f~=nil then
      io.close(f)
      return true
    else
      return false
    end
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function DirectoryProcessor(job, dir_name, filter, do_sub_dirs, function_ptr)
      local num_files_processed = 0
      local directory_reader = DirectoryReader()
      local cur_dir_reader = DirectoryReader()
      directory_reader:BuildDirectoryList(dir_name, do_sub_dirs)
      directory_reader:SortDirs()
      local number_of_directories = directory_reader:NumberOfDirs()
      for i = 1, number_of_directories do
        local cur_directory = directory_reader:DirAtIndex(i)
        -- get contents of current directory
        -- dont include sub dirs, use passed filter
        cur_dir_reader:BuildDirectoryList(cur_directory.Name, false)
        cur_dir_reader:GetFiles(filter, true, false)
        -- call passed method for each file:
        local num_files_in_dir = cur_dir_reader:NumberOfFiles()
        for j=1, num_files_in_dir  do
          local file_info = cur_dir_reader:FileAtIndex(j)
          if not function_ptr(job, file_info.Name) then
            return true
          end -- if end
          num_files_processed = num_files_processed + 1
        end -- for end
        -- empty out our directory object ready for next go
        cur_dir_reader:ClearDirs()
        cur_dir_reader:ClearFiles()
      end -- for end
      return num_files_processed
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Directory Tools end
 
 
</nowiki>
 
==Drawing Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
 
<nowiki> </nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╦═╗╔═╗╦ ╦╦╔╗╔╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
<nowiki> </nowiki>║║╠╦╝╠═╣║║║║║║║║ ╦  ║ ║ ║║ ║║  ╚═╗
═╩╝╩╚═╩ ╩╚╩╝╩╝╚╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function DrawTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function LayerClear(LayerName)
local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
  if Mylayer.IsEmpty then
      Milling.job.LayerManager:RemoveLayer(Mylayer)
  end -- if end
return true
end -- function end
-- ====================================================]]
function Scale(Num)
local mtl_block = MaterialBlock()
if mtl_block.InMM then
  return Num * 25.4
else
  return Num
end
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function AssyHoler(pt1, pt2, PartName)                  -- Draws Assy Holes in a stight line
local Ang1 = GetPolarDirection(pt1, pt2)
local Ang2 = GetPolarDirection(pt2, pt1)
pt1 = Polar2D(pt1, Ang1, Milling.AssemblyHoleStartEnd)
DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
pt2 = Polar2D(pt2, Ang2, Milling.AssemblyHoleStartEnd)
DrawCircle(pt2, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
local Dist = GetDistance(pt1, pt2)
if Project.Debugger then
  DMark("pt1", pt1)
  DMark("pt2", pt2)
end
BaseScrew(2)
Milling.AssemblyHoleSpace = ((Milling.AssemblyHoleMaxSpace + Milling.AssemblyHoleMinSpace) * 0.5)
HoleCount = Round(math.floor(Dist / Milling.AssemblyHoleSpace))
HoleSpacing = (Dist / HoleCount)
HoleCount = (Dist / HoleSpacing)
if (Dist > (HoleSpacing * 2.0)) then
  for i = HoleCount, 1, -1 do
    pt1 = Polar2D(pt1, Ang1, HoleSpacing)
    DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
    if Project.Debugger then
      DMark("pt1w", pt1)
    end
    BaseScrew(1)
  end -- for end
elseif (Dist > HoleSpacing) then
  ptC = Polar2D(pt1, Ang1, Dist / 2.0)
  if Project.Debugger then
    DMark("ptC", ptC)
  end
  DrawCircle(ptC, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
else
  -- Done No Holes
end
return true
end -- end AssyHoler function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawBoneCenter2Pts(pt1, pt2, SlotWidth, BitRadius)
  Local Project = {}
  Project.job  = VectricJob()
  Project.ang  = GetPolarDirection(pt1, pt2)
  Project.dis  = H(SlotWidth)
  Project.bit  = math.sin(math.rad(45.0)) * BitRadius
  Project.ptA  = Polar2D(pt1, Project.ang +  90.0, Project.dis)
  Project.ptAa  = Polar2D(Project.ptA, Project.ang, Project.bit)
  Project.ptAb  = Polar2D(Project.ptA, Project.ang + 270.0, Project.bit)
  Project.ptB  = Polar2D(pt1, Project.ang + 270.0, Project.dis)
  Project.ptBa  = Polar2D(Project.ptB, Project.ang +  90.0, Project.bit)
  Project.ptBb  = Polar2D(Project.ptB, Project.ang, Project.bit)
  Project.ptC  = Polar2D(pt2, Project.ang + 270.0, Project.dis)
  Project.ptCa  = Polar2D(Project.ptC, Project.ang +  90.0, Project.bit)
  Project.ptCb  = Polar2D(Project.ptC, Project.ang - 180.0, Project.bit)
  Project.ptD  = Polar2D(pt2, Project.ang +  90.0, Project.dis)
  Project.ptDa  = Polar2D(Project.ptD, Project.ang - 180.0, Project.bit)
  Project.ptDb  = Polar2D(Project.ptD, Project.ang + 270.0, Project.bit)
  Project.line  = Contour(0.0)
  Project.layer = Project.job.LayerManager:GetLayerWithName("DogBone")
  Project.line:AppendPoint(Project.ptAa)
  Project.line:ArcTo(Project.ptAb, 1.0)
  Project.line:LineTo(Project.ptBa)
  Project.line:ArcTo(Project.ptBb, 1.0)
  Project.line:LineTo(Project.ptCb)
  Project.line:ArcTo(Project.ptCa, 1.0)
  Project.line:LineTo(Project.ptDb)
  Project.line:ArcTo(Project.ptDa, 1.0)
  Project.line:LineTo(Project.ptAa)
  Project.layer:AddObject(CreateCadContour(Project.line), true)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function InsideCornerNipper(AngPlung, BitRadius, CornerPt)
local NipLength = math.sin(math.rad(45.0)) * ((BitRadius + 0.04) * 2.0)
local Pt1, Pt2 = Point2D()
if Material.Orientation == "V" then
  Pt1 = Polar2D(CornerPt, (AngPlung + 90.0) - 45.0, NipLength)
  Pt2 = Polar2D(CornerPt, (AngPlung + 90.0) + 45.0, NipLength)
else
  Pt1 = Polar2D(CornerPt, (AngPlung + 180.0) - 45.0, NipLength)
  Pt2 = Polar2D(CornerPt, (AngPlung + 180.0) + 45.0, NipLength)
end
return Pt1, Pt2
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function AddGroupToJob(job, group, layer_name)
  --[[  --------------- AddGroupToJob --------------------------------------------------|
  |  Add passed group to the job - returns object created
  |  Parameters:
  |    job              -- job we are working with
  |    group            -- group of contours to  add to document
  |    layer_name      -- name of layer group will be created on|
  |  Return Values:
  |    object created to represent group in document
  ]]</nowiki>
  --  create a CadObject to represent the  group
  local cad_object = CreateCadGroup(group);
  -- create a layer with passed name if it doesnt already exist
  local layer = job.LayerManager:GetLayerWithName(layer_name)
  -- and add our object to it
  layer:AddObject(cad_object, true)
  return cad_object
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawArc(PtS, PtE, ArcRadius, Layer)
--[[Draw Arc
  function main(script_path)
  local MyPt1 = Point2D(3.5,3.8)
  local MyPt2 = Point2D(3.5,6.8)
  local layer = "My Arc"
  DrawArc(MyPt1, MyPt2, -0.456, Layer)
  return true
  end -- function end
  -- -----------------------------------------------------]]</nowiki>
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: No job loaded")
      return false
    end
    local line = Contour(0.0)
    local layer = job.LayerManager:GetLayerWithName(Layer)
    line:AppendPoint(PtS)
    line:ArcTo(PtE,1);
    layer:AddObject(CreateCadContour(line), true)
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawEllipse(CenterPt, LongAxe, ShortAxe, Layer)
  local LongAngle = 90.0
  local ValueAB = (LongAxe - ShortAxe) * 0.50
  local ValueAC = ValueAB * math.cos(math.rad(LongAngle))
  local job = VectricJob()
  local LRad = LongAxe * 0.50
  local ptT = Polar2D(CenterPt, LongAngle, LRad)
  local X = 0.0
  local pty = Point2D(0.0,0.0)
  local ptx  = Point2D(0.0,0.0)
  local mylayer = job.LayerManager:GetLayerWithName(Layer)
  local line = Contour(0.0)
        line:AppendPoint(ptT)
  while (X < 360.0) do
    pty = Polar2D(CenterPt, LongAngle + X, LRad)
    ValueAC = ValueAB * math.cos(math.rad(LongAngle + X))
    if ((LongAngle + X) >= 90.0) then
      ptx = Polar2D(pty, 180.0, ValueAC)
    else
      ptx = Polar2D(pty,  0.0, ValueAC)
    end
    line:LineTo(ptx)
    X = X + 1
  end -- while end
    line:LineTo(ptT)
  mylayer:AddObject(CreateCadContour(line), true)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawEllipse1(DrawEllipse_CenterPt, DrawEllipse_LongAxe, DrawEllipse_ShortAxe, DrawEllipse_LongAxeAngle, DrawEllipse_Layer)
  -- ---------------------------------------------------]]
  function H(x)                                        -- Returns half the value
    return x * 0.5
  end -- function end
  -- ---------------------------------------------------]]
  function Polar2D(pt, ang, dis)                        -- Calculate a new point based on reference point, angle and distance.
  -- Returns a 2Dpoint(x, y)
    return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
  end -- End Function
  -- ---------------------------------------------------]]
  function GetDistance(objA, objB)
    local xDist = objB.x - objA.x
    local yDist = objB.y - objA.y
    return math.sqrt((xDist ^ 2) + (yDist ^ 2))
  end -- function end
  -- ---------------------------------------------------]]
  function Radius2Bulge (p1, p2, Rad)
    local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
    local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
    local bulge = (2 * seg) / chord
    return bulge
  end -- function end
  -- ---------------------------------------------------]]
function GetPolarAngle(Start, Corner, End)
  local function GetPolarDirection(point1, point2)              --
    local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
    if point1.X < point2.X then
      if point1.Y < point2.Y then
        ang = ang + 0.0
      else
        ang = 360.0 - ang
      end -- if end
    else
      if point1.Y < point2.Y then
        ang = 180.0 - ang
      else
        ang = ang + 180.0
      end -- if end
    end -- if end
    if ang >=360 then
      ang = ang -360.0
    end -- if end
    return ang
  end -- function end
  return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
end -- function end
  -- ---------------------------------------------------]]
  -- Call = DrawEllipse(2DPoint(20.0, 20.0), 20.0, 10.0, 0.0, "Jim")
  local job = VectricJob()
  local EndRadius = 0.0
  local TopRadius = 0.0
  local ptT = Polar2D(DrawEllipse_CenterPt,  (90.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
  local ptB = Polar2D(DrawEllipse_CenterPt, (270.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
  local ptR = Polar2D(DrawEllipse_CenterPt,  (0.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
  local ptL = Polar2D(DrawEllipse_CenterPt, (180.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
  local ptC = DrawEllipse_CenterPt
  --[[
      DMark("ptC", ptC)
      DMark("ptT", ptT)
      DMark("ptB", ptB)
      DMark("ptL", ptL)
      DMark("ptR", ptR)
  ]]</nowiki>
  local C_Offset = H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe)
  local LT_SlopeDist = H(GetDistance(ptL, ptT) - H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe))
  local LT_Dist  = GetDistance(ptL, ptT)
  local LT_Angle = math.abs(90.0 - GetAngle(ptT, ptL, ptC))
  local pt_a = Polar2D(ptL, LT_Angle + DrawEllipse_LongAxeAngle, LT_SlopeDist)
  local aT_Dist  = GetDistance(pt_a, ptT)
  local aC_Dist = aT_Dist / (math.tan(math.rad(LT_Angle)))
  local Tc_Dist = math.sqrt(aT_Dist^2 + aC_Dist^2)
  local pt_c = Polar2D(ptT, (270.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
  local cC_Dist  = GetDistance(pt_c, ptC)
  local b_Dist = math.tan(math.rad(LT_Angle)) * cC_Dist
  local pt_b = Polar2D(ptC, (180.0 + DrawEllipse_LongAxeAngle), b_Dist)
  local pt_d = Polar2D(ptB,  (90.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
  local pt_e = Polar2D(ptC,  (0.0 + DrawEllipse_LongAxeAngle), b_Dist)
  local pt1  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
  local pt2  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
  local pt3  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
  local pt4  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
  --[[
      DMark("pt1", pt1)
      DMark("pt2", pt2)
      DMark("pt3", pt3)
      DMark("pt4", pt4)
      local line = Contour(0.0)
      local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
      line:AppendPoint(pt1)
      line:LineTo(pt2)
      line:LineTo(pt3)
      line:LineTo(pt4)
      line:LineTo(pt1)
      layer:AddObject(CreateCadContour(line), true)
  ]]</nowiki>
  local T_Sec  = GetDistance(ptC, ptT) - H(GetDistance(pt1, pt4))
  local R_Sec  = GetDistance(ptC, ptR) - H(GetDistance(pt1, pt2))
  local T_Chor  = GetDistance(pt1, pt2)
  local R_Chor  = GetDistance(pt1, pt4)
  local T_Bulge = Radius2Bulge (pt1, pt2, Tc_Dist)
  local L_Bulge = Radius2Bulge (pt1, pt4, GetDistance(ptL, pt_b))
  local line = Contour(0.0)
  local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
  line:AppendPoint(pt1)
  line:ArcTo(pt2, T_Bulge)
  line:ArcTo(pt3, L_Bulge)
  line:ArcTo(pt4, T_Bulge)
  line:ArcTo(pt1, L_Bulge)
  layer:AddObject(CreateCadContour(line), true)
  job:Refresh2DView()
  return true
end -- Draw Ellipse function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawBox(p1, p2, p3, p4, Layer)
  --[[ Draw Box
    function main(script_path)
    local MyPt1 = Point2D(1.0,1.0)
    local MyPt2 = Point2D(1.0,3.0)
    local MyPt3 = Point2D(3.0,1.0)
    local MyPt4 = Point2D(3.0,3.0)
    local layer = "My Box"
    DrawBox(MyPt1 ,MyPt2, MyPt3, MyPt4, Layer)
    return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: No job loaded")
      return false
    end -- if end
    local line = Contour(0.0)
    local layer = job.LayerManager:GetLayerWithName(Layer)
    line:AppendPoint(p1)
    line:LineTo(p2)
    line:LineTo(p3)
    line:LineTo(p4)
    line:LineTo(p1)
    layer:AddObject(CreateCadContour(line), true)
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawCircle(Pt1, CenterRadius, Layer)
  --[[ ==Draw Circle==
    function main(script_path)
    local MyPt1 = Point2D(1.0,1.0)
    local MyRad = 3.0
    local layer = "My Box"
    DrawCircle(MyPt1, MyRad, Layer)
    return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end -- if end
  local pa = Polar2D(Pt1,  180.0, CenterRadius)
  local pb = Polar2D(Pt1,    0.0, CenterRadius)
  local Contour = Contour(0.0)
  local layer = job.LayerManager:GetLayerWithName(Layer)
  Contour:AppendPoint(pa)
  Contour:ArcTo(pb, 1)
  Contour:ArcTo(pa, 1)
  layer:AddObject(CreateCadContour(Contour), true)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawLine(Pt1, Pt2, Layer)
--[[Draws a line from Pt1 to Pt2 on the layer name.
  function main(script_path)
  local MyPt1 = Point2D(3.5,3.8)
  local MyPt2 = Point2D(3.5,6.8)
  local layer = "My Line"
  DrawLine(MyPt1 , MyPt2, MyPt3, Layer)
  return true
  end -- function end
  -- -----------------------------------------------------]]</nowiki>
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end
  local line = Contour(0.0)
  local layer = job.LayerManager:GetLayerWithName(Layer)
  line:AppendPoint(Pt1)
  line:LineTo(Pt2)
  layer:AddObject(CreateCadContour(line), true)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawStar(pt1, InRadius ,OutRadius, layer)      --This draw function requires the center point, inter star radius, outer star radius and layer name.
--[[
    function main(script_path)
      local MyPt = Point2D(3.5,3.8)
      local InRadius = 9.0
      local OutRadius= 20.0
      local layer = "My Star"
      DrawStar(MyPt , InRadius ,OutRadius, layer)
      return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end
  local p1 =  Polar2D(pt1,  18.0,  OutRadius)
  local p2 =  Polar2D(pt1,  54.0,  InRadius)
  local p3 =  Polar2D(pt1,  90.0,  OutRadius)
  local p4 =  Polar2D(pt1,  126.0, InRadius)
  local p5 =  Polar2D(pt1,  162.0, OutRadius)
  local p6 =  Polar2D(pt1,  198.0, InRadius)
  local p7 =  Polar2D(pt1,  234.0, OutRadius)
  local p8 =  Polar2D(pt1,  270.0, InRadius)
  local p9 =  Polar2D(pt1,  306.0, OutRadius)
  local p0 =  Polar2D(pt1,  342.0, InRadius)
  local line = Contour(0.0)
-- local layers = job.LayerManager:GetLayerWithName(layer)
  line:AppendPoint(p1);
  line:LineTo(p2);  line:LineTo(p3)
  line:LineTo(p4);  line:LineTo(p5)
  line:LineTo(p6);  line:LineTo(p7)
  line:LineTo(p8);  line:LineTo(p9)
  line:LineTo(p0);  line:LineTo(p1)
  layer:AddObject(CreateCadContour(line), true)
  job:Refresh2DView()
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawTriangle(p1, p2, p3, Layer)
--[[Draw Triangle
    function main(script_path)
      local MyPt1 = Point2D(3.5,3.8)
      local MyPt2 = Point2D(3.5,6.8)
      local MyPt3 = Point2D(9.8,6.8)
      local layer = "My Triangle"
      DrawTriangle(MyPt1 , MyPt2, MyPt3, Layer)
      return true
    end -- function end
  -- -----------------------------------------------------]]</nowiki>
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end
  local line = Contour(0.0)
  local layer = job.LayerManager:GetLayerWithName(Layer)
  line:AppendPoint(p1)
  line:LineTo(p2)
  line:LineTo(p3)
  line:LineTo(p1)
  layer:AddObject(CreateCadContour(line), true)
  job:Refresh2DView()
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Radius2Bulge (p1, p2, Rad)
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
  local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
  local bulge = (2 * seg) / chord
  return bulge
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ChordSeg2Radius (Chr, Seg)
  local rad =  (((Chr * Chr)/(Seg * 4)) + Seg) / 2.0
  return rad
end  -- end Function
-- ====================================================]]
function CreateJob(job_name, width, height, thickness, in_mm, job_origin, z_on_surface)
--[[ ----------- CreateJob -------------------------------------------------
  | This function was provided "as is" by Vectric technical team and a part of the gadget API documentation.
  | Create a new empty job with the passed settings
]]</nowiki>
-- we fill in most of our bounds in a Box2D
local job_bounds = Box2D()
local blc = Point2D(0, 0)
local trc = Point2D(width, height)
local origin_offset = Vector2D(0,0)
-- calculate bottom left corner offset for chosen origin
if Template.DXFOrientation == "Vertical" then
  trc = Point2D(height, width)
  if (job_origin == "BLC") then
    origin_offset:Set(0, 0)
  elseif (job_origin == "BRC") then
    origin_offset:Set(height, 0)
  elseif (job_origin == "TRC") then
    origin_offset:Set(height, width)
  elseif (job_origin == "TLC") then
    origin_offset:Set(0, width)
  elseif (job_origin == "CENTRE") then
    origin_offset:Set(height / 2, width / 2)
  elseif (job_origin == "CENTER") then
    origin_offset:Set(height / 2, width / 2)
  else
    MessageBox("Unknown XY origin specified " .. job_origin)
  end
else
  if (job_origin == "BLC") then
    origin_offset:Set(0, 0)
  elseif (job_origin == "BRC") then
    origin_offset:Set(width, 0)
  elseif (job_origin == "TRC") then
    origin_offset:Set(width, height)
  elseif (job_origin == "TLC") then
    origin_offset:Set(0, height)
  elseif (job_origin == "CENTRE") then
    origin_offset:Set(width / 2, height / 2)
  elseif (job_origin == "CENTER") then
    origin_offset:Set(width / 2, height / 2)
  else
    MessageBox("Unknown XY origin specified " .. job_origin)
  end
end
-- subtract the origin offset vector from our 'standard' corner positions to get position for corners for requested origin
blc = blc - origin_offset
trc = trc - origin_offset
job_bounds:Merge(blc)
job_bounds:Merge(trc)
local success = CreateNewJob(job_name,job_bounds,thickness,in_mm,z_on_surface)
return success
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DrawFontGrid(job)
  local pt = Point2D(0.3,0.3)
  local scl  = 1.0 -- (scl * 0.5)
  local pA0  = pt
  local ang  = 0.0
  local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl))
  local pA2  = Polar2D(pt, ang + 90.0000, (0.5000 * scl))
  local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl))
  local pA4  = Polar2D(pt, ang + 90.0000, (1.0000 * scl))
  local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl))
  local pA6  = Polar2D(pt, ang + 90.0000, (1.5000 * scl))
  local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl))
  local pA8  = Polar2D(pt, ang + 90.0000, (2.0000 * scl))
  local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl))
  local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl))
 
  PointCircle(pA0)
  PointCircle(pA1)
  PointCircle(pA2)
  PointCircle(pA3)
  PointCircle(pA4)
  PointCircle(pA5)
  PointCircle(pA6)
  PointCircle(pA7)
  PointCircle(pA8)
  PointCircle(pA9)
  PointCircle(pA10)
 
  local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl))
  local pB1  = Polar2D(pt, ang + 45.0000, (0.3536 * scl))
  local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl))
  local pB3  = Polar2D(pt, ang + 71.5651, (0.7906 * scl))
  local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl))
  local pB5  = Polar2D(pt, ang + 78.6901, (1.2748 * scl))
  local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl))
  local pB7  = Polar2D(pt, ang + 81.8699, (1.7678 * scl))
  local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl))
  local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl))
 
  PointCircle(pB0)
  PointCircle(pB1)
  PointCircle(pB2)
  PointCircle(pB3)
  PointCircle(pB4)
  PointCircle(pB5)
  PointCircle(pB7)
  PointCircle(pB8)
  PointCircle(pB10)
 
  local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl))
  local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl))
  local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl))
  local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl))
  local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
  local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl))
  local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl))
  local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
  local pC8 = Polar2D(pt, ang + 74.0550, (1.8201 * scl))
  local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl))
 
  PointCircle(pC0)
  PointCircle(pC1)
  PointCircle(pC2)
  PointCircle(pC3)
  PointCircle(pC4)
  PointCircle(pC6)
  PointCircle(pC8)
  PointCircle(pC10)
 
  local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl))
  local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl))
  local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
  local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl))
  local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl))
  local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl))
 
  PointCircle(pD0)
  PointCircle(pD1)
  PointCircle(pD2)
  PointCircle(pD4)
  PointCircle(pD7)
  PointCircle(pD8)
 
  local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl))
  local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl))
  local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
  local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl))
  local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl))
  local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl))
  local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl))
  local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl))
 
  PointCircle(pE0)
  PointCircle(pE1)
  PointCircle(pE2)
  PointCircle(pE3)
  PointCircle(pE5)
  PointCircle(pE6)
  PointCircle(pE7)
  PointCircle(pE8)
 
  local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl))
  local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl))
  local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl))
  local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl))
  local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl))
  local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl))
  local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl))
  local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl))
  local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl))
 
  PointCircle(pF0)
  PointCircle(pF1)
  PointCircle(pF2)
  PointCircle(pF3)
  PointCircle(pF4)
  PointCircle(pF5)
  PointCircle(pF6)
  PointCircle(pF7)
  PointCircle(pF8)
 
  local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl))
  local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl))
  local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl))
  local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl))
  local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl))
  local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl))
  local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl))
  local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl))
  local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl))
  local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))
 
  PointCircle(pG0)
  PointCircle(pG1)
  PointCircle(pG2)
  PointCircle(pG3)
  PointCircle(pG4)
  PointCircle(pG5)
  PointCircle(pG6)
  PointCircle(pG7)
  PointCircle(pG8)
  PointCircle(pG10)
 
  local pH0  = Polar2D(pt, ang + 0.0000, (1.5000 * scl))
  local pH10 = Polar2D(pt, 63.4349,      (2.7951 * scl))
  PointCircle(pH0)
  PointCircle(pH10)
  job:Refresh2DView()
  return true
end
 
</nowiki>
c-- =====================================================]]
<nowiki>
 
function DrawWriter(what, where, size, lay, ang)
  local group
--[[ How to use:
  |    local TextMessage = "Your Text Here"
  |    local TextPt = Point2D(3.5,3.8)
  |    local TextHight = 0.5
  |    local TextLayer = "Jim Anderson"
  |    local TextAng = 20.0
  |    DrawWriter(TextMessage ,local TextPt , TextHight , TextLayer,TextAng )
  |    -- ==Draw Writer==
  |    -- Utilizing a provided string of text, the program walks the string and reproduces each letter (parametrically) on the drawing using vectors.
  function main()
      -- create a layer with passed name if it doesn't already exist
    local job = VectricJob()
    if not job.Exists then
          DisplayMessageBox("No job loaded")
          return false;
    end
    local TextMessage = "Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz 1 2 3 4 5 6 7 8 9 0 ! @ # $ % & * ( ) { } [ ] ? , . : ; '' ' _ - + = ~ ^ < > |"
    local TextPt = Point2D(0.1, 2.0)
    local TextHight = 0.25
    local TextLayer = "Gadget Text"
    local TextAng = 10.0
    DrawWriter(TextMessage, TextPt, TextHight, TextLayer, TextAng)
    job:Refresh2DView()
    return true
  end
 
-- ==============================================================================
local function Polar2D(pt, ang, dis)
  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
end
-- ==============================================================================
local function MonoFont(job, pt, letter, scl, lay, ang)
  scl = (scl * 0.5) ;
  local pA0 = pt ;
  local pA1 = Polar2D(pt, ang + 90.0000, (0.2500 * scl)) ;  local pA2 = Polar2D(pt, ang + 90.0000, (0.5000 * scl)) ;
  local pA3 = Polar2D(pt, ang + 90.0000, (0.7500 * scl)) ;  local pA4 = Polar2D(pt, ang + 90.0000, (1.0000 * scl)) ;
  local pA5 = Polar2D(pt, ang + 90.0000, (1.2500 * scl)) ;  local pA6 = Polar2D(pt, ang + 90.0000, (1.5000 * scl)) ;
  local pA7 = Polar2D(pt, ang + 90.0000, (1.7500 * scl)) ;  local pA8 = Polar2D(pt, ang + 90.0000, (2.0000 * scl)) ;
  local pA9 = Polar2D(pt, ang + 90.0000, (2.2500 * scl)) ;  local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl)) ;
  local pB0 = Polar2D(pt, ang +  0.0000, (0.2500 * scl)) ;  local pB1 = Polar2D(pt, ang + 45.0000, (0.3536 * scl)) ;
  local pB2 = Polar2D(pt, ang + 63.4352, (0.5590 * scl)) ;  local pB3 = Polar2D(pt, ang + 71.5651, (0.7906 * scl)) ;
  local pB4 = Polar2D(pt, ang + 75.9638, (1.0308 * scl)) ;  local pB5 = Polar2D(pt, ang + 78.6901, (1.2748 * scl)) ;
  local pB6 = Polar2D(pt, ang + 80.5376, (1.5207 * scl)) ;  local pB7 = Polar2D(pt, ang + 81.8699, (1.7678 * scl)) ;
  local pB8 = Polar2D(pt, ang + 82.8750, (2.0156 * scl)) ;  local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl)) ;
  local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl)) ;  local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl)) ;
  local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl)) ;  local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl)) ;
  local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;  local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl)) ;
  local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl)) ;  local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;
  local pC8 = Polar2D(pt, ang + 75.9640, (2.0616 * scl)) ;  local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl)) ;
  local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl)) ;  local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl)) ;
  local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl)) ;
  local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl)) ;  local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl)) ;
  local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl)) ;  local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl)) ;
  local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl)) ;
  local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl)) ;  local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl)) ;
  local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl)) ;  local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl)) ;
  local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl)) ;  local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl)) ;
  local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl)) ;  local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl)) ;
  local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl)) ;  local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl)) ;
  local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl)) ;  local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl)) ;
  local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl)) ;  local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl)) ;
  local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl)) ;  local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl)) ;
  local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl)) ;  local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl)) ;
  local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl)) ;  local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl)) ;
  local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl)) ;  local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl)) ;
  local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))      ;  local pH0 = Polar2D(pt, ang +  0.0000, (1.5000 * scl)) ;
  local pH10 = Polar2D(pt,63.4349, (2.7951 * scl))      ;  local layer = job.LayerManager:GetLayerWithName(lay) ;
  local line = Contour(0.0) ;
-- ------------------------------------------------------------------
  if letter == 32 then
    pH0 = pH0
  end
  if letter == 33 then
    line:AppendPoint(pB0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
    line = Contour(0.0) line:AppendPoint(pB3) ;  line:LineTo(pE3) ;  line:LineTo(pE8) ;  line:LineTo(pB8) ;  line:LineTo(pB3) ;  group:AddTail(line) ;
  end
  if letter == 34 then
    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB7) ;  line:LineTo(pC10) ;
    group:AddTail(line) ;  pH0 = pE0
  end
  if letter == 35 then
    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
    line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;
    line = Contour(0.0) ;  line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;
  end
  if letter == 36 then
    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
    line:LineTo(pB4) ;  line:LineTo(pA5) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  group:AddTail(line) ;
    line = Contour(0.0) ;  line:AppendPoint(pC0) ;  line:LineTo(pE0) ;  line:LineTo(pE8) ;  line:LineTo(pC8) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
  end
  if letter == 37 then
    line:AppendPoint(pC6) ;  line:LineTo(pC8) ;  line:LineTo(pA8) ;  line:LineTo(pA6) ;  line:LineTo(pE6) ;  line:LineTo(pG8) ;
    line:LineTo(pA0) ;  line:LineTo(pC2) ;  line:LineTo(pG2) ;  line:LineTo(pG0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
  end
  if letter == 38 then
    line:AppendPoint(pG2) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA3) ;
    line:LineTo(pE6) ;  line:LineTo(pE7) ;  line:LineTo(pD8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA6) ;  line:LineTo(pG0) ;
    group:AddTail(line) ;
  end
  if letter == 39 then
    line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  pH0 = pC0
  end
  if letter == 40 then
    line:AppendPoint(pB8) ;  line:LineTo(pA5) ;  line:LineTo(pA3) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  pH0 = pD0
  end
  if letter == 41 then
    line:AppendPoint(pA8) ;  line:LineTo(pB5) ;  line:LineTo(pB3) ;  line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pG0
  end
  if letter == 42 then
    line:AppendPoint(pA2) ;  line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;  line:LineTo(pG2) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD7) ;
    line:LineTo(pD1) ;  group:AddTail(line) ;
  end
  if letter == 43 then
    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD1) ;  line:LineTo(pD7) ;
    group:AddTail(line)
  end
  if letter == 44 then
    line:AppendPoint(pC0) ;  line:LineTo(pE2) ;  line:LineTo(pC2) ;  line:LineTo(pC4) ;  line:LineTo(pF4) ;  line:LineTo(pF2) ;
    line:LineTo(pD0) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
  end
  if letter == 45 then
    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
  end
  if letter == 46 then
    line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  pH0 = pD0 ;
  end
  if letter == 47 then
    line:AppendPoint(pA0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
  end
  if letter == 48 then
    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG8) ;  line:LineTo(pA0) ; group:AddTail(line) ;
  end
  if letter == 49 then
    line:AppendPoint(pA6) ;  line:LineTo(pD8) ;  line:LineTo(pD0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;
    line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 50 then
    line:AppendPoint(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;
    line:LineTo(pA2) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 51 then
    line:AppendPoint(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
    line:LineTo(pG3) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;
    line:AppendPoint(pF4) ;  line:LineTo(pB4) ;  group:AddTail(line) ;
  end
  if letter == 52 then
    line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;
  end
  if letter == 53 then
    line:AppendPoint(pG8) ;  line:LineTo(pA8) ;  line:LineTo(pA5) ;  line:LineTo(pF4) ;  line:LineTo(pG3) ;  line:LineTo(pG1) ;
    line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
  end
  if letter == 54 then
    line:AppendPoint(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA1) ;  line:LineTo(pB0) ;
    line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
  end
  if letter == 55 then
    line:AppendPoint(pB0) ;  line:LineTo(pG8) ;  line:LineTo(pA8) ;  group:AddTail(line) ;
  end
  if letter == 56 then
    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
    line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;
    line:LineTo(pA3) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB4) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
  end
  if letter == 57 then
    line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG3) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;
    line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  group:AddTail(line) ;
  end
  if letter == 58 then
    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;
    group:AddTail(line) ;  pH0 = pD0 ;
  end
  if letter == 59 then
    line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB3) ;  line:LineTo(pB4) ;  line:LineTo(pA4) ;  line:LineTo(pA3) ;  line:LineTo(pB3) ;
    line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pD0 ;
  end
  if letter == 60 then
    line:AppendPoint(pF8) ;  line:LineTo(pA4) ;  line:LineTo(pG0) ;  group:AddTail(line)
  end
  if letter == 61 then
    line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
    line:LineTo(pG6) ;  group:AddTail(line) ;
  end
  if letter == 62 then
    line:AppendPoint(pA8) ;  line:LineTo(pF4) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 63 then
    line:AppendPoint(pB5) ;  line:LineTo(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pE8) ;  line:LineTo(pF7) ;
    line:LineTo(pF5) ;  line:LineTo(pC3) ;  line:LineTo(pC2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pE0) ;
    line:LineTo(pE1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
  end
  if letter == 64 then
    line:AppendPoint(pG0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;
    line:LineTo(pG6) ;  line:LineTo(pG3) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB5) ;  line:LineTo(pE5) ;  line:LineTo(pE2) ;
    group:AddTail(line)
  end
  if letter == 65 then
    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
    line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 66 then
    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
  end
  if letter == 67 then
    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
  end
  if letter == 68 then
    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
    line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 69 then
    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
  end
  if letter == 70 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
    line:LineTo(pF4) ;  group:AddTail(line) ;
  end
  if letter == 71 then
    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
  end
  if letter == 72 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
  end
  if letter == 73 then
    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
  end
  if letter == 74 then
    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
    group:AddTail(line) ;
  end
  if letter == 75 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 76 then
    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 77 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 78 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
  end
  if letter == 79 then
    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
  end
  if letter == 80 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
    line:LineTo(pA4) ;  group:AddTail(line) ;
  end
  if letter == 81 then
    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
  end
  if letter == 82 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 83 then
    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
  end
  if letter == 84 then
    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
    line:LineTo(pD0) ;  group:AddTail(line) ;
  end
  if letter == 85 then
    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
    group:AddTail(line) ;
  end
  if letter == 86 then
    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
  end
  if letter == 87 then
    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
  end
  if letter == 88 then
    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
    line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 89 then
    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
    line:LineTo(pD4) ;  group:AddTail(line) ;
  end
  if letter == 90 then
    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
 
  if letter == 91 then
    line:AppendPoint(pC0) ;  line:LineTo(pB0) ;  line:LineTo(pB8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;
  end
  if letter == 92 then
    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
  end
  if letter == 93 then
    line:AppendPoint(pE0) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pE8) ;  group:AddTail(line) ;
  end
  if letter == 94 then
    line:AppendPoint(pD8) ;  line:LineTo(pG6) ;  line:LineTo(pG5) ;  line:LineTo(pD7) ;  line:LineTo(pA5) ;  line:LineTo(pA6) ;
    line:LineTo(pD8) ;  group:AddTail(line) ;
  end
  if letter == 95 then
    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  group:AddTail(line) ;
  end
  if letter == 96 then
    line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
  end
  -- Start of Lower Case
  if letter == 97 then
    line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
    line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 98 then
    line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
    line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
  end
  if letter == 99 then
    line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
    line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
  end
  if letter == 100 then
    line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
    line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 101 then
    line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
    line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
  end
  if letter == 102 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
    line:LineTo(pF4) ;  group:AddTail(line) ;
  end
  if letter == 103 then
    line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
    line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
  end
  if letter == 104 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
  end
  if letter == 105 then
    line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
  end
  if letter == 106 then
    line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
    group:AddTail(line) ;
  end
  if letter == 107 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
    group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 108 then
    line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 109 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 110 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
  end
  if letter == 111 then
    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
  end
  if letter == 112 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
    line:LineTo(pA4) ;  group:AddTail(line) ;
  end
  if letter == 113 then
    line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
    line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
  end
  if letter == 114 then
    line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
    line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 115 then
    line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
    line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
  end
  if letter == 116 then
    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
    line:LineTo(pD0) ;  group:AddTail(line) ;
  end
  if letter == 117 then
    line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
    group:AddTail(line) ;
  end
  if letter == 118 then
    line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
  end
  if letter == 119 then
    line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
  end
  if letter == 120 then
    line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
    line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  if letter == 121 then
    line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
    line:LineTo(pD4) ;  group:AddTail(line) ;
  end
  if letter == 122 then
    line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
  end
  -- End of Lower Case
  if letter == 123 then
    line:AppendPoint(pD0) ;  line:LineTo(pC0) ;  line:LineTo(pB1) ;  line:LineTo(pB2) ;  line:LineTo(pC3) ;  line:LineTo(pA4) ;
    line:LineTo(pC5) ;  line:LineTo(pB6) ;  line:LineTo(pB7) ;  line:LineTo(pC8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
  end
  if letter == 124 then
    line:AppendPoint(pA0) ;  line:LineTo(pA10) ;  line:LineTo(pC10) ;  line:LineTo(pC0) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
  end
  if letter == 125 then
    line:AppendPoint(pD0) ;  line:LineTo(pE0) ;  line:LineTo(pF1) ;  line:LineTo(pF2) ;  line:LineTo(pE3) ;  line:LineTo(pG4) ;
    line:LineTo(pE5) ;  line:LineTo(pF6) ;  line:LineTo(pF7) ;  line:LineTo(pE8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
  end
  if letter == 126 then
    line:AppendPoint(pA2) ;  line:LineTo(pA3) ;  line:LineTo(pB5) ;  line:LineTo(pF3) ;  line:LineTo(pG5) ;
    line:LineTo(pG4) ;  line:LineTo(pF2) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
  end
  return pH0
end -- function end
 
-- ==============================================================================
local function AddGroupToJob(job, group, layer_name)
  --  create a CadObject to represent the  group
  local cad_object = CreateCadGroup(group);
  -- create a layer with passed name if it doesnt already exist
  local layer = job.LayerManager:GetLayerWithName(layer_name)
  -- and add our object to it
  layer:AddObject(cad_object, true)
  return cad_object
end -- end function
 
-- =========================================================================
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: Not finding a job loaded")
    return false
  end
  local strlen = string.len(what)
  local strup = what
  local x = strlen
  local i = 1
  local y = ""
  local ptx = where
  group = ContourGroup(true)
  while i <=  x do
    y = string.byte(string.sub(strup, i, i))
    if (y >= 97) and (y <= 122) then -- Lower case
      ptx = MonoFont(job, ptx, y, (size * 0.75), lay, ang)
      ptx = Polar2D(ptx, ang, size * 0.05)
    else -- Upper case
      ptx = MonoFont(job, ptx, y, size, lay, ang)
      ptx = Polar2D(ptx, ang, size * 0.07)
    end
    i = i + 1
  end -- while end;
  AddGroupToJob(job, group, lay)
  job:Refresh2DView()
  return true
end -- Draw Text function end
 
--  ====================================================]]
function Holer(pt, ang, dst, dia, lay)
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: No job loaded")
      return false
    end
  --Caller: Holer(ptx, anx, BaseDim.HoleSpace, Milling.ShelfPinRadius, Milling.LNSideShelfPinDrill .. "-Base")
    local function AddGroupToJob(job, group, layer_name)
      local cad_object = CreateCadGroup(group);
      local layer = job.LayerManager:GetLayerWithName(layer_name)
      layer:AddObject(cad_object, true)
      return cad_object
    end
  local group = ContourGroup(true)
  group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
  pt = Polar2D(pt, ang, dst)
  group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
  AddGroupToJob(job, group, lay)
  return true
end  --  function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- DrawTools function end
 
==Data Export Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╔═╗╔╦╗╔═╗  ╔═╗═╗ ╦╔═╗╔═╗╦═╗╔╦╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║╠═╣ ║ ╠═╣  ║╣ ╔╩╦╝╠═╝║ ║╠╦╝ ║    ║ ║ ║║ ║║  ╚═╗
═╩╝╩ ╩ ╩ ╩ ╩  ╚═╝╩ ╚═╩  ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function ExportTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function LogWriter(LogName, xText)
  -- Adds a new xText Line to a app log file
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
  local fileW = io.open(LogName,  "a")
  if fileW then
    fileW:write(xText .. "\n")
    fileW:close()
  end -- if end
  Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Write_CSV(xFilename) -- Writes the values to a csv format file
-- Usage: Write_CSV("C:\\Path\\MyName.csv")
-- Door.CSVPath = dialog:GetTextField("DoorCSVPath")
-- local filename = Path .. "\\" .. Name .. ".csv"
  local filename = xFilename
  xFilename
  local file = io.open(filename, "w")
  if file then  -- if the file was opened
    file:write("Count,Height,Width\n")  -- Header Line
    if Door.Unit then
      file:write("1,110,595\n");    file:write("1,150,75\n");    file:write("1,175,395\n");    file:write("1,140,495\n")
      file:write("1,175,445\n");    file:write("1,175,595\n");    file:write("2,200,100\n");    file:write("3,250,125\n")
      file:write("1,300,150\n");    file:write("2,350,175\n");    file:write("3,400,200\n");    file:write("1,450,225\n")
      file:write("2,500,250\n");    file:write("3,550,275\n");    file:write("1,600,300\n");    file:write("2,650,325\n")
      file:write("3,700,350\n");    file:write("1,750,375\n");    file:write("2,800,400\n");    file:write("3,850,425\n");
      file:write("1,900,450\n");    file:write("2,950,475\n");    file:write("3,1000,500\n");    file:write("1,1050,525\n");
      file:write("2,1100,550\n");  file:write("3,1150,575\n");  file:write("1,1200,600\n");    file:write("2,1250,625\n");
      file:write("3,1300,650\n");  file:write("1,1350,675\n");  file:write("2,1400,700\n");    file:write("3,1450,725\n");
      file:write("1,1500,750\n");  file:write("2,1550,775\n");  file:write("3,1600,800\n");    file:write("1,1650,825\n");
      file:write("2,1700,850\n");  file:write("3,1750,875\n");  file:write("1,1800,900\n");    file:write("2,1850,925\n");
      file:write("3,1900,950\n");  file:write("1,1950,975\n");  file:write("2,2000,1000\n");  file:write("3,2050,1025\n");
      file:write("1,2100,1050\n");  file:write("2,2150,1075\n");  file:write("3,2200,1100\n");  file:write("1,2250,1125\n");
      file:write("2,2300,1150\n");  file:write("3,2350,1175\n");  file:write("1,2400,1200\n");  file:write("2,2450,1225\n")
    else
      file:write("1,04.5000,23.2500\n");  file:write("1,06.0000,03.3125\n");  file:write("1,06.5000,15.5000\n");  file:write("1,05.3750,19.5000\n");
      file:write("1,07.1875,17.5000\n");  file:write("1,06.1875,23.5000\n");  file:write("2,07.8750,03.8750\n");  file:write("3,09.8750,05.0000\n");
      file:write("1,11.7500,05.8750\n");  file:write("2,13.7500,06.6750\n");  file:write("3,15.7500,07.8750\n");  file:write("1,17.1250,08.8250\n");
      file:write("2,19.5000,09.5000\n");  file:write("3,21.1250,10.3750\n");  file:write("1,23.6250,11.1250\n");  file:write("2,25.5000,12.1250\n");
      file:write("3,27.6250,13.7500\n");  file:write("1,29.5000,14.7500\n");  file:write("2,31.4375,15.7500\n");  file:write("3,33.4375,16.7500\n");
      file:write("1,35.4375,17.7500\n");  file:write("2,37.4375,18.6250\n");  file:write("3,39.3750,19.6250\n");  file:write("1,41.3750,20.6250\n");
      file:write("2,43.3750,21.6250\n");  file:write("3,45.1875,22.6250\n");  file:write("1,47.2500,23.6250\n");  file:write("2,49.1875,24.6250\n");
      file:write("3,51.1250,25.5000\n");  file:write("1,53.1250,26.5000\n");  file:write("2,55.1250,27.5000\n");  file:write("3,57.1250,28.5000\n");
      file:write("1,59.1250,29.5000\n");  file:write("2,61.2500,30.5000\n");  file:write("3,62.9375,31.4375\n");  file:write("1,64.9375,32.4375\n");
      file:write("2,66.9375,33.4375\n");  file:write("3,68.8125,34.4375\n");  file:write("1,70.8750,35.3750\n");  file:write("2,72.9375,36.4375\n");
      file:write("3,74.8750,37.4375\n");  file:write("1,76.9375,38.3750\n");  file:write("2,78.7500,39.3750\n");  file:write("3,80.7500,40.3750\n");
      file:write("1,82.6250,41.3750\n");  file:write("2,84.6250,42.3750\n");  file:write("3,86.6250,43.3750\n");  file:write("1,88.5000,44.2500\n");
      file:write("2,90.6250,45.2500\n");  file:write("3,92.6250,46.2500\n");  file:write("1,94.4375,47.2500\n");  file:write("2,95.4375,48.2500\n")
    end -- if end
    file:close()-- closes the open file
  end -- if end
  return  true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- ExportTools function end
 
 
</nowiki>
 
==Text File Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗═╗ ╦╔╦╗  ╔═╗╦╦  ╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║ ╔╩╦╝ ║  ╠╣ ║║  ║╣    ║ ║ ║║ ║║  ╚═╗
╩ ╩ ╚═ ╩  ╚  ╩╩═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function FileTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function LengthOfFile(filename)                      -- Returns file line count
--[[Counts the lines in a file
    Returns: number]]
    local len = 0
    if FileExists(filename) then
      local file = io.open(filename)
      if file then
      for _ in file:lines() do
        len = len + 1
      end
      file:close()
    end -- if end
    end
    return len
  end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function NameValidater(FileName)
    local MyTrue = true
    local strlen = string.len(FileName)
    local strup = string.upper(FileName)
    local i = 1
    local y = ""
    while i <=  strlen do
      y = string.byte(string.sub(strup, i, i))
      if y == 32 then  --  Space
        MyTrue = false
        break
      elseif y == 45 then  -- Dash
        MyTrue = false
        break
      elseif y == 127 then  -- Delete
        MyTrue = false
        break
      elseif y == 126 then  -- Delete
        MyTrue = false
        break
 
      elseif y == 123 then  -- Open brace
        MyTrue = false
        break
      elseif y == 124 then  -- Pipe
        MyTrue = false
        break
      elseif y == 125 then  -- Close brace
        MyTrue = false
        break
 
      elseif  -- Illegal Filename Characters
      (y == 33) or -- ! Exclamation mark
      (y == 34) or -- " Double Quotes
      (y == 35) or -- # Hash
      (y == 36) or -- $ Dollar
      (y == 37) or -- % Percent
      (y == 38) or -- & Ampersand
      (y == 39) or -- ' Apostrophe
      (y == 42) or -- * Asterisk
      (y == 43) or -- + Plus
      (y == 44) or -- , Comma
      (y == 47) or -- / Slash
      (y == 58) or -- : Colon
      (y == 59) or -- ; Semi-colon
      (y == 60) or -- < Less than
      (y == 62) or -- > Greater than
      (y == 63) or -- ? Question mark
      (y == 64) or -- @ At
      (y == 92) or -- \ Backslash
      (y == 96) or -- ` Single Quotes
      (y == 123) or -- { Open brace
      (y == 124) or -- | Pipe
      (y == 125)    -- } Close brace
      then
        MyTrue = false
        break
      elseif (y <= 31) then -- Control Codes
        MyTrue = false
        break
      elseif (y >= 48) and (y <= 57) then -- Numbers
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      elseif (y >= 97) and (y <= 122) then -- Lowercase A to Z
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      end -- if end
      i = i + 1  end -- while end;
    return MyTrue
  end -- if end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function CopyFileFromTo(OldFile, NewFile)            -- Copy Old File to Newfile
    if FileExists(NewFile) then
      DisplayMessageBox("File copy " .. File .. " failed. \n\nFile found at: " .. NewFile  .. "\n" )
      return false
    elseif not FileExists(OldFile) then
      DisplayMessageBox("File copy of " .. File .. " failed. \n\nFile not found at: " .. OldFile .. "\n" )
      return false
    else
      local fileR = io.open(OldFile)      -- reader file
      local fileW = io.open(NewFile, "w") -- writer file
      if fileR and fileW then  -- if both files are open
        for Line in fileR:lines() do
          fileW:write(Line .. "\n")
        end -- for end
      end
      if fileR then fileR:close() end
      if fileW then fileW:close() end
      return true
    end -- for end
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function ValidateName(FileName)                      -- Returns True if the file name is safe to use
  local MyTrue = true
  local strlen = string.len(FileName)
  local strup = string.upper(FileName)
  local i = 1
  local y = ""
  while i <=  strlen do
    y = string.byte(string.sub(strup, i, i))
    if y == 32 then -- Space
      MyTrue = true
    elseif y == 45 then -- hyphn
      MyTrue = true
    elseif (y >= 48) and (y <= 57) then -- numbers
      MyTrue = true
    elseif (y >= 65) and (y <= 90) then -- Uppercase
      MyTrue = true
    else
      MyTrue = false
      break
    end -- if end
    i = i + 1
  end -- while end
  return MyTrue
end -- if end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function FileExists(name)                            -- Returns True if file is found
  -- call = ans = FileExists("sample.txt")
    local f=io.open(name,"r")
    if f~=nil then io.close(f) return true else io.close(f) return false end
  end -- end function
  -- ===================================================]]
  function FileAccess(FileName)                        -- Returns true if file is available for update.
    if (not(os.rename(FileName, FileName))) then
      StatusMessage("Error", FileName, "The Gadget cannot access the ".. FileName ..
        " The OS has blocked write access. " ..
        "Verify the full path is correct and No application has the file open. ", "(1405)")
        return false
  else
    return true
  end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function isdir(path)                                  -- Returns true if path is found
  local function exists(file)
    local ok, err, code = os.rename(file, file)
    if not ok then
      if code == 13 then
        return true
      end
    end
    return ok, err
  end
  return exists(path.."/")
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function Sheetlabel(Wpt, xTextHeight,  xThickness, xType, YY) -- Constructs sheet label
  local pt1Text = Point2D()
  local Pang    = 0.0
  local Tang    = 0.0
  if YY then
    pt1Text = Polar2D(Polar2D(Wpt, 90.0,  YY), 90.0,  6.0 * JimAndi.Cal)
    Pang = 270.0
    Tang = 0.0
  else
    if Material.Orientation == "V" then
      pt1Text = Polar2D(Wpt, 90.0, Milling.MaterialBlockWidth + (4.0 * JimAndi.Cal))
    else
      pt1Text = Polar2D(Wpt, 90.0,  Milling.MaterialBlockHeight + (4.0 * JimAndi.Cal))
    end
    Pang = 270.0
    Tang = 0.0
  end
  DrawWriter(Project.ProgramName, pt1Text, Milling.TextHeight * 3.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 3.35)
  DrawWriter("Cabinet ID: " .. Project.DrawerID, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
  DrawWriter("Cabinet Name: " .. Project.CabinetName, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
  if xThickness then
    DrawWriter("Material: " .. xThickness .. " " .. xType, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function DiskRights(path)                            -- Returns true if you have write access to path.
  xx = io.open(path, "w")
  if xx == nil then
      io.close()
      return false
  else
      xx:close()
      return true
  end
end -- function rights
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- FileTools function end
 
 
</nowiki>
 
==Geometry Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔═╗╔═╗╔═╗╔╦╗╔═╗╔╦╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
║ ╦║╣ ║ ║║║║║╣  ║ ╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
╚═╝╚═╝╚═╝╩ ╩╚═╝ ╩ ╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function GeometryTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function SheetNew()                                    -- Adds a new sheet to the drawing
  if GetVersion() >= 10.5 then then
    local layer_manager = Milling.job.LayerManager
    -- get current sheet count - note sheet 0 the default sheet counts as one sheet
    local orig_num_sheets = layer_manager.NumberOfSheets
    -- get current active sheet index
    local orig_active_sheet_index = layer_manager.ActiveSheetIndex
    -- set active sheet to last sheet
    local num_sheets = layer_manager.NumberOfSheets
    layer_manager.ActiveSheetIndex = num_sheets - 1
    -- Add a new sheet
    layer_manager:AddNewSheet()
    -- set active sheet to last sheet we just added
    num_sheets = layer_manager.NumberOfSheets
    layer_manager.ActiveSheetIndex = num_sheets - 1
    Milling.job:Refresh2DView()
  end -- if end
  return true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetDiameterAndCentre(cadcontour, point2d)
  local contour = cadcontour:GetContour()
  local arc = contour:GetFirstSpan()
  local point3d = Point3D();
  arc = CastSpanToArcSpan(arc)
  local diameter = arc:RadiusAndCentre(point3d) * 2.0
  point2d = Point2D(point3d.x, point3d.y)
  -- MessageBox("Diameter = " .. diameter)
  return diameter, point2d
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function IsCircle(cadcontour)                          -- Returns True if conture is a circle
  local contour = cadcontour:GetContour()
  -- Does it consist only of arcs?
  if contour.ContainsBeziers then
    return false
  end
  if not contour.ContainsArcs then
    return false
  end
  -- Does is contain 4 contours?
  if contour.Count ~= 4 then
    return false;
  end
  -- Check the arcs end and initial points make a square.
  local arcs = {}
  local count = 1;
  local pos = contour:GetHeadPosition()
  local object
  while pos ~= nil do
    object, pos = contour:GetNext(pos)
    arcs[count] = object
    count = count + 1
  end
  local x_1 =(arcs[1]).StartPoint2D.x
  local y_1 =(arcs[1]).StartPoint2D.y
  local x_3 =(arcs[3]).StartPoint2D.x
  local y_3 =(arcs[3]).StartPoint2D.y
  local x_2 =(arcs[2]).StartPoint2D.x
  local y_2 =(arcs[2]).StartPoint2D.y
  local x_4 =(arcs[4]).StartPoint2D.x
  local y_4 =(arcs[4]).StartPoint2D.y
  local horizontal_distance = (x_1 - x_3)*(x_1 - x_3) + (y_1 - y_3)*(y_1 - y_3)
  local vertical_distance = (x_4 - x_2)*(x_4 - x_2) + (y_2 - y_4)*(y_2 - y_4)
  if math.abs(horizontal_distance - vertical_distance) > 0.04 then
    return false
  end
  -- Check the bulge factor is 90
  local bulge = 0;
  for _, arc_span in ipairs(arcs) do
    bulge = CastSpanToArcSpan(arc_span).Bulge;
    if math.abs(math.abs(bulge)  - g_bulge90) > 0.04 then
      return false
    end
  end
  return true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function SheetSet(Name)                                -- Move focus to a named sheet
  local job = VectricJob()
  local sheet_manager = job.SheetManager
  local sheet_ids = sheet_manager:GetSheetIds()
  for id in sheet_ids do
    if(sheet_manager:GetSheetName(id) == Name) then
    sheet_manager.ActiveSheetId = id
    end
  end
end
-- ====================================================]]
function SheetNextSize(X, Y)                            -- Make New Sheet to size (x, y)
  if X == nil then
    X = Milling.MaterialBlockWidth
  else
    X = X + (2 * Milling.Cal)
  end
  if Y == nil then
    Y = Milling.MaterialBlockHeight
  else
    Y = Y + (2 * Milling.Cal)
  end
  Milling.Sheet = Milling.Sheet + 1
  local sheet_manager = Milling.job.SheetManager
  local sheet_ids = sheet_manager:GetSheetIds()
  for id in sheet_ids do
    if(sheet_manager:GetSheetName(id) == "Sheet 1") then
    sheet_manager:CreateSheets(1, id, Box2D(Point2D(0, 0), Point2D(X, Y)))
    end
  end
  SheetSet("Sheet " .. tostring(Milling.Sheet))
  return true
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetPolarAngle(Start, Corner, End)              -- Returns the Polar Angle
  local function GetPolarDirection(point1, point2)              --
    local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
    if point1.X < point2.X then
      if point1.Y < point2.Y then
        ang = ang + 0.0
      else
        ang = 360.0 - ang
      end -- if end
    else
      if point1.Y < point2.Y then
        ang = 180.0 - ang
      else
        ang = ang + 180.0
      end -- if end
    end -- if end
    if ang >=360 then
      ang = ang -360.0
    end -- if end
    return ang
  end -- function end
  return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetOrientation(point1, point2)                -- Orientation of left, right, up or down
  if DecimalPlaces(point1.X,8) == DecimalPlaces(point2.X,8) then
    if point1.Y < point2.Y then
      return 90.0
    else
      return 270.0
    end
  elseif DecimalPlaces(point1.Y,8) == DecimalPlaces(point2.Y,8) then
    if point1.X < point2.X then
      return 0.0
    else
      return 180.0
    end
  else
    return nil
  end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetPolarDirection(point1, point2)              -- Retuens and amgle from two points
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
  if point1.X < point2.X then
    if point1.Y < point2.Y then
      ang = ang + 0.0
    else
      ang = 360.0 - ang
    end -- if end
  else
    if point1.Y < point2.Y then
      ang = 180.0 - ang
    else
      ang = ang + 180.0
    end -- if end
  end -- if end
  if ang >=360 then
    ang = ang -360.0
  end -- if end
  return ang
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function CenterArc(A, B, RadiusD)                      -- Retuns 2DPoint from Arc point and Radius
  local radius = ((tonumber(RadiusD) or 0) * g_var.scl)
  local horda = (A - B).Length
  if math.abs(radius) < (horda / 2) and radius ~= 0 then
--D("Too small radius " .. radius .. "\nreplaced by the smallest possible " .. (horda / 2))
    radius = (horda / 2)
  end
  return Point2D(((A.x + B.x) / 2 + (B.y - A.y) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda), ((A.y + B.y) / 2 + (A.x - B.x) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda))
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Polar2D(pt, ang, dis)                          -- Retuns 2DPoint from Known Point, Angle direction, and Projected distance.
-- The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance.
-- ::''Returns a 2Dpoint(x, y)''
  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
end -- End Function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetDistance(objA, objB)                        -- Returns Double from two Points
  local xDist = objB.x - objA.x
  local yDist = objB.y - objA.y
  return math.sqrt((xDist ^ 2) + (yDist ^ 2))
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetAngle(point1, point2)
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
  if point1.X < point2.X then
    if point1.Y < point2.Y then
      ang = ang + 0.0
    else
      ang = 360.0 - ang
    end -- if end
  else
    if point1.Y < point2.Y then
      ang = 180.0 - ang
    else
      ang = ang + 180.0
    end -- if end
  end -- if end
  if ang >=360.0 then
    ang = ang -360.0
  end -- if end
  return ang
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Arc2Bulge(p1, p2, Rad)                        -- Returns the Bulge factor for an arc
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
  local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
  local bulge = (2 * seg) / chord
  return bulge
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function TrigIt()                                      -- Calulates Right Angle
-- ==Trig Function==
-- VECTRIC LUA SCRIPT
 
</nowiki>
-- =====================================================]]
<nowiki>
 
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- They are provided 'as-is', without any express or implied warranty, and you
--  make use of them entirely at your own risk.
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages
--  arising from their use.
-- Permission is granted to anyone to use this software for any purpose,
-- including commercial applications, and to alter it and redistribute it freely,
-- subject to the following restrictions:
-- 1. The origin of this software must not be misrepresented; you must not
--    claim that you wrote the original software.
-- 2. If you use this software in a product, an acknowledgement in the product
--    documentation would be appreciated but is not required.
-- 3. Altered source versions must be plainly marked as such, and must not be
--    misrepresented as being the original software.
-- 4. This notice may not be removed or altered from any source distribution.
--
-- Right Triangle TrigFunction is written by Jim Anderson of Houston Texas 2020
 
</nowiki>
-- =====================================================]]
<nowiki>
 
-- Code Debugger
-- require("mobdebug").start()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
-- Global Variables --
    Trig = {}
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function TrigTest() -- Test the All Right Angle
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 1: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 2: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 3: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 4: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 5: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 6: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  9.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 7: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
    " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
    )
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  9.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test Error: \n" ..
      " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
      " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
      " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
      " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
      " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
      " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
      " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
      " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
      " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
      " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
    )
    return true
  end -- function end --
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function TrigClear()  -- Clears and resets Trig Table
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
      local function BSA()
        Trig.B  = (Trig.C - Trig.A)
        Trig.Slope = math.tan(math.rad(Trig.A)) * 12.0
        Trig.Area =  (Trig.Opp * Trig.Adj) * 0.5
        Trig.Inscribing = ((Trig.Opp + Trig.Adj) - Trig.Hyp) * 0.5
        Trig.Circumscribing =  Trig.Hyp * 0.5
        Trig.Parameter = Trig.Opp + Trig.Adj + Trig.Hyp
      end
      if Trig.A == 0.0 and Trig.B > 0.0 and Trig.Slope == 0.0 then
        Trig.A = Trig.C - Trig.B
      elseif Trig.A == 0.0 and Trig.B == 0.0 and Trig.Slope > 0.0 then
        Trig.A = math.deg(math.atan(Trig.Slope / 12.0))
      end -- if end
-- test 4
      if (Trig.A > 0.0) and (Trig.Opp >  0.0) then -- A and Rise or (B2C)
        Trig.Adj =  Trig.Opp / (math.tan(math.rad(Trig.A)))
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        BSA()
        return true
      -- test 6
      elseif (Trig.A > 0.0) and (Trig.Hyp >  0.0)  then -- A and Slope or (A2B)
        Trig.Adj = math.cos(math.rad(Trig.A)) * Trig.Hyp
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
        BSA()
        return true
      -- test 5
      elseif (Trig.A > 0.0) and (Trig.Adj >  0.0)  then -- A and Base or (A2C)
        Trig.Opp = math.tan(math.rad(Trig.A)) * Trig.Adj
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        BSA()
        return true
        -- test 1
      elseif (Trig.Opp >  0.0) and (Trig.Adj >  0.0) then -- Rise and Base
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      elseif (Trig.Adj >  0.0) and (Trig.Hyp >  0.0) then -- Rise and Slope
-- test 2
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      elseif (Trig.Opp >  0.0) and (Trig.Hyp >  0.0) then -- Base and Slope
-- test 3
        Trig.Adj = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Opp * Trig.Opp))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      else
        DisplayMessageBox("Error: Trig Values did not match requirements: \n" ..
                          " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
                          " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
                          " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
                          " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
                          " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
                          " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
                          " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
                          " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
                          " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
                          " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
                          " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
                          )
        return false
      end
    end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Geometry Tools end
 
</nowiki>
 
==INI File Tools==
These functions manipulate the INI files for the storage and retrieval of data.
 
 
===NameStrip===
Convert string to the correct data type.
 
Local Words = NameStrip("KPSDFKSPSK - 34598923", "-") -- returns "KPSDFKSPSK"
 
 
'''Source Code'''
 
<nowiki> function NameStrip(str, var)
    if "" == str then
      DisplayMessageBox("Error in string")
    else
      if string.find(str, var) then
        local j = assert(string.find(str, var) - 1)
        return All_Trim(string.sub(str, 1, j))
      else
        return str
      end
    end
  end -- function end </nowiki>
 
===HeadStrip===
Convert string to the correct data type.
 
<nowiki>
  function HeadStrip(str, var)                            -- convert string to the correct data type
-- Local Words = HeadStrip("LastName23 = Smith", "=") -- returns "Smith"
    if "" == str then
      DisplayMessageBox("Error in string")
    else
      if string.find(str, var) then
        local j = assert(string.find(str, var) + 1)
        return All_Trim(string.sub(str, j))
      else
        return str
      end
    end
  end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_AreDupGroups(xPath, xFile)                -- Are there duplicate groups
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
      CleanNames = RemoveDups(GroupNames)
    if TableLength(GroupNames) == TableLength(CleanNames)then
      return true
    else
      return false
    end
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_FixDupGroups(xPath, xFile)                -- Find and fix duplicate groups
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
    return true
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_DeleteGroup(xPath, xFile, xGroup)          -- Deletes only the first find of xGroup
-- Deletes old ini (.bak) file
-- Copy's the .ini to a backup (.bak) new file
-- Reads the new backup file and writes a new file to the xGroup value
-- Stops Writing lines until next Group is found
-- Writes to end of file
-- Call: DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
    if FileExists(OfileName) then
      os.remove(OfileName)
    end
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
--    os.rename(NfileName, OfileName) -- makes backup copy file
    if CopyFileFromTo(NfileName, OfileName) then
      local fileR  = io.open(OfileName)
      local fileW  = io.open(NfileName,  "w")
      local groups  = false
      local writit  = true
      local MyTxt  = ""
      local txt = ""
      if fileR and fileW then  -- files are open
        for Line in fileR:lines() do  -- read each line of the backup file
          txt = Line  -- copy line from file to txt
          if All_Trim(Line) == "[" .. All_Trim(xGroup) ..  MyTxt .. "]" then  -- look for a match
            groups = true
            txt = ""
          end -- if end
          if groups and MyTxt == "" then  -- if group is true turn off the write function
            writit = false
            if "[" == string.sub(All_Trim(txt), 1, 1) then  -- turns write function on if next group is found
              groups = false
              xGroup = "-"
              writit = true
              MyTxt  = "--"
            else
              writit = false
            end -- if end
          end -- if end
          if writit then
            fileW:write(txt .. "\n")
            txt = ""
          end -- if end
        end -- for end
        os.remove(OfileName)
      end -- if end
      if fileR then fileR:close() end
      if fileW then fileW:close() end
    end
    return true
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_RenameGroup(xOldGroup, xNewGroup)          -- Renames a group
--Deletes old ini Hardware.bak file
--Copys the ini file to a backup copy file
--Reads the backup file and writes a new ini file to the xGroup
--Writes new file with new group  to the new ini file
  local NfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".ini"
  local OfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".bak"
  os.remove(OfileName)
  CopyFileFromTo(NfileName, OfileName) -- makes backup file
  local fileR = io.open(OfileName)
  local fileW = io.open(NfileName, "w")
  if fileR and fileW then
    local groups = false
    local txt = ""
    for Line in fileR:lines() do
      if All_Trim(Line) == "[" .. All_Trim(xOldGroup) .. txt .. "]" then -- Group
        fileW:write(xNewGroup .. "\n")
        txt = "-"
      else
        fileW:write(Line .. "\n")
      end -- if end
    end -- for end
    fileR:close()
    fileW:close()
    os.remove(OfileName)
  end -- if end
  return true
end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_DeleteItem(xPath, xFile, xGroup, xItem)
-- Deletes old ini (.bak) file
-- Copys the .ini to a backup (.bak) new file
-- Reads the new backup file and writes a new file to the xGroup value
-- Stops Writing lines until next Group is found
-- Writes to end of file
-- DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
  local NfileName = xPath .. "\\" .. xFile .. ".ini"
  local OfileName = xPath .. "\\" .. xFile .. ".bak"
  os.remove(OfileName)
  CopyFileFromTo(NfileName, OfileName) -- makes backup copy file
  local fileR = io.open(OfileName)
  local fileW = io.open(NfileName,  "w")
  if fileR and fileW then
    local groups = false
    local writit = true
    local txt = ""
    for Line in fileR:lines() do
      txt = Line
      if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then
        groups = true
      end -- if end
      if groups then
  -- ===================
        if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
          writit = false
          groups = false
        end -- if end
      end -- if end
  -- ===================
      if writit then
        fileW:write(txt .. "\n")
      end -- if end
      writit = true
    end -- for end
    os.remove(OfileName)
    fileR:close()
    fileW:close()
  end -- if end
  return true
end -- function end
 
-- =======================================================]]
  function INI_ValidateGroup(xFile, xGroup)              -- Reads INI file and returns true if group is found
  -- Reads INI file and returns true if the group is found
  local fileR = io.open(xFile)
  local group = false
  for Line in fileR:lines() do
    if string.upper(All_Trim(Line)) == "[" .. string.upper(All_Trim(xGroup)) .. "]" then  -- Group
    group = true
    break
    end -- if end
  end -- for end
  fileR:close()
  return group
end -- function end
-- =======================================================]]
  function INI_ValidateItem(xFile, xGroup, xItem)        -- Reads INI file and returns true if group and item is found
    local fileR = io.open(xFile)
    if fileR then
      local group = false
      local item = false
      local ItemLen = string.len(xItem)
      for Line in fileR:lines() do
        if All_Trim(Line) == "[" ..  string.upper(All_Trim(xGroup)) .. "]" then  -- Group
        group = true
        end -- if end
        if group then
          if string.upper(xItem) == string.upper(string.sub(Line, 1, string.len(xItem)))  then  -- Item
            item = true
            break
          end -- if end
        end -- if end
      end -- for end
      fileR:close()
    end -- if end
    return group
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_StrValue(str, ty)
-- Convert string to the correct data type
    if nil == str then
      DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
    else
      if "" == All_Trim(str) then
        DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
      else
        local j = (string.find(str, "=") + 1)
        if ty == "D" then -- Double
          return tonumber(string.sub(str, j))
        end -- if end
        if ty == "I" then  -- Intiger
          return math.floor(tonumber(string.sub(str, j)))
        end -- if end
        if ty == "S" then  -- String
          return All_Trim(string.sub(str, j))
        end -- if end
        if ty == "B" then  -- Bool
          if "TRUE" == All_Trim(string.sub(str, j)) then
            return true
          else
            return false
          end -- if end
        end -- if end
      end -- if end
    end -- if end
    return nil
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)
    -- ==INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)==
    -- Returns a value from a file, group, and Item
    -- Usage: XX.YY = GetIniValue("C:/temp", "ScrewDia", "[Screws]", "Diameter", "D")
    local filenameR = xPath .. "\\" .. FileName .. ".ini"
    local FL = LengthOfFile(filenameR)
    local file = io.open(filenameR, "r")
    local dat = "."
    local ItemNameLen = string.len(ItemName)
    if file then
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if dat == "[" .. string.upper(GroupName) .. "]" then
          break
        else
          FL = FL - 1
        end -- if end
      end -- while end
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if string.upper(ItemName) == string.sub(dat, 1, ItemNameLen)  then
          break
        else
          FL = FL - 1
          if FL == 0 then
            dat = "Error - item not  found"
            break
          end -- if end
        end -- if end
      end -- while end
      file:close()-- closes the open file
    end -- if end
    local XX = StrIniValue(dat, ValueType)
    return XX
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_GetIDFor(xPath, FileName, GroupName, ItemValue)
    -- == INI_GetIDFor(xPath, FileName, GroupName, ItemValue) ==
    -- Returns a ItemID from a file, group, and ItemValue
    -- Usage: XX.YY = INI_GetIDFor("C:/temp", "UserList", "[Users]", "Anderson")
    -- returns: "UserLastName22"
    local filenameR = xPath .. "\\" .. FileName .. ".ini"
    local FL = LengthOfFile(filenameR)
    local file = io.open(filenameR, "r")
    if file then
      local dat = "."
      local ItemValueLen = string.len(ItemValue)
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if dat == "[" .. string.upper(GroupName) .. "]" then
          break
        else
          FL = FL - 1
        end -- if end
      end -- while end
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if string.upper(ItemValue) == HeadStrip(dat, "=")  then
          break
        else
          FL = FL - 1
          if FL == 0 then
            dat = "Error - item not  found"
            break
          end -- if end
        end -- if end
      end -- while end
      file:close()-- closes the open file
    end -- if end
    local XX = NameStrip(dat, "=")
    return XX
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_ReadGroups(xFile, aName)
  --[[Reads INI and returns a list contain the [Headers] as Array
  IniFile = {} Global variables
  xPath = script_path
  ]]
    local filename = xFile
    local file = io.open(filename, "r")
    if file then
      local fLength = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (fLength >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (aName, string.sub(dat, 2, -2))
        end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          file:close()-- closes the open file
          return true
        end
        fLength = fLength - 1
      end -- while
    end -- if
    if file then file:close() end
    return true
  end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_ProjectHeaderReader(xPath)
  -- ==ProjectHeaderReader(xPath)==
  -- Gets the INI Header values of a ini file and uploads to "IniFile" Array
  --[[
  Gets the INI Header values of a ini file and uploads to "IniFile" Array
  IniFile = {} Global variables
  xPath = script_path
  ]]
    local filename = xPath .. "/CabinetProjects.ini"
    local file = io.open(filename, "r")
    if file then
      local Cabing = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (Cabing >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (Projects, string.sub(dat, 2, -2))
        end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          return true
        end
        Cabing = Cabing - 1
      end
      file:close()
    end
    return true
  end -- function end
 
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_AddNewProject(xPath, xGroup)
  -- Appends a New Project to CabinetProjectQuestion.ini
  -- ==AddNewProject(xPath)==
  -- Appends a New Project to CabinetProjectQuestion.ini
    local filename = xPath .. "/ProjectList.ini"
    local file = io.open(filename, "a")
    if file then
      file:write("[" .. All_Trim(xGroup) .. "] \n")
      file:write("load_date = " .. StartDate(true) .. " \n")
      file:write("#====================================== \n")
      file:close()-- closes the open file
    end
    return true
  end -- function end
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_StdHeaderReader(xPath, Fname)
  -- ==StdHeaderReader(xPath, Fname)==
  -- Gets the INI Header values of a ini file and uploads to "IniFile" Array
  --[[
  Gets the INI Header values of a ini file and uploads to "IniFile" Array
  IniFile = {} Global variables
  xPath = script_path
  ]]
    local filename = xPath .. "\\" .. Fname .. ".ini"
    local file = io.open(filename, "r")
    if file then
      local WallMilling = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (WallMilling >= 0) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (IniFile, string.sub(dat, 2, -2))
        end -- if end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          return true
        end -- if end
        WallMilling = WallMilling - 1
      end -- while end
      file:close()
    end
    return true
  end  -- function end
 
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_ReadProjectinfo(Table, xPath, xGroup, xFile)
-- ProjectQuestion = {}
-- ==ReadProjectinfo(xPath, xGroup, xFile)==
-- Reads an ini files group and sets the table.names
    Table.ProjectContactEmail      = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactEmail", "S")
    Table.ProjectContactName        = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactName", "S")
    Table.ProjectContactPhoneNumber = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactPhoneNumber", "S")
    Table.ProjectName              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectName", "S")
    Table.ProjectPath              = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectPath", "S")
    Table.StartDate                = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.StartDate", "S")
    return true
  end -- function end
 
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_UpdateItem(xPath, xFile, xGroup, xItem, xValue)
  -- Deletes old ini (.bak) file
  -- Copys the .ini to a backup (.bak) new file
  -- Reads the new backup file and writes a new file to the xGroup
  -- Writes new xValue for the for the xItem
  -- Reads and writes a new file to end of file
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
    os.remove(OfileName)
    if CopyFileFromTo(NfileName, OfileName) then-- makes backup file
      local fileR = io.open(OfileName)
      local fileW = io.open(NfileName,  "w")
      if fileR and fileW then
        local groups = false
        local txt = ""
        for Line in fileR:lines() do
          txt = Line
          if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then -- Group
            groups = true
          end -- if end
          if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
            if groups then
              txt = xItem .. " = " .. xValue
              groups = false
            end -- if end
          end -- if end
          fileW:write(txt .. "\n")
          txt = ""
        end -- for end
        os.remove(OfileName)
        fileR:close()
        fileW:close()
      end
    end
    return true
  end -- function end
 
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_ReadProject(xPath, xFile, xGroup)
  -- Milling = {}
    Milling.LayerNameBackPocket          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameBackPocket", "S")
    Milling.LayerNameTopBottomCenterDado = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameTopBottomCenterDado", "S")
    Milling.LayerNameDrawNotes          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawNotes", "S")
    Milling.LayerNameDrawFaceFrame      = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawFaceFrame", "S")
    Milling.BackPocketDepthWall          = GetIniValue(xPath, xFile, xGroup, "Milling.BackPocketDepthWall", "N")
    Milling.BlindDadoSetbackWall        = GetIniValue(xPath, xFile, xGroup, "Milling.BlindDadoSetbackWall", "N")
    Milling.CabDepthWall                = GetIniValue(xPath, xFile, xGroup, "Milling.CabDepthWall", "N")
    return true
  end -- function end
 
 
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function INI_TestDeleteDups()
    --[[ Requires 3 global variables
    clean  = {}
    dups  = {}
    Names  = {}
    ]]
    local myPath = "C:\\Users\\CNC\\Documents\\test"
    local myName = "Tester"
    local myfile = "C:\\Users\\CNC\\Documents\\test\\Tester.ini"
    INI_ReadGroups(myfile, Names)
    FindDups(Names, dups, clean)
    for i,v in ipairs(dups) do
      INI_DeleteGroup(myPath, myName, v)
    end
    return true
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
 
end -- INI_Tools()
 
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- INI Tools end
 
</nowiki>
 
==Data Import Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╔═╗╔╦╗╔═╗  ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║╠═╣ ║ ╠═╣  ║║║║╠═╝║ ║╠╦╝ ║    ║ ║ ║║ ║║  ╚═╗
═╩╝╩ ╩ ╩ ╩ ╩  ╩╩ ╩╩  ╚═╝╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function ImportTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Read_CSV(xFile, Header)
  --Read_CSV(Door.CSVFile, true)
  local fileR = io.open(xFile)
  local xLine = ""
  local result = {}
  if fileR then
    for Line in fileR:lines() do
      xLine = Line
      if Header then
        Header = false
      else
        xLine = All_Trim(Line)
        for match in (xLine..","):gmatch("(.-)"..",") do
          table.insert(result, match)
        end -- for end
        Door.Count    = tonumber(result[1])
        Door.Height    = tonumber(result[2])
        Door.Width    = tonumber(result[3])
 
        result = {}
        while Door.Count > 0 do
          if      Door.Style == StyleA.Name then
            DoorStyleA()
          elseif  Door.Style == StyleB.Name then
            DoorStyleB()
          elseif  Door.Style == StyleC.Name then
            DoorStyleC()
          elseif  Door.Style == StyleE.Name then
            DoorStyleE()
          elseif  Door.Style == StyleF.Name then
            DoorStyleF()
          elseif  Door.Style == StyleG.Name then
            DoorStyleG()
          else
            DisplayMessageBox("No Style Select!")
          end --if end
          Door.Count =  Door.Count - 1
        end -- for end
      end --if end
      Door.Record = Door.Record + 1
      MyProgressBar:SetPercentProgress(ProgressAmount(Door.Record))
    end --for end
  end --if end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- ImportTools function end
 
</nowiki>
 
==Job Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╦╔═╗╔╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║ ║╠╩╗  ║ ║ ║║ ║║  ╚═╗
╚╝╚═╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function JobTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function ValidJob()
  -- A better error message
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: Cannot run Gadget, no drawing found \n" ..
                        "Please create a new file (drawing) and \n" ..
                        "specify the material dimensions \n"
      )
      return false
    else
      return true
    end  -- if end
  end -- ValidJob end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function MoveSetectedVectors(job, NewBasePoint)
    local Selection = job.Selection
    if Selection.IsEmpty then
      MessageBox("LayoutImportedVectors: No vectors selected!")
      return false
    end
    local MySelection = Selection:GetBoundingBox();
    if not NewBasePoint then
      NewBasePoint = Point2D(0,0)
    end
    local MyNewLocatioin = BasePoint - MySelection.BLC
    local Txform = TranslationMatrix2D(MyNewLocatioin)
    Selection:Transform(Txform)
    return true
  end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function FixPath(path)                                -- Lua Returns a fixed path
    return path:gsub("%\\", "/")
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function FixPath(myPath) {                            -- JavaScript Tool Returns a fixed path
    /* myPath  = "C:\\User\\Bob\\Home\\Drawings"; */
    /* NewPath = "C:/User/Bob/Home/Drawings"; */
    var NewPath = "";
    var myLetter = "";
    var CheckPathLen = myPath.length;
    for (let i = 0; i < myPath.length; i++) {
      myLetter = myPath.charAt(i)
      if myLetter.charCodeAt(0) == 92 {
        NewPath = NewPath + "/";
      } else {
        NewPath = NewPath + myLetter;
      }
    }
    return NewPath;
  }
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function GetUnits(UTable)                              -- returns Drawing Units data
    local mtl_block = MaterialBlock()
    if mtl_block.InMM then
      UTable.Units  = "Drawing Units: mm"
      UTable.Unit = true
      UTable.UnitCheck = {"metric", "kilometer", "kilometers", "kh", "meter", "meters", "m", "decimeter", "decimeters", "dm", "centimeter", "centimeters", "cm", "millimeter", "millimeters", "mm"}
      UTable.Cal = 25.4
    else
      UTable.Units  = "Drawing Units: inches"
      UTable.Unit = false
      UTable.UnitCheck = {"imperial", "miles", "mile", "mi", "yards", "yard", "yd", "feet", "foot", "ft", "inches", "inch", "in", "fractions", "fraction"}
      UTable.Cal = 1.0
    end
    return true
  end -- end function
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
function CheckTheUnits(UTable, Value)                    -- Checks if the unit of messure in of drawing units
  local goodtogo = false
  for i=1, #UTable.UnitCheck  do
    if string.upper(Value) == string.upper(UTable.UnitCheck[i]) then
      goodtogo = true
      break
    end -- if end
  end -- for end
  if goodtogo then
    return true
  else
    return false
  end -- if end
end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function GetMatlBlk(Table)
    local mtl_block = MaterialBlock()
    if mtl_block.InMM then
      Table.Units = "Drawing Units: mm"
      Table.Unit = true
    else
      Table.Units = "Drawing Units: inches"
      Table.Unit = false
    end
    if mtl_block.Width> mtl_block.Height then
      Table.MaterialThickness = mtl_block.Height
      Table.MaterialLength = mtl_block.Width
      Table.Orantation = "H"
    else
      Table.MaterialThickness = mtl_block.Width
      Table.MaterialLength = mtl_block.Height
      Table.Orantation = "V"
    end
    Table.FrontThickness = Dovetail.MaterialThickness
    Table.SideThickness = Dovetail.MaterialThickness
    if mtl_block.Height == mtl_block.Width then
        MessageBox("Error! Material block cannot square")
    end
    return true
  end -- end function
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function GetBoxJointMaterialSettings(Table)
    local mtl_block = MaterialBlock()
    --local units
    if mtl_block.InMM then
      Table.Units = "Drawing Units: mm"
      Table.Unit = true
    else
      Table.Units = "Drawing Units: inches"
      Table.Unit = false
    end
    if mtl_block.Width > mtl_block.Height then
      Table.MaterialThickness = mtl_block.Height
      Table.MaterialLength = mtl_block.Width
      Table.Orantation = "H"
    else
      Table.MaterialThickness = mtl_block.Width
      Table.MaterialLength = mtl_block.Height
      Table.Orantation = "V"
    end
    if mtl_block.Height == mtl_block.Width then
      MessageBox("Error! Material block cannot square")
    end
    -- Display material XY origin
    local xy_origin_text = "invalid"
    local xy_origin = mtl_block.XYOrigin
    if  xy_origin == MaterialBlock.BLC then
        Table.xy_origin_text = "Bottom Left Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 90.0
        Table.Direction2 = 0.0
        Table.Direction3 = 270.0
        Table.Direction4 = 180.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 90.0
        Table.Direction3 = 180.0
        Table.Direction4 = 270.0
        Table.Bulge = -1.0
      end
    elseif xy_origin == MaterialBlock.BRC then
      Table.xy_origin_text = "Bottom Right Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 90.0
        Table.Direction2 = 180.0
        Table.Direction3 = 270.0
        Table.Direction4 = 0.0
        Table.Bulge = -1.0
      else
        Table.Direction1 = 180.0
        Table.Direction2 = 90.0
        Table.Direction3 = 0.0
        Table.Direction4 = 270.0
        Table.Bulge = 1.0
      end
    elseif xy_origin == MaterialBlock.TRC then
      Table.xy_origin_text = "Top Right Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 270.0
        Table.Direction2 = 180.0
        Table.Direction3 = 90.0
        Table.Direction4 = 0.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 180.0
        Table.Direction2 = 270.0
        Table.Direction3 = 0.0
        Table.Direction4 = 90.0
        Table.Bulge = -1.0
      end
    elseif xy_origin == MaterialBlock.TLC then
      Table.xy_origin_text = "Top Left Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 270.0
        Table.Direction2 = 0.0
        Table.Direction3 = 90.0
        Table.Direction4 = 180.0
        Table.Bulge = -1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 270.0
        Table.Direction3 = 180.0
        Table.Direction4 = 90.0
        Table.Bulge = 1.0
      end
    elseif xy_origin == MaterialBlock.CENTRE then  -- NOTE: English spelling for Centre!
      Table.xy_origin_text = "Center"
      if Table.Orantation == "V" then
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = -1.0
      end
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
    else
        Table.xy_origin_text = "Unknown XY origin value!"
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
      if Table.Orantation == "V" then
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
      else
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
      end
    end
    -- Setup Fingers and Gaps
    Table.NoFingers0 = 1 + (Rounder(BoxJoint.MaterialLength / BoxJoint.MaterialThickness, 0))
    Table.NoFingers2 = Rounder(BoxJoint.NoFingers0 / 2, 0)
    Table.FingerSize = BoxJoint.MaterialLength /  BoxJoint.NoFingers0
    Table.NoFingers1 = BoxJoint.NoFingers0 - BoxJoint.NoFingers2
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function GetMaterialSettings(Table)
  local MaterialBlock = MaterialBlock()
  Table.MaterialBlockThickness = MaterialBlock.Thickness
  Table.xy_origin = MaterialBlock.XYOrigin
  if MaterialBlock.InMM then
    Table.Units  = "Drawing Units: mm"
    Table.Unit = true
    Table.Cal = 25.4
  else
    Table.Units  = "Drawing Units: inches"
    Table.Unit = false
    Table.Cal = 1.0
  end
  --local units
if MaterialBlock.Width > MaterialBlock.Height then
    Table.Orantation = "H" -- Horizontal
elseif MaterialBlock.Width < MaterialBlock.Height then
    Table.Orantation = "V"  -- Vertical
  else
    Table.Orantation = "S" -- Squair
end
  if Table.xy_origin == MaterialBlock.BLC then
    Table.XYorigin = "Bottom Left Corner"
  elseif Table.xy_origin == MaterialBlock.BRC then
    Table.XYorigin = "Bottom Right Corner"
  elseif Table.xy_origin == MaterialBlock.TRC then
    Table.XYorigin = "Top Right Corner"
  else
    Table.XYorigin = "Top Left Corner"
  end -- if end
  Table.UnitDisplay  = "Note: Units: (" .. Table.Units ..")"
  return true
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function IsSingleSided(Table)
    local SingleSided = Table.job.IsSingleSided
    if not SingleSided then
      DisplayMessageBox("Error: Job must be a single sided job")
      return false
    end  -- if end
  end --IsSingleSided function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function IsDoubleSided(Table)
  if not Table.job.IsDoubleSided then
    DisplayMessageBox("Error: Job must be a Double Sided Project")
    return false
  else
    return true
  end  -- if end
end-- IsDoubleSided function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ShowSetting(Table)
  local name = ""
      DisplayMessageBox(
    name .. " MaterialThickness = " .. tostring(Table.MaterialThickness) .."\n" ..
    name .. " BottleRad        = " .. tostring(Table.BottleRad)        .."\n" ..
    name .. " SideLenght        = " .. tostring(Table.SideLenght)        .."\n" ..
    name .. " SideHight        = " .. tostring(Table.SideHight)        .."\n" ..
    name .. " EndLenght        = " .. tostring(Table.EndLenght)        .."\n" ..
    name .. " EndHight          = " .. tostring(Table.EndHight)          .."\n" ..
    name .. " TopLenght        = " .. tostring(Table.TopLenght)        .."\n" ..
    name .. " TopWidht          = " .. tostring(Table.TopWidht)          .."\n" ..
    name .. " HandleLenght      = " .. tostring(Table.HandleLenght)      .."\n" ..
    name .. " HandleWidht      = " .. tostring(Table.HandleWidht)      .."\n" ..
    name .. " HandleRad        = " .. tostring(Table.HandleRad)        .."\n" ..
    name .. " MillingBitRad    = " .. tostring(Table.MillingBitRad)    .."\n" ..
    "\n")
end -- ShowSettings function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function MakeLayers()
  local Red, Green, Blue = 0, 0, 0
  local function GetColor(str) -- returns color value for a Color Name
    local sx = str
    local Red = 0
    local Green = 0
    local Blue = 0
    local Colors = {}
    Colors.Black = "0,0,0"
    Colors.Red = "255,0,0"
    Colors.Blue = "0,0,255"
    Colors.Yellow = "255,255,0"
    Colors.Cyan = "0,255,255"
    Colors.Magenta = "255,0,255"
    Colors.Green = "0,128,0"
    if "" == str then
      DisplayMessageBox("Error: Empty string passed")
    else
      str = Colors[str]
      if "string" == type(str) then
        if string.find(str, ",") then
          Red  = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          str  = string.sub(str, assert(string.find(str, ",") + 1))
          Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          Blue  = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
        end
      else
        DisplayMessageBox("Error: Color " .. sx .. " not Found" )
        Red = 0
        Green = 0
        Blue = 0
      end
    end
    return Red, Green, Blue
  end
  local layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackPocket)
        Red, Green, Blue = GetColor(Milling.LNBackPocketColor)
        layer:SetColor (Red, Green, Blue)
        layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackProfile)
        Red, Green, Blue = GetColor(Milling.LNBackProfileColor)
        layer:SetColor (Red, Green, Blue)
  return true
end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
function MyLayerClear(LayerName)
  local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
    if Mylayer.IsEmpty then
        Milling.job.LayerManager:RemoveLayer(Mylayer)
    end -- if end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function LayerClear()                                  --  calling MyLayerClear
  MyLayerClear(Milling.LNBackPocket  .. "-Wall")
  MyLayerClear(Milling.LNBackPocket  .. "-Base")
  MyLayerClear(Milling.LNBackProfile .. "-Wall")
  MyLayerClear(Milling.LNBackProfile .. "-Base")
  MyLayerClear("PartLabels")
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
 
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Job Tools end
 
</nowiki>
 
==Logic and Test Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╦  ╔═╗╔═╗╦╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║  ║ ║║ ╦║║    ║ ║ ║║ ║║  ╚═╗
╩═╝╚═╝╚═╝╩╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function LogicTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DialogStringChecks()
  local MyTrue = false
  if Milling.LNBottomProfile == "" then
    MessageBox("Error: Bottom Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSideProfile  == "" then
    MessageBox("Error: Side Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSidePocket  == "" then
    MessageBox("Error: Side Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontProfile == "" then
    MessageBox("Error: Front Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontPocket  == "" then
    MessageBox("Error: Front Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackProfile  == "" then
    MessageBox("Error: Back Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackPocket == "" then
    MessageBox("Error: Back Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNDrawNotes == "" then
    MessageBox("Error: Draw Notes layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNPartLabels == "" then
    MessageBox("Error: Part Lables layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBlume == "" then
    MessageBox("Error: Blume layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Project.ProjectName == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactEmail  == "" then
    MessageBox("Error: Contact Email cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactName == "" then
    MessageBox("Error: Contact Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactPhoneNumber == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.DrawerID == "" then
    MessageBox("Error: Contact Phone Number cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ProjectPath == "" then
    MessageBox("Error: Project Path cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  else
    MyTrue = true
  end -- if end
  return MyTrue
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function CheckNumber(num)
  if type(num) == "number" then
    return true
  else
  return false
  end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function AboveZero(num)
  if (type(num) == "number") and (num > 0.0)then
    return true
  else
  return false
  end -- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- LogicTools function end
 
</nowiki>
 
==File Logging Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╦  ╔═╗╔═╗╔═╗╦╔╗╔╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
║  ║ ║║ ╦║ ╦║║║║║ ╦  ║ ║ ║║ ║║  ╚═╗
╩═╝╚═╝╚═╝╚═╝╩╝╚╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function LoggingTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function LogWriter(xPath, xFile, xText)
  -- Writes new xText Line to a log file
    local LogName = xPath .. "\\" .. xFile .. ".txt"
    local fileW = io.open(LogName,  "a")
    if fileW then
      fileW:write(xText .. "\n")
      fileW:close()
    end
    return true
  end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
  function LogWriter(LogName, xText)
  -- Adds a new xText Line to a app log file
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
    local fileW = io.open(LogName,  "a")
    if fileW then
      fileW:write(xText .. "\n")
      fileW:close()
    end -- if end
    Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Logging Tools Function End
 
</nowiki>
 
==Math Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╔═╗╔╦╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
║║║╠═╣ ║ ╠═╣  ║ ║ ║║ ║║  ╚═╗
╩ ╩╩ ╩ ╩ ╩ ╩  ╩ ╚═╝╚═╝╩═╝╚═╝
function MathTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ArcSegment (p1, p2, Rad)                      -- Returns the Arc Segment
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
  return segment
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function D(x)                                          -- Returns double the value
  return x * 2.0
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function H(x)                                          -- Returns half the value
  return x * 0.5
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function C(x)                                          -- Returns scale value
  return x * Project.Cal
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ChordSag2Radius (Chr, Seg)                    -- Returns the Rad from Chord and Seg
  local rad = ((((Chr * Chr)/(Seg * 4)) + Seg) / 2.0)
  return rad
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RadSag2Chord(Rad, Seg)                        -- Returns the Chord from Rad and Seg
  local Ang = 2 * math.acos(1 - (Seg/Rad))
  local Chord = (2 * Rad) * math.sin(Ang * 0.5)
  return Chord
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RadChord2Segment (Rad, Chord)      -- Returns the Arc Segment from Rad and Chord
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - Chord^2))))
  return segment
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RoundTo(Num, Per)                  -- Returns the number from
  local Head = Num < 0 and math.ceil(Num) or math.floor(Num)
  local Tail = Num - Head
  local Value = Head + tonumber(string.sub(tostring(Tail), 1, Per + 2))
  return Value
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Round(x)
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DecimalPlaces(Dnum, Plac)
  return tonumber(string.sub(tostring(Dnum)  .. "000000000000000000000000000000000000",1, string.len(tostring(math.floor(Dnum))) + 1 + Plac))
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function tointeger( x )
    local num = tonumber( x )
    return num < 0 and math.ceil( num ) or math.floor( num )
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
-- ===TrigIt===
-- Finds all 5 properties of a triangle
  function TrigIt(A, B, AB, AC, BC)
-- Sub Function to help other functions
-- Call = A, B, AB, AC, BC = Trig(A, B, AB, AC, BC)
-- C is the corner, A = small ang and B is the big angle
-- returns all values
-- A, B = angles
-- C = 90.0 Deg
-- B to C (BC) is Run - Base - adjacent
-- A to C (AC) is Rise - Height - opposite
-- A to B (AB) is Slope - hypotenuse
    if (B > 0.0) and (A == 0.0) then
      A = math.deg(math.rad(90) - math.rad(B))
    end
    if (A > 0.0) and (B == 0.0) then
      B = math.deg(math.rad(90) - math.rad(A))
    end
    if  (AC > 0.0) and (BC > 0.0) then
      AB = math.sqrt((AC ^ 2) + (BC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (AB > 0.0) and (BC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (BC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (AB > 0.0) and (AC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (AC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (A > 0.0) and (AC > 0.0) then
      AB = AC / math.cos(math.rad(A))
      BC = AB * math.sin(math.rad(A))
    elseif (A > 0.0) and (BC > 0.0) then
      AB = BC / math.sin(math.rad(A))
      AC = AB * math.cos(math.rad(A))
    elseif (A > 0.0) and (AB > 0.0) then
      BC = AB * math.sin(math.rad(A))
      AC = AB * math.cos(math.rad(A))
    else
      MessageBox("Error: No Missing Value")
    end -- if end
    return A, B, AB, AC, BC
  end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function Maximum (a)                                  -- Returns the Max number from an array
-- print(maximum({8,10,23,12,5}))    --> 23  3
    local mi = 1 -- maximum index
    local m = a[mi]  -- maximum value
    for i,val in ipairs(a)  do
      if val > m then
        mi = i
        m = val
      end -- if end
    end
    return m, mi
  end  -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function IsEven(IsEven_Number)                        -- Returns True/False if number is even
    if (IsEven_Number % 2 == 0) then
      return true
    else
      return false
    end -- if end
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function IsOdd(IsOdd_Number)                            -- Returns True/False if number is odd
    if(IsOdd_Number%2 == 0) then
      return false
    end -- end if
    return true
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Math Tools function End
 
</nowiki>
 
==Registry Read and Write Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╦═╗╔═╗╔═╗╦╔═╗╔╦╗╦═╗╦ ╦  ╔╦╗╔═╗╔═╗╦  ╔═╗
╠╦╝║╣ ║ ╦║╚═╗ ║ ╠╦╝╚╦╝  ║ ║ ║║ ║║  ╚═╗
╩╚═╚═╝╚═╝╩╚═╝ ╩ ╩╚═ ╩    ╩ ╚═╝╚═╝╩═╝╚═╝
function RegistryTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DocVarChk(Name, Value)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:DocumentVariableExists(Name)
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DocVarGet(Name)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:GetDocumentVariable(Name, 0.0)
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function DocVarSet(Name, Value)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:SetDocumentVariable(Name, Value)
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RegistryReadMaterial()                -- Read from Registry Material values for LUA Bit
  local RegistryRead              = Registry("Material")
  Milling.SafeZGap                = Rounder(RegistryRead:GetString("SafeZGap",              "0.500"), 4)
  Milling.StartZGap              = Rounder(RegistryRead:GetString("StartZGap",            "0.500"), 4)
  Milling.HomeX                  = Rounder(RegistryRead:GetString("HomeX",                "0.000"), 4)
  Milling.HomeY                  = Rounder(RegistryRead:GetString("HomeY",                "0.000"), 4)
  Milling.HomeZGap                = Rounder(RegistryRead:GetString("HomeZGap",              "0.750"), 4)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RegistryLastTenFiles(FileName)        -- Adds to the top ten Log file list
  local Registry = Registry(RegName)
  LogFile.File10 = Registry:GetString("LogFile.File09", "No Log Yet" )
  LogFile.File09 = Registry:GetString("LogFile.File08", "No Log Yet" )
  LogFile.File08 = Registry:GetString("LogFile.File07", "No Log Yet" )
  LogFile.File07 = Registry:GetString("LogFile.File06", "No Log Yet" )
  LogFile.File06 = Registry:GetString("LogFile.File05", "No Log Yet" )
  LogFile.File05 = Registry:GetString("LogFile.File04", "No Log Yet" )
  LogFile.File04 = Registry:GetString("LogFile.File03", "No Log Yet" )
  LogFile.File03 = Registry:GetString("LogFile.File02", "No Log Yet" )
  LogFile.File02 = Registry:GetString("LogFile.File01", "No Log Yet" )
  LogFile.File01 = FileName
  return FileName
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RegistryRead()                        -- Read from Registry values
  local RegistryRead = Registry("RegName")
  local Yes_No      = RegistryRead:GetBool("BaseDim.Yes_No", ture)
  local CabHeight    = RegistryRead:GetDouble("BaseDim.CabHeight", 35.500)
  local CabCount    = RegistryRead:GetInt("BaseDim.CabCount", 36)
  local Name        = RegistryRead:GetString("BaseDim.Name", "Words")
 
  Milling.MillTool1.FeedRate                = RegistryRead:GetDouble("Milling.MillTool1.FeedRate",              30.000)
  Milling.MillTool1.InMM                    = RegistryRead:GetBool("Milling.MillTool1.InMM ",                  false)
  Milling.MillTool1.Name                    = RegistryRead:GetString("Milling.MillTool1.Name",                  "No Tool Selected")
  Milling.MillTool1.BitType                = RegistryRead:GetString("Milling.MillTool1.BitType",              "END_MILL") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool1.RateUnits              = RegistryRead:GetInt("Milling.MillTool1.RateUnits",                4)
  Milling.MillTool1.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool1.SpindleSpeed",            20000)
  Milling.MillTool1.ToolNumber              = RegistryRead:GetInt("Milling.MillTool1.ToolNumber",              1)
  Milling.MillTool1.Stepdown                = RegistryRead:GetDouble("Milling.MillTool1.Stepdown",              0.2000)
  Milling.MillTool1.Stepover                = RegistryRead:GetDouble("Milling.MillTool1.Stepover",              0.0825)
  Milling.MillTool1.ToolDia                = RegistryRead:GetDouble("Milling.MillTool1.ToolDia",              0.1250)
  Milling.MillTool1.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool1.PlungeRate",            15.000)
 
  Milling.MillTool2.FeedRate                = RegistryRead:GetDouble("Milling.MillTool2.FeedRate",              30.000)
  Milling.MillTool2.InMM                    = RegistryRead:GetBool("Milling.MillTool2.InMM ",                  false)
  Milling.MillTool2.Name                    = RegistryRead:GetString("Milling.MillTool2.Name",                  "No Tool Selected")
  Milling.MillTool2.BitType                = RegistryRead:GetString("Milling.MillTool2.BitType",              "BALL_NOSE") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool2.RateUnits              = RegistryRead:GetInt("Milling.MillTool2.RateUnits",                4)
  Milling.MillTool2.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool2.SpindleSpeed",            20000)
  Milling.MillTool2.ToolNumber              = RegistryRead:GetInt("Milling.MillTool2.ToolNumber",              2)
  Milling.MillTool2.Stepdown                = RegistryRead:GetDouble("Milling.MillTool2.Stepdown",              0.2000)
  Milling.MillTool2.Stepover                = RegistryRead:GetDouble("Milling.MillTool2.Stepover",              0.0825)
  Milling.MillTool2.ToolDia                = RegistryRead:GetDouble("Milling.MillTool2.ToolDia",              0.1250)
  Milling.MillTool2.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool2.PlungeRate",            15.000)
 
  Milling.MillTool3.FeedRate                = RegistryRead:GetDouble("Milling.MillTool3.FeedRate",              30.000)
  Milling.MillTool3.InMM                    = RegistryRead:GetBool("Milling.MillTool3.InMM",                    false)
  Milling.MillTool3.Name                    = RegistryRead:GetString("Milling.MillTool3.Name",                  "No Tool Selected")
  Milling.MillTool3.BitType                = RegistryRead:GetString("Milling.MillTool3.BitType",              "END_MILL")  -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool3.RateUnits              = RegistryRead:GetInt("Milling.MillTool3.RateUnits",                4)
  Milling.MillTool3.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool3.SpindleSpeed",            20000)
  Milling.MillTool3.ToolNumber              = RegistryRead:GetInt("Milling.MillTool3.ToolNumber",              3)
  Milling.MillTool3.Stepdown                = RegistryRead:GetDouble("Milling.MillTool3.Stepdown",              0.2000)
  Milling.MillTool3.Stepover                = RegistryRead:GetDouble("Milling.MillTool3.Stepover",              0.0825)
  Milling.MillTool3.ToolDia                = RegistryRead:GetDouble("Milling.MillTool3.ToolDia",              0.1250)
  Milling.MillTool3.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool3.PlungeRate",            15.000)
 
  Milling.MillTool4.FeedRate                = RegistryRead:GetDouble("Milling.MillTool4.FeedRate",              30.000)
  Milling.MillTool4.InMM                    = RegistryRead:GetBool("Milling.MillTool4.InMM ",                  false)
  Milling.MillTool4.Name                    = RegistryRead:GetString("Milling.MillTool4.Name",                  "No Tool Selected")
  Milling.MillTool4.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool4.PlungeRate",            15.000)
  Milling.MillTool4.RateUnits              = RegistryRead:GetInt("Milling.MillTool4.RateUnits",                4)
  Milling.MillTool4.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool4.SpindleSpeed",            20000)
  Milling.MillTool4.Stepdown                = RegistryRead:GetDouble("Milling.MillTool4.Stepdown",              0.2000)
  Milling.MillTool4.Stepover                = RegistryRead:GetDouble("Milling.MillTool4.Stepover",              0.0825)
  Milling.MillTool4.ToolDia                = RegistryRead:GetDouble("Milling.MillTool4.ToolDia",              0.1250)
  Milling.MillTool4.ToolNumber              = RegistryRead:GetInt("Milling.MillTool4.ToolNumber",              5)
 
  Milling.MillTool5.FeedRate                = RegistryRead:GetDouble("Milling.MillTool5.FeedRate",              30.000)
  Milling.MillTool5.InMM                    = RegistryRead:GetBool("Milling.MillTool5.InMM ",                  false)
  Milling.MillTool5.Name                    = RegistryRead:GetString("Milling.MillTool5.Name",                  "No Tool Selected")
  Milling.MillTool5.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool5.PlungeRate",            15.000)
  Milling.MillTool5.RateUnits              = RegistryRead:GetInt("Milling.MillTool5.RateUnits",                4)
  Milling.MillTool5.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool5.SpindleSpeed",            20000)
  Milling.MillTool5.Stepdown                = RegistryRead:GetDouble("Milling.MillTool5.Stepdown",              0.2000)
  Milling.MillTool5.Stepover                = RegistryRead:GetDouble("Milling.MillTool5.Stepover",              0.0825)
  Milling.MillTool5.ToolDia                = RegistryRead:GetDouble("Milling.MillTool5.ToolDia",              0.1250)
  Milling.MillTool5.ToolNumber              = RegistryRead:GetInt("Milling.MillTool5.ToolNumber",              6)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function RegistryWrite()                      -- Write to Registry values
  local RegistryWrite = Registry("RegName")
  local RegValue
  RegValue = RegistryWrite:SetBool("ProjectQuestion.CabinetName", true)
  RegValue = RegistryWrite:SetDouble("BaseDim.CabDepth", 23.0000)
  RegValue = RegistryWrite:SetInt("BaseDim.CabHeight", 35)
  RegValue = RegistryWrite:SetString("BaseDim.CabLength", "Words")
 
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.FeedRate" ,    Milling.MillTool1.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool1.InMM",            Milling.MillTool1.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool1.Name",          Milling.MillTool1.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool1.BitType",      Milling.MillTool1.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.PlungeRate" ,  Milling.MillTool1.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.RateUnits",        Milling.MillTool1.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.SpindleSpeed",    Milling.MillTool1.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepdown" ,    Milling.MillTool1.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepover" ,    Milling.MillTool1.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.ToolDia" ,      Milling.MillTool1.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.ToolNumber",      Milling.MillTool1.ToolNumber)
 
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.FeedRate" ,    Milling.MillTool2.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool2.InMM",            Milling.MillTool2.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool2.Name",          Milling.MillTool2.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool2.BitType",      Milling.MillTool2.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.PlungeRate" ,  Milling.MillTool2.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.RateUnits",        Milling.MillTool2.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.SpindleSpeed",    Milling.MillTool2.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepdown" ,    Milling.MillTool2.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepover" ,    Milling.MillTool2.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.ToolDia" ,      Milling.MillTool2.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.ToolNumber",      Milling.MillTool2.ToolNumber)
 
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.FeedRate" ,    Milling.MillTool3.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool3.InMM",            Milling.MillTool3.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool3.Name",          Milling.MillTool3.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool3.BitType",      Milling.MillTool3.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.PlungeRate",    Milling.MillTool3.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.RateUnits",        Milling.MillTool3.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.SpindleSpeed",    Milling.MillTool3.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepdown" ,    Milling.MillTool3.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepover" ,    Milling.MillTool3.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.ToolDia" ,      Milling.MillTool3.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.ToolNumber",      Milling.MillTool3.ToolNumber)
 
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.FeedRate" ,    Milling.MillTool4.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool4.InMM",            Milling.MillTool4.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool4.Name",          Milling.MillTool4.Name)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.PlungeRate" ,  Milling.MillTool4.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.RateUnits",        Milling.MillTool4.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.SpindleSpeed",    Milling.MillTool4.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepdown" ,    Milling.MillTool4.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepover" ,    Milling.MillTool4.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.ToolDia" ,      Milling.MillTool4.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.ToolNumber",      Milling.MillTool4.ToolNumber)
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function REG_CheckRegistryBool()              -- Checks Registry for Bool values
  local RegistryRead = Registry("RegName")
  if RegistryRead:BoolExists("ProjectQuestion.Runtool") then
    DisplayMessageBox("Alert: The Runtool value is saved.")
  else
    DisplayMessageBox("Alert: The Runtool value is not saved.")
  end -- if end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function REG_CheckRegistryDouble()            -- Checks Registry for Double values
  local RegistryRead = Registry("RegName")
  if RegistryRead:DoubleExists("ProjectQuestion.ProjectCost") then
    DisplayMessageBox("Alert: The project cost is saved.")
  else
    DisplayMessageBox("Alert: The Project Cost is not saved.")
  end -- if end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function REG_CheckRegistryInt()                -- Checks Registry for Int values
  local RegistryRead = Registry("RegName")
  if RegistryRead:IntExists("ProjectQuestion.ProjectCount") then
    DisplayMessageBox("Alert: The Project Count is saved.")
  else
    DisplayMessageBox("Alert: The Project Count is not saved.")
  end -- if end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function REG_CheckRegistryString()            -- Checks Registry for String values
  local RegistryRead = Registry("RegName")
  if RegistryRead:StringExists("ProjectQuestion.ProjectPath") then
    DisplayMessageBox("Alert: The Project path is saved.")
  else
    DisplayMessageBox("Alert: The Project path is not saved.")
  end
  return true
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
end -- Registry end
 
</nowiki>
 
==String Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔═╗╔╦╗╦═╗╦╔╗╔╔═╗  ╔╦╗╔═╗╔═╗╦  ╔═╗
╚═╗ ║ ╠╦╝║║║║║ ╦  ║ ║ ║║ ║║  ╚═╗
╚═╝ ╩ ╩╚═╩╝╚╝╚═╝  ╩ ╚═╝╚═╝╩═╝╚═╝
function StringTools()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function StringToArraySplit(s, delimiter)
--[[
split_string = StringToArraySplit("Hello World,Jim,Bill,Tom", ",")
Returns = array
-- split_string[1] = "Hello World,)
-- split_string[2] = "Jim"
]]
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
      table.insert(result, match)
  end
  return result
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function WrapString(Str, Wid)                          -- wraps text at the nearest space and puts a return char in the space location
  --[[  How to use:
  Call WrapString(string, Number)
WrapString("Jim is a tall man that lives in Texas. He was raised in North East Texas on 1000 acres from 1970 to 1982. This is a man that knows numbers of great people from a round the world.", 40)
returns "Jim is a tall man that lives in Texas.\n
          He was raised in North East Texas on\n
          1000 acres from 1970 to 1982. This is a man\n
          that knows numbers of great people from\n
          a round the world."
]]
  local Wider = Wid
  local Posx = string.len(Str)
  local StrLen = string.len(Str)
  local pt = 0
  local function FindSpace(MyStr)
  local Pos = string.len(MyStr)
  local str = MyStr
    if string.find(MyStr, " ") ~= nil then
      while Pos>0 do
        Pos = Pos - 1
          if (string.byte(string.sub(str,-1)) == 32) then
            break
          else
            str = string.sub(str, 1, Pos)
          end
        end
    end
    return Pos
  end
  if StrLen > Wider then
    while Wider < Posx do
      pt = FindSpace(string.sub(Str,1, Wider))
      Str = string.sub(Str, 1, pt) .. "\n" ..  string.sub(Str, pt +2)
      Wider = Wider + Wid
    end
  end
  return Str
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function CleanString(inStr)                            -- Check for ascii letters below 127
  local outStr, str1 = ""
  local inStrLen = string.len(inStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(inStr, i, i)
    if string.byte(str1) <= 127 then
    outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
 
</nowiki> 
-- =====================================================]]
<nowiki>
 
function CheckString(YourStr)                          -- Check string for specal bite chars for HTML
  local function FindLetter(TheStr, TestChar)
    local outStr = false
    local strChar = ""
    local TheStrLen = string.len(TheStr)
    for i = 1, TheStrLen ,1 do
      strChar = string.sub(TheStr, i, i)
      if string.byte(strChar) == string.byte(TestChar) then
        outStr = true
        break
      end
    end
    return outStr
  end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  local StrTest = false
  StrTest = SwitchLetter(YourStr,  "&")  -- Non frendly File Name letters
  StrTest = SwitchLetter(YourStr,  "#")
  StrTest = SwitchLetter(YourStr,  "@")
  StrTest = SwitchLetter(YourStr,  "^")
  StrTest = SwitchLetter(YourStr,  "$")
    return outStr
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function MakeHTMLReady(MyStr)                          -- fixs string with specal bite chars for HTML
  local function SwitchLetter(MyStr, MyChar, NewStr)
  local outStr, str1 = ""
  local inStrLen = string.len(MyStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(MyStr, i, i)
    if string.byte(str1) == string.byte(MyChar) then
    outStr=outStr .. NewStr
    else
        outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  local outStr = ""
  outStr = SwitchLetter(MyStr, "!", "&#33;")
  outStr = SwitchLetter(outStr, "#", "&#35;")
  outStr = SwitchLetter(outStr, "$", "&#36;")
  outStr = SwitchLetter(outStr, "%", "&#37;")
  outStr = SwitchLetter(outStr, "&", "&#38;")
  outStr = SwitchLetter(outStr, "'", "&#39;")
  outStr = SwitchLetter(outStr, "(", "&#40;")
  outStr = SwitchLetter(outStr, ")", "&#41;")
  outStr = SwitchLetter(outStr, "*", "&#42;")
  outStr = SwitchLetter(outStr, "+", "&#43;")
  outStr = SwitchLetter(outStr, ",", "&#44;")
  outStr = SwitchLetter(outStr, "-", "&#45;")
  outStr = SwitchLetter(outStr, ".", "&#46;")
  outStr = SwitchLetter(outStr, "/", "&#47;")
  outStr = SwitchLetter(outStr, ":", "&#58;")
  outStr = SwitchLetter(outStr, ";", "&#59;")
  outStr = SwitchLetter(outStr, "<", "&#60;")
  outStr = SwitchLetter(outStr, "=", "&#61;")
  outStr = SwitchLetter(outStr, ">", "&#62;")
  outStr = SwitchLetter(outStr, "?", "&#63;")
  outStr = SwitchLetter(outStr, "@", "&#64;")
  outStr = SwitchLetter(outStr, "[", "&#91;")
  outStr = SwitchLetter(outStr, "]", "&#93;")
  outStr = SwitchLetter(outStr, "^", "&#94;")
  outStr = SwitchLetter(outStr, "_", "&#95;")
  outStr = SwitchLetter(outStr, "`", "&#96;")
  outStr = SwitchLetter(outStr, "{", "&#123")
  outStr = SwitchLetter(outStr, "|", "&#124")
  outStr = SwitchLetter(outStr, "}", "&#125")
  outStr = SwitchLetter(outStr, "~", "&#126")
    return outStr
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function SwitchLetter(MyStr, MyChar, NewStr)            -- swwap a leter for another letter
  local outStr, str1 = ""
  local inStrLen = string.len(MyStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(MyStr, i, i)
    if string.byte(str1) == string.byte(MyChar) then
    outStr=outStr .. NewStr
    else
        outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function PadC(str, lenth)                        -- Adds spaces to front and back to center text in lenth
-- Local Word = PadC("K", 12) -- returns "    K      "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  if string.len(str) < lenth then
  local a = math.floor(lenth - string.len(str) * 0.5) - 2
  local b = math.ceil(lenth - string.len(str) * 0.5) - 2
  --print ("a = " .. a)
  for _ = 1, a, 1 do
    str =  " " .. str
  end
  for _ = 1, b, 1 do
    str =  str .. " "
  end
  --print ("str len = " .. #str)
  end
  return str
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function PadR(str, len)                        -- Adds spaces to Back of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "KPSDFKSPSK  "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = str .. " "
  end
  return str
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function PadL(str, len)              -- Adds spaces to Front of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "  KPSDFKSPSK"
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = " " .. str
  end
  return str
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function NumberPad(str, front, back) -- Adds spaces to front and zeros to the back of string
  local mychar
  local  a,b,c,d = 0,0,0,0
  local x,y,z = "","",""
  if type(str) ~= "string" then
    str = tostring(str)
  end
  c = string.len(str)
  for i = 1, c, 1 do
    mychar = string.byte(string.sub(str, i,i))
    if mychar == 46 then
      b = i
    end
  end
--  print("b = " .. b)
  if b == 0 then
    str = str .. "."
    c = c + 1
    b = c
  end -- if loc
  x = string.sub(str, 1, b-1)
  y = string.sub(str, b+1)
  a = c - b
  a = #x
  d = #y
  if a < front then
    front = front - (a - 1)
    for _ = 1, front -1 do
      x = " " .. x
    end -- end for front
  end
  back = back - (c - b)
  for i = 1, back  do
    y = y .. "0"
  end -- end for back
  str =  x .. "." .. y
  return str
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function All_Trim(s)                          -- Trims spaces off both ends of a string
  return s:match( "^%s*(.-)%s*$" )
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function Make_Proper_Case(str)
  local str=string.gsub(string.lower(str),"^(%w)", string.upper)
  return string.gsub(str,"([^%w]%w)", string.upper)
end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ifT(x)                                -- Converts Boolean True or False to String "Yes" or "No"
-- ===ifT(x)===
  if x then
    return "Yes"
  else
    return "No"
  end-- if end
end -- function end
 
</nowiki>
-- =====================================================]]
<nowiki>
 
function ifY(x)                                -- Converts String "Yes" or "No" to Boolean True or False
-- ===ifY(x)===
  if string.upper(x) == "YES" then
    return true
  else
    return false
  end-- if end
end -- function end
-- =***************************************************=]]
end -- String function end
 
</nowiki>
 
==Seed Documents==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
function SeedTool()
  -- VECTRIC LUA SCRIPT
-- =====================================================]]
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.
-- Permission is granted to anyone to use this software for any purpose,
-- including commercial applications, and to alter it and redistribute it freely,
-- subject to the following restrictions:
-- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
-- 2. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.
-- 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-- 4. This notice may not be removed or altered from any source distribution.
-- Easy Seed Gadget Master is written by Jim Anderson of Houston Texas 2020
-- =====================================================]]
-- require("mobdebug").start()
-- require "strict"
local Tools
-- Global Variables --
local Ver = "1.0"  -- Version 7: Aug 2021 - Clean Up and added Ver to Dialog
 
-- Table Names
Milling = {}
Project = {}
 
-- =====================================================]]
 
function main(script_path)
--[[
Gadget Notes: Dec 2019 - My New Gadget
  ]]
-- Localized Variables --
 
-- Job Validation --
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end
 
  Tools = assert(loadfile(script_path .. "\\EasyGearToolsVer" .. Ver .. ".xlua")) (Tools) -- Load Tool Function
-- Get Data --
 
-- Calculation --
 
-- Do Something --
 
 
  return true
end  -- function end
-- ==================== End ============================]]
</nowiki>
 
==Setup Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔═╗╔═╗╔╦╗╦ ╦╔═╗
╚═╗║╣  ║ ║ ║╠═╝
╚═╝╚═╝ ╩ ╚═╝╩
function SetupAndLetter Seeds()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function LUA_Seed()
    -- VECTRIC LUA SCRIPT
    -- ==============================================================================
    --  Gadgets are an entirely optional add-in to Vectric's core software products.
    --  They are provided 'as-is', without any express or implied warranty, and you
    --  make use of them entirely at your own risk.
    --  In no event will the author(s) or Vectric Ltd. be held liable for any damages
    --  arising from their use.
    --  Permission is granted to anyone to use this software for any purpose,
    --  including commercial applications, and to alter it and redistribute it freely,
    --  subject to the following restrictions:
    --  1. The origin of this software must not be misrepresented;
    --    you must not claim that you wrote the original software.
    --    If you use this software in a product, an acknowledgement in the product
    --    documentation would be appreciated but is not required.
    --  2. Altered source versions must be plainly marked as such, and
    --    must not be misrepresented as being the original software.
    --  3. This notice may not be removed or altered from any source distribution.
    -- ==============================================================================
    -- "AppName Here" was written by JimAndi Gadgets of Houston Texas
    -- ==============================================================================
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    -- require("mobdebug").start()
    -- require "strict"
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
    -- Global variables
 
</nowiki>   
-- =====================================================]]
<nowiki>
 
  end -- lua function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function Install_letter()
  -- Steps to Install:
 
  -- 1. Download the gadget x.zip that is attached to this post.
  -- 2. Rename it from x.zip to x.vgadget
  -- 3. In Vectric Pro or Aspire click on Gadgets -> Install Gadget and navigate to where you downloaded the file to, select it and click Ok.
 
  -- It should give you a pop up saying the gadget was installed and you should see x in the Gadgets menu.
 
  -- Image Here
 
  -- Steps for Use:
  -- 1. Select a layer that you want to calculate for
  -- 2. Enter the cut depth
  -- 3. Enter the percentage of coverage for the area that will be filled in
  -- 4. Enter the hardner to resin percentage
  -- 5. Click the Calculate Button and the results will be displayed below in the Results Pane.
  end -- install function
 
end -- Header function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
 
</nowiki>
 
==Toolpathing Tools==
This object is a name-value pair that represents a Document Variable within a [[VectricJob]].
 
<nowiki>
 
</nowiki>
-- =====================================================]]
<nowiki>
 
╔╦╗╔═╗╔═╗╦  ╔═╗╔═╗╔╦╗╦ ╦╔═╗
║ ║ ║║ ║║  ╠═╝╠═╣ ║ ╠═╣╚═╗
╩ ╚═╝╚═╝╩═╝╩  ╩ ╩ ╩ ╩ ╩╚═╝
function Toolpaths()
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function CreateLayerProfileToolpath(name, layer_name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
    -- clear current selection
    local selection = job.Selection
    selection:Clear()
    -- get layer
    local layer = job.LayerManager:FindLayerWithName(layer_name)
    if layer == nil then
      DisplayMessageBox("No layer found with name = " .. layer_name)
      return false
    end
    -- select all closed vectors on the layer
    if not SelectVectorsOnLayer(layer, selection, true, false, true) then
      DisplayMessageBox("No closed vectors found on layer " .. layer_name)
      return false
    end
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
 
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local profile_data = ProfileParameterData()
    -- start depth for toolpath
    profile_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    profile_data.CutDepth = cut_depth
    -- direction of cut - ProfileParameterData.
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- side we machine on - ProfileParameterData.
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
    -- ProfileParameterData.PROFILE_ON
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
    -- Allowance to leave on when machining
    profile_data.Allowance = 0.0
    -- true to preserve start point positions, false to reorder start
    -- points to minimise toolpath length
    profile_data.KeepStartPoints = false
    -- true if want to create 'square' external corners on toolpath
    profile_data.CreateSquareCorners = false
    -- true to perform corner sharpening on internal corners (only with v-bits)
    profile_data.CornerSharpen = false
    -- true to use tabs (position of tabs must already have been defined on vectors)
    profile_data.UseTabs = false
    -- length for tabs if being used
    profile_data.TabLength = 5.0
    -- Thickness for tabs if being used
    profile_data.TabThickness = 1.0
    -- if true then create 3d tabs else 2d tabs
    profile_data.Use3dTabs = true
    -- if true in Aspire, project toolpath onto composite model
    profile_data.ProjectToolpath = false
    -- Create object used to control ramping
    local ramping_data = RampingData()
    -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
    -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
    -- or RampingData.CONSTRAIN_ANGLE
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
    -- if we are constraining ramp by distance, distance to ramp over
    ramping_data.RampDistance = 100.0
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function CreateProfileToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local profile_data = ProfileParameterData()
    -- start depth for toolpath
    profile_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    profile_data.CutDepth = cut_depth
    -- direction of cut - ProfileParameterData.
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- side we machine on - ProfileParameterData.
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
    -- ProfileParameterData.PROFILE_ON
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
    -- Allowance to leave on when machining
    profile_data.Allowance = 0.0
    -- true to preserve start point positions, false to reorder start
    -- points to minimise toolpath length
    profile_data.KeepStartPoints = false
    -- true if want to create 'square' external corners on toolpath
    profile_data.CreateSquareCorners = false
    -- true to perform corner sharpening on internal corners (only with v-bits)
    profile_data.CornerSharpen = false
    -- true to use tabs (position of tabs must already have been defined on vectors)
    profile_data.UseTabs = false
    -- length for tabs if being used
    profile_data.TabLength = 5.0
    -- Thickness for tabs if being used
    profile_data.TabThickness = 1.0
    -- if true then create 3d tabs else 2d tabs
    profile_data.Use3dTabs = true
    -- if true in Aspire, project toolpath onto composite model
    profile_data.ProjectToolpath = false
    -- Create object used to control ramping
    local ramping_data = RampingData()
    -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
    -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
    -- or RampingData.CONSTRAIN_ANGLE
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
    -- if we are constraining ramp by distance, distance to ramp over
    ramping_data.RampDistance = 100.0
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function CreatePocketingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_stepover_percent, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * (tool_stepover_percent / 100)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC,...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * (tool_stepover_percent / 100) -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass pocketing options
    local pocket_data = PocketParameterData()
    -- start depth for toolpath
    pocket_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    pocket_data.CutDepth = cut_depth
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or
    -- ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- Allowance to leave on when machining
    pocket_data.Allowance = 0.0
    -- if true use raster clearance strategy , else use offset area clearance
    pocket_data.DoRasterClearance = true
    -- angle for raster if using raster clearance
    pocket_data.RasterAngle = 0
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
    -- if true we ramp into pockets (always zig-zag)
    pocket_data.DoRamping = false
    -- if ramping, distance to ramp over
    pocket_data.RampDistance = 10.0
    -- if true in Aspire, project toolpath onto composite model
    pocket_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- if we are doing two tool pocketing define tool to use for area clearance
    local area_clear_tool = nill
    -- we just create a tool twice as large for testing here
    area_clear_tool = Tool("Lua Clearance End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    area_clear_tool.InMM = tool_in_mm
    area_clear_tool.ToolDia = tool_dia * 2
    area_clear_tool.Stepdown = tool_stepdown * 2
    area_clear_tool.Stepover = tool_dia * 2 *(tool_stepover_percent / 100)
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC..
    area_clear_tool.FeedRate = 30
    area_clear_tool.PlungeRate = 10
    area_clear_tool.SpindleSpeed = 20000
    area_clear_tool.ToolNumber = 1
    area_clear_tool.VBit_Angle = 90.0 -- used for vbit only
    area_clear_tool.ClearStepover = tool_dia*2*(tool_stepover_percent/100) -- used for vbit
  -- Create our toolpath
    local toolpath_manager = ToolpathManager()
     local toolpath_id = toolpath_manager:CreatePocketingToolpath(name,tool,area_clear_tool,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nill then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>
 
  function CreateDrillingToolpath(name, start_depth, cut_depth, retract_gap, tool_dia, tool_stepdown, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua Drill", Tool.THROUGH_DRILL) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
     tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
     tool.FeedRate = 30
     tool.PlungeRate = 10
     tool.SpindleSpeed = 20000
     tool.ToolNumber = 1
     tool.VBit_Angle = 90.0 -- used for vbit only
     tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
     -- Create object used to set home position and safez gap above material surface
     -- Create object used to set home position and safez gap above material surface
     local pos_data = ToolpathPosData()
     local pos_data = ToolpathPosData()  
     pos_data:SetHomePosition(0, 0, 1.0)
     vcarve_data:SetHomePosition(Milling.HomeX, Milling.HomeY, Milling.HomeZGap ) -- vcarve_data:SetHomePosition(0, 0, 1.0)
     pos_data.SafeZGap = 5.0
     vcarve_data.SafeZGap = Milling.SafeZGap -- vcarve_data.SafeZGap = 0.5
     -- Create object used to pass profile options
     local vcarve_data = VCarveParameterData() -- Create object used to pass pocketing options - used for area clearance only
     local drill_data = DrillParameterData()
     vcarve_data.StartDepth = start_depth    -- start depth for toolpath
    -- start depth for toolpath
     vcarve_data.DoFlatBottom = flat_depth > 0.0    -- flag indicating if we are creating a flat bottomed toolpath
     drill_data.StartDepth = start_depth
     vcarve_data.FlatDepth = flat_depth    -- cut depth for toolpath this is depth below start depth
     -- cut depth for toolpath this is depth below start depth
     vcarve_data.ProjectToolpath = false    -- if true in Aspire, project toolpath onto composite model
     drill_data.CutDepth = cut_depth
     vcarve_data.UseAreaClearTool = true    -- set flag indicating we are using flat tool
    -- if true perform peck drilling
     local pocket_data = PocketParameterData()   -- Create object used to pass pocketing options - used for area clearance only
    drill_data.DoPeckDrill = retract_gap > 0.0
     pocket_data.StartDepth = start_depth    -- start depth for toolpath
    -- distance to retract above surface when peck drilling
     pocket_data.CutDepth = flat_depth    -- cut depth for toolpath this is depth below start depth
    drill_data.PeckRetractGap = retract_gap
     pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    -- if true in Aspire, project toolpath onto composite model
     drill_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
     local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view,
    -- if false we dont
     local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
     local display_warnings = true
    -- Create our toolpath
     local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateDrillingToolpath(name,tool,drill_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function
 
</nowiki>
-- =====================================================]]
<nowiki>


  function CreateVCarvingToolpath(name, start_depth, flat_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
    --[[ -------------- CreateVCarvingToolpath --------------
    |
    | Create a VCarving toolpath within the program for the currently selected vectors
    | Parameters:
    | name, -- Name for toolpath
    | start_depth -- Start depth for toolpath below surface of material
    | flat_depth -- flat depth - if 0.0 assume not doing flat bottom
    | vbit_angle -- angle of vbit to use
    | vbit_dia -- diameter of VBit to use
    | vbit_stepdown -- stepdown for tool
    | tool_stepover_percent - percentage stepover for tool
    | tool_in_mm -- true if tool size and stepdown are in mm
    |
    | Return Values:
    | true if toolpath created OK else false
    |
  ]]
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua VBit",Tool.VBIT )-- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = vbit_dia
    tool.Stepdown = vbit_stepdown
    tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    -- vcarve_data:SetHomePosition(0, 0, 1.0)
    vcarve_data:SetHomePosition(Milling.HomeX, Milling.HomeY, Milling.HomeZGap )
    -- vcarve_data.SafeZGap = 0.5
    vcarve_data.SafeZGap = Milling.SafeZGap
    -- Create object used to pass pocketing options - used for area clearance only
    local vcarve_data = VCarveParameterData()
    -- start depth for toolpath
    vcarve_data.StartDepth = start_depth
    -- flag indicating if we are creating a flat bottomed toolpath
    vcarve_data.DoFlatBottom = flat_depth > 0.0
    -- cut depth for toolpath this is depth below start depth
    vcarve_data.FlatDepth = flat_depth
    -- if true in Aspire, project toolpath onto composite model
    vcarve_data.ProjectToolpath = false
    -- set flag indicating we are using flat tool
    vcarve_data.UseAreaClearTool = true
    -- Create object used to pass pocketing options - used for area clearance only
    local pocket_data = PocketParameterData()
    -- start depth for toolpath
    pocket_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    pocket_data.CutDepth = flat_depth
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION
    -- or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
     -- if true use raster clearance strategy , else use offset area clearance
     -- if true use raster clearance strategy , else use offset area clearance
     pocket_data.DoRasterClearance = false
     pocket_data.DoRasterClearance = false
Line 12,952: Line 6,535:
     area_clear_tool.SpindleSpeed = 20000
     area_clear_tool.SpindleSpeed = 20000
     area_clear_tool.ToolNumber = 2
     area_clear_tool.ToolNumber = 2
     -- Create object which can be used to automatically select geometry
     local geometry_selector = GeometrySelector()    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
     -- Create our toolpath
     -- Create our toolpath
     local toolpath_manager = ToolpathManager()
     local toolpath_manager = ToolpathManager()
     local toolpath_id = toolpath_manager:CreateVCarvingToolpath(name,tool,area_clear_tool,vcarve_data,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
     local toolpath_id = toolpath_manager:CreateVCarvingToolpath(name,tool, area_clear_tool,vcarve_data, pocket_data,pos_data,geometry_selector, create_2d_previews,display_warnings)
     if toolpath_id == nil then
     if toolpath_id == nil then
       DisplayMessageBox("Error creating toolpath")
       DisplayMessageBox("Error creating toolpath")
Line 12,962: Line 6,544:
     end
     end
     return true
     return true
end -- end function
end -- end function</nowiki>


</nowiki>
----
-- =====================================================]]
<nowiki>


  function CreatePrismToolpath(name, start_depth, cut_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
===CreatePrismToolpath===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function CreatePrismToolpath(name, start_depth, cut_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
   --[[ ------------------- CreatePrismToolpath -------------------
   --[[ ------------------- CreatePrismToolpath -------------------
   |
   |
Line 13,017: Line 6,599:
     if min_bevel_depth > cut_depth then
     if min_bevel_depth > cut_depth then
       DisplayMessageBox("A prism will not be fully formed with a depth of " .. cut_depth .. "\r\n" ..
       DisplayMessageBox("A prism will not be fully formed with a depth of " .. cut_depth .. "\r\n" ..
                         "A depth of " .. min_bevel_depth .. " is required to fully form the prism"
                         "A depth of " .. min_bevel_depth .. " is required to fully form the prism")
                        )
     end -- if end
     end -- if end
     -- Create object which can be used to automatically select geometry
     -- Create object which can be used to automatically select geometry
Line 13,034: Line 6,615:
     end -- if end
     end -- if end
     return true
     return true
end -- end function
end -- end function</nowiki>


</nowiki>
----
-- =====================================================]]
<nowiki>


  function CreateFlutingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
===CreateFlutingToolpath===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function CreateFlutingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
     --[[ ----------------- CreateFlutingToolpath -----------------
     --[[ ----------------- CreateFlutingToolpath -----------------
   | Create a flutting toolpath within the program for the currently selected vectors
   | Create a flutting toolpath within the program for the currently selected vectors
Line 13,107: Line 6,688:
     end
     end


     end -- end function
     end -- end function</nowiki>


</nowiki>
----
-- =====================================================]]
<nowiki>


  function SelectVectorsOnLayer(layer, selection, select_closed, select_open, select_groups)
===SelectVectorsOnLayer===
[[File:TopOfPage.png|right|50px|link=JimAndi Toolbox]]
<nowiki>function SelectVectorsOnLayer(layer, selection, select_closed, select_open, select_groups)
     -- Please Note: SelectVectorsOnLayer is provided by Vectric and can be found in the SDK and Sample Gadget files.
     -- Please Note: SelectVectorsOnLayer is provided by Vectric and can be found in the SDK and Sample Gadget files.
     --[[  ---------------- SelectVectorsOnLayer ----------------
     --[[  ---------------- SelectVectorsOnLayer ----------------
Line 13,165: Line 6,746:
     return objects_selected
     return objects_selected
   end -- function end
   end -- function end
 
</nowiki>  
</nowiki>
[[Category:SDK]]
-- =====================================================]]
 
 
[[File:Back.jpg|right|50px|link=Vectric Lua Interface for Gadgets]]
==References==
==References==
'''Please Note:''' The base material for the contents found in this WiKi was sourced from Vectric Lua Interface for Gadgets, version 10.0, published August 21, 2019. by Vectric Ltd. Most current document from Vertric can be downloaded at [https://gadgets.vectric.com/developerinfo.html Vertric Developer Information]
'''Please Note:''' The base material for the contents found in this WiKi was sourced from Vectric Lua Interface for Gadgets, version 10.0, published August 21, 2019. by Vectric Ltd. Most current document from Vertric can be downloaded at [https://gadgets.vectric.com/developerinfo.html Vertric Developer Information]
=]]
end -- Toolpaths function end

Latest revision as of 10:21, 16 November 2024

Back.jpg

Table and Array Tools

This object is a name-value pair that represents a Document Variable within a VectricJob.

ArrayClear

TopOfPage.png

ArrayClear - Clears the data from a data array.

local tbl = {1, 2, 5, 6}

tbl = ArrayClear(tbl)

returns tbl = {}

 function ArrayClear(arrayName)
   for _,v in ipairs(arrayName) do
     table.remove(arrayName, i)
   end -- for end
   return true
  end -- function end 

NameCheck

TopOfPage.png

Checks if Name is in the list of it is default name.

a = {1, 2, 5, 6}

Words = NameCheck(a, 5) -- returns true

  function NameCheck(Name, Defalt, ListName)
     if Name ~= Defalt then
       for i=1, ListName do
         if Name == i then
           return true
         end
       end
       return false
     else
       return  true
     end
  end -- function end 

RemoveDuplicates

TopOfPage.png

Returns table of unique items in "A" acending or "D" decending

local tbl = {1, 2, 5, 3, 5, 6, 4}

tbl = ArrayClear(tbl, "A")

returns tbl = {1, 2, 3, 4, 5, 6}
  function RemoveDuplicates(tab, order)
     local hashSet = {}
     local new = {}
     local value
     for i = 1, #tab do
       value = (tab[i])
       if hashSet[value] == nil then
         table.insert(new, value)
         hashSet[value] = true
       end
     end
     if string.upper(order) =="A" then
       table.sort(new)
     else
       table.sort(new, function(a, b) return a > b end)
     end
     return new
  end -- function end 

RemoveTableItem

TopOfPage.png

Returns table with item removed.

local tbl = {1, 2, 3, 4, 5, 6}

tbl = RemoveTableItem(tbl, 4)

returns tbl = {1, 2, 3, 5, 6}
  function RemoveTableItem(tabName, tabItem)
     for x = 1 in ipairs(tabName) do
       if tabName[x] == tabItem then
          table.remove(tabName, i)
       end
     end -- for end
     return true
  end -- function end 

TableLength

TopOfPage.png
 Returns table item count
 local tbl = {1, 2, 3, 4, 5, 6}
 tbl = TableLength(tbl)

 returns tbl = 6
-- =====================================================]]
  function TableLength(tbl)
     -- tbl = {7, 6, 5, 4, 3, 2, 1}
     local count = 0
     for _ in pairs(tbl) do
       count = count + 1
     end
     return count
  end -- function end 

FindDups

TopOfPage.png

Find all duplicate items and returns two tables the dup and clean tables

Returns table item count

local tbl = {1, 2, 2, 4, 4, 6}

local tbl1 = {}

local tbl2 = {}

tbl1, tbl2 = TableLength(tbl)

returns tbl1, tbl2 = 6

 function FindDups(checktbl, duptbl, cleantbl)
     function tLength(tbl) -- tLength returns table count
       local count = 0
       for _ in pairs(tbl) do
         count = count + 1
       end
       return count
     end
     -- =================================
     local trip = false
     for i=1, tLength(checktbl) do
       for x=1, tLength(cleantbl) do
         if cleantbl[x] == checktbl[i] then
           trip = true
         end
       end
       if trip then
         table.insert(duptbl,   checktbl[i])
       else
         table.insert(cleantbl, checktbl[i])
       end
       trip = false
     end
     return table.sort(duptbl), table.sort(cleantbl)
  end -- function end 

ReverseTable

TopOfPage.png

Returns a reversed table

local tbl = {1, 2, 3, 4, 5, 6}

tbl = ReverseTable(tbl)

returns tbl = {6, 5, 4, 3, 2, 1}

 function ReverseTable(tbl)
    --tbl = {7, 6, 7, A, 5, 4, 3, A, 2, 1}
     local n = #tbl
     local i = 1
     while i < n do
       tbl[i],tbl[n] = tbl[n],tbl[i]
       i = i + 1
       n = n - 1
     end
     return tbl
  end -- function end 

Conversion Tools

Back.jpg

This collection of functions that assist in the conversion activities.

Bool2Str

TopOfPage.png

bool2Str - Converts true or false as a string. local x = true tbl = bool2Str(x) -- =====================================================]] returns "true" function Bool2Str(x) if x then return "true" else return "false" end end --function end


D2S8

TopOfPage.png
 D2S8 - Converts a Number (Double) to a String with 8 places

 function D2S8(d)                               -- Converts a Number (Double) to a String with 8 places
-- local x =12.2351
-- returns "12.23510000"
-- =====================================================]]
    return string.format("%.8f", d)
  end -- end function 

D2S4

TopOfPage.png
 D2S4 - Converts a Number (Double) to a String with 4 places
 local x =12.23
  = D2S4(x)

 returns x = "12.2300"
-- =====================================================]]
  function D2S4(d) 
    return string.format("%.4f", d)
  end -- end function 

Toint

TopOfPage.png
 Toint - Converts a Double Number to a intiger
 local x = 12.23
  = toint(x)

 returns x = 12
  function toint(number)
    return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
  end -- end function 

Rounder

TopOfPage.png
 return tonumber(string.format("%." .. (idp or 0) .. "f", n

-- =====================================================]]
function Rounder(num, idp)                              --  Rounds a Number (Double) up or down
  return tonumber(string.format("%." .. (idp or 0) .. "f", num))
end -- end function 

RUsame

TopOfPage.png
-- =====================================================]]
function RUsame(num, comp)                              --  Rounds a Number (Double) up or down
  local function toint(number)
    return math.floor(tonumber(number) or error("Could not cast '" .. tostring(number) .. "' to number.'"))
  end
  local function Rounder(num, idp)                      --  Rounds a Number (Double) up or down
    return tonumber(string.format("%." .. (idp or 0) .. "f", num))
  end -- end function
        num = math.abs(num)
  local idp = #comp
  local Mynum = Rounder(num, idp)
  local Myint = toint(Mynum)
  local Myval = tonumber(tostring(Myint) .. "." .. comp)
  if (Mynum == Myval) then
    return true
  else
    return false
  end -- if end
end -- end function 

WithIn

TopOfPage.png

Retuns true if number is within tolerance with match


 function WithIn(Num, Mat, Tol)
    if ((Num >= (Mat - Tol)) and (Num <= (Mat + Tol))) then
      return true
    end -- if end
    return false
  end -- end function 

Double2Fraction

TopOfPage.png

Converts a Measurement (Double) to a Fractional String

local txt = Double2Fraction(1.25)

returns txt ="1-1/4"

 function Double2Fraction(Num)
  local Frac = "Error"
  if Num then
    Frac = tostring(Num)
  end
  if (not Milling.Unit) and Num then
    local AmountValuex = math.floor(math.abs(Num))
    local DicValue    = Num - AmountValuex
    local AmountValue = tostring(AmountValuex)
    Frac              = tostring(DicValue)

    if Project.Fractions == "No Fractions" then
      Frac = tostring(Num)

    elseif Project.Fractions == "1/8" then
      if     DicValue >= 0.9375 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.8125 then Frac = "7/8" .. string.char(34)
      elseif DicValue >= 0.6875 then Frac = "3/4" .. string.char(34)
      elseif DicValue >= 0.5625 then Frac = "5/8" .. string.char(34)
      elseif DicValue >= 0.4375 then Frac = "1/2" .. string.char(34)
      elseif DicValue >= 0.3125 then Frac = "3/8" .. string.char(34)
      elseif DicValue >= 0.1875 then Frac = "1/4" .. string.char(34)
      elseif DicValue >= 0.0625 then Frac = "1/8" .. string.char(34)
      else
        Frac = "0"
      end
    elseif Project.Fractions == "1/16" then
      if     DicValue >= 0.96875 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.90625 then Frac = "15/16" .. string.char(34)
      elseif DicValue >= 0.84375 then Frac = "7/8"   .. string.char(34)
      elseif DicValue >= 0.78125 then Frac = "13/16" .. string.char(34)
      elseif DicValue >= 0.71875 then Frac = "3/4"   .. string.char(34)
      elseif DicValue >= 0.65625 then Frac = "11/16" .. string.char(34)
      elseif DicValue >= 0.59375 then Frac = "5/8"   .. string.char(34)
      elseif DicValue >= 0.53125 then Frac = "9/16"  .. string.char(34)
      elseif DicValue >= 0.46875 then Frac = "1/2"   .. string.char(34)
      elseif DicValue >= 0.40625 then Frac = "7/16"  .. string.char(34)
      elseif DicValue >= 0.34375 then Frac = "3/8"   .. string.char(34)
      elseif DicValue >= 0.28125 then Frac = "5/16"  .. string.char(34)
      elseif DicValue >= 0.21875 then Frac = "1/4"   .. string.char(34)
      elseif DicValue >= 0.15625 then Frac = "3/16"  .. string.char(34)
      elseif DicValue >= 0.09375 then Frac = "1/8"   .. string.char(34)
      elseif DicValue >= 0.03125 then Frac = "1/16"  .. string.char(34)
      else
        Frac = "0"
      end -- If end
    elseif Project.Fractions == "1/32" then
      if     DicValue >= 0.984375 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
      elseif DicValue >= 0.953126 then Frac = "31/32" .. string.char(34)
      elseif DicValue >= 0.921876 then Frac = "15/16" .. string.char(34)
      elseif DicValue >= 0.890626 then Frac = "29/32" .. string.char(34)
      elseif DicValue >= 0.859376 then Frac = "7/8"   .. string.char(34)
      elseif DicValue >= 0.828126 then Frac = "27/32" .. string.char(34)
      elseif DicValue >= 0.796876 then Frac = "13/16" .. string.char(34)
      elseif DicValue >= 0.765626 then Frac = "25/32" .. string.char(34)
      elseif DicValue >= 0.737376 then Frac = "3/4"   .. string.char(34)
      elseif DicValue >= 0.703126 then Frac = "23/32" .. string.char(34)
      elseif DicValue >= 0.671876 then Frac = "11/16" .. string.char(34)
      elseif DicValue >= 0.640626 then Frac = "21/32" .. string.char(34)
      elseif DicValue >= 0.609376 then Frac = "5/8"   .. string.char(34)
      elseif DicValue >= 0.578126 then Frac = "19/32" .. string.char(34)
      elseif DicValue >= 0.541260 then Frac = "9/16"  .. string.char(34)
      elseif DicValue >= 0.515626 then Frac = "17/32" .. string.char(34)
      elseif DicValue >= 0.484376 then Frac = "1/2"   .. string.char(34)
      elseif DicValue >= 0.468760 then Frac = "15/32" .. string.char(34)
      elseif DicValue >= 0.421876 then Frac = "7/16"  .. string.char(34)
      elseif DicValue >= 0.390626 then Frac = "13/32" .. string.char(34)
      elseif DicValue >= 0.359376 then Frac = "3/8"   .. string.char(34)
      elseif DicValue >= 0.328126 then Frac = "11/32" .. string.char(34)
      elseif DicValue >= 0.296876 then Frac = "5/16"  .. string.char(34)
      elseif DicValue >= 0.265626 then Frac = "9/32"  .. string.char(34)
      elseif DicValue >= 0.234376 then Frac = "1/4"   .. string.char(34)
      elseif DicValue >= 0.203126 then Frac = "7/32"  .. string.char(34)
      elseif DicValue >= 0.171876 then Frac = "3/16"  .. string.char(34)
      elseif DicValue >= 0.140626 then Frac = "5/32"  .. string.char(34)
      elseif DicValue >= 0.109376 then Frac = "1/8"   .. string.char(34)
      elseif DicValue >= 0.078126 then Frac = "3/32"  .. string.char(34)
      elseif DicValue >= 0.046876 then Frac = "1/16"  .. string.char(34)
      elseif DicValue >= 0.015626 then Frac = "1/32"  .. string.char(34)
      else
        Frac = "0"
      end -- If end
    elseif Project.Fractions == "1/64" then
      if     DicValue >= 0.9921875 then
        AmountValue = tostring(AmountValuex + 1)
        Frac = "0"
        elseif DicValue >= 0.9765625 then Frac = "62/64" .. string.char(34)
        elseif DicValue >= 0.9609375 then Frac = "31/32" .. string.char(34)
        elseif DicValue >= 0.9453125 then Frac = "61/64" .. string.char(34)
        elseif DicValue >= 0.9296875 then Frac = "15/16" .. string.char(34)
        elseif DicValue >= 0.9140625 then Frac = "59/64" .. string.char(34)
        elseif DicValue >= 0.8984375 then Frac = "29/32" .. string.char(34)
        elseif DicValue >= 0.8828125 then Frac = "57/64" .. string.char(34)
        elseif DicValue >= 0.8671875 then Frac = "7/8"   .. string.char(34)
        elseif DicValue >= 0.8515625 then Frac = "55/64" .. string.char(34)
        elseif DicValue >= 0.8359375 then Frac = "27/32" .. string.char(34)
        elseif DicValue >= 0.8203125 then Frac = "53/64" .. string.char(34)
        elseif DicValue >= 0.8046875 then Frac = "13/16" .. string.char(34)
        elseif DicValue >= 0.7890625 then Frac = "51/64" .. string.char(34)
        elseif DicValue >= 0.7734375 then Frac = "25/32" .. string.char(34)
        elseif DicValue >= 0.7578125 then Frac = "49/64" .. string.char(34)
        elseif DicValue >= 0.7421875 then Frac = "3/4"   .. string.char(34)
        elseif DicValue >= 0.7265625 then Frac = "47/64" .. string.char(34)
        elseif DicValue >= 0.7109375 then Frac = "23/32" .. string.char(34)
        elseif DicValue >= 0.6953125 then Frac = "45/64" .. string.char(34)
        elseif DicValue >= 0.6796875 then Frac = "11/16" .. string.char(34)
        elseif DicValue >= 0.6640625 then Frac = "43/64" .. string.char(34)
        elseif DicValue >= 0.6484375 then Frac = "21/32" .. string.char(34)
        elseif DicValue >= 0.6328125 then Frac = "41/64" .. string.char(34)
        elseif DicValue >= 0.6171875 then Frac = "5/8"   .. string.char(34)
        elseif DicValue >= 0.6015625 then Frac = "39/64" .. string.char(34)
        elseif DicValue >= 0.5859375 then Frac = "19/32" .. string.char(34)
        elseif DicValue >= 0.5703125 then Frac = "37/64" .. string.char(34)
        elseif DicValue >= 0.5546875 then Frac = "9/16"  .. string.char(34)
        elseif DicValue >= 0.5390625 then Frac = "35/64" .. string.char(34)
        elseif DicValue >= 0.5234375 then Frac = "17/32" .. string.char(34)
        elseif DicValue >= 0.5078125 then Frac = "33/64" .. string.char(34)
        elseif DicValue >= 0.4921875 then Frac = "1/2"   .. string.char(34)
        elseif DicValue >= 0.4765625 then Frac = "31/64" .. string.char(34)
        elseif DicValue >= 0.4609375 then Frac = "15/32" .. string.char(34)
        elseif DicValue >= 0.4453125 then Frac = "29/32" .. string.char(34)
        elseif DicValue >= 0.4296875 then Frac = "7/16"  .. string.char(34)
        elseif DicValue >= 0.4140625 then Frac = "27/64" .. string.char(34)
        elseif DicValue >= 0.3984375 then Frac = "13/32" .. string.char(34)
        elseif DicValue >= 0.3828125 then Frac = "25/64" .. string.char(34)
        elseif DicValue >= 0.3671875 then Frac = "3/8"   .. string.char(34)
        elseif DicValue >= 0.3515625 then Frac = "23/64" .. string.char(34)
        elseif DicValue >= 0.3359375 then Frac = "11/32" .. string.char(34)
        elseif DicValue >= 0.3203125 then Frac = "21/64" .. string.char(34)
        elseif DicValue >= 0.3046875 then Frac = "5/16"  .. string.char(34)
        elseif DicValue >= 0.2890625 then Frac = "19/64" .. string.char(34)
        elseif DicValue >= 0.2734375 then Frac = "9/32"  .. string.char(34)
        elseif DicValue >= 0.2578125 then Frac = "17/64" .. string.char(34)
        elseif DicValue >= 0.2421875 then Frac = "1/4"   .. string.char(34)
        elseif DicValue >= 0.2265625 then Frac = "15/64" .. string.char(34)
        elseif DicValue >= 0.2109375 then Frac = "7/32"  .. string.char(34)
        elseif DicValue >= 0.1953125 then Frac = "13/64" .. string.char(34)
        elseif DicValue >= 0.1796875 then Frac = "3/16"  .. string.char(34)
        elseif DicValue >= 0.1640625 then Frac = "11/64" .. string.char(34)
        elseif DicValue >= 0.1484375 then Frac = "5/32"  .. string.char(34)
        elseif DicValue >= 0.1328125 then Frac = "9/64"  .. string.char(34)
        elseif DicValue >= 0.1171875 then Frac = "1/8"   .. string.char(34)
        elseif DicValue >= 0.1015625 then Frac = "7/64"  .. string.char(34)
        elseif DicValue >= 0.0859375 then Frac = "3/32"  .. string.char(34)
        elseif DicValue >= 0.0703125 then Frac = "5/64"  .. string.char(34)
        elseif DicValue >= 0.0546875 then Frac = "1/16"  .. string.char(34)
        elseif DicValue >= 0.0390625 then Frac = "3/64"  .. string.char(34)
        elseif DicValue >= 0.0234375 then Frac = "1/32"  .. string.char(34)
        elseif DicValue >= 0.0078125 then Frac = "1/64"  .. string.char(34)
        else
          Frac = "0"
        end -- If end
      end
    if Project.Fractions == "No Fractions" then
      Frac = tostring(Num)
    else
      if Frac == "0" then
        Frac = AmountValue .. string.char(34)
      else
        if AmountValue ~= "0" then
          Frac = AmountValue .. "-" .. Frac
        end
      end
    end
  end
  return Frac
end -- end function 

Time and Date Tools

Back.jpg

This collection of functions are utilized in the date and time calculations.

StartDateTime

TopOfPage.png

StartDateTime - Returns the Date and Time.

local dt= StartDateTime(true)

returns tbl = "10/02/23"

   function StartDateTime(LongShort)
--[[ Date Value Codes
--  |    %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %B  full month name (e.g., September)
--  |    %c  date and time (e.g., 09/16/98 23:48:10)
--  |    %d  day of the month (16) [01-31]
--  |    %H  hour, using a 24-hour clock (23) [00-23]
--  |    %I  hour, using a 12-hour clock (11) [01-12]
--  |    %M  minute (48) [00-59]
--  |    %m  month (09) [01-12]
--  |    %p  either "am" or "pm" (pm)
--  |    %S  second (10) [00-60]
--  |    %w  weekday (3) [0-6 = Sunday-Saturday]
--  |    %x  date (e.g., 09/16/98)
--  |    %X  time (e.g., 23:48:10)
--  |    %Y  full year (e.g., 1998)
--  |    %y  two-digit year (98) [00-99]
--  |    %%  the character `%´ ]]
    if LongShort then
      return os.date("%b %d, %Y") .. " - " .. os.date("%I") .. ":" .. os.date("%m") .. os.date("%p")
    else
      return os.date("%Y%m%d%H%M")
    end
  end 

StartDate

TopOfPage.png

StartDate - Returns the Date and Time.

local dt= StartDate(true)

returns tbl = "10/02/23"

  function StartDate(LongShort)
--[[ Date Value Codes
--  |    %a  abbreviated weekday name (e.g., Wed)
--  |    %A  full weekday name (e.g., Wednesday)
--  |    %b  abbreviated month name (e.g., Sep)
--  |    %B  full month name (e.g., September)
--  |    %c  date and time (e.g., 09/16/98 23:48:10)
--  |    %d  day of the month (16) [01-31]
--  |    %H  hour, using a 24-hour clock (23) [00-23]
--  |    %I  hour, using a 12-hour clock (11) [01-12]
--  |    %M  minute (48) [00-59]
--  |    %m  month (09) [01-12]
--  |    %p  either "am" or "pm" (pm)
--  |    %S  second (10) [00-60]
--  |    %w  weekday (3) [0-6 = Sunday-Saturday]
--  |    %x  date (e.g., 09/16/98)
--  |    %X  time (e.g., 23:48:10)
--  |    %Y  full year (e.g., 1998)
--  |    %y  two-digit year (98) [00-99]
--  |    %%  the character `%´ ]]

    if LongShort then
      return os.date("%b %d, %Y")  -- "Sep 01, 2022"
    else
      return os.date("%Y%m%d")     -- "20220901"
    end
  end 

Wait

TopOfPage.png

Wait - Waits for a duration.

local dt = Wait(true)

returns tbl = "10/02/23"

   function Wait(time)
    local duration = os.time() + time
    while os.time() < duration do end
    end
 end -- function end 

Debugging Tools

Back.jpg

This collection of functions assist in the debugging of code.

DMark - places a circle and notation to assist in geometry debugging

TopOfPage.png

Draws a circle and marks on the drawing for debugging purposes.

call = DebugMarkPoint("Note: Hi", Pt1)

 function DMark(Note, Pt)
  -- ==== Sub Function
    local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
      local pa   = Polar2D(Cpt, 180.0, CircleRadius)
      local pb   = Polar2D(Cpt,   0.0, CircleRadius)
      local line = Contour(0.0)
      line:AppendPoint(pa); line:ArcTo(pb,1); line:ArcTo(pa,1)
      local layer = job.LayerManager:GetLayerWithName(LayerName)
      layer:AddObject(CreateCadContour(line), true)
      return true
    end -- function end
  -- ====
    local BubbleSize = 1.25
    if not Project.DebugAngle then
      Project.DebugAngle = 0.0
    end
    Project.DebugAngle = Project.DebugAngle + 2.0
    if Project.DebugAngle >= 90.0 and Project.DebugAngle <= 358.0 then
      Project.DebugAngle = 272.0
    elseif Project.DebugAngle >= 360.0 then
      Project.DebugAngle = 2.0
    end
    if Pt then
      local job = VectricJob()
      local Pt1 = Polar2D(Pt, Project.DebugAngle, BubbleSize)
      local Pt2 = Polar2D(Pt1, 0.0, BubbleSize * 0.25)
      local Pt3 = Polar2D(Pt2, 315.0, BubbleSize * 0.0883883476483188 * 4.0)
      local line = Contour(0.0)
      local layer = job.LayerManager:GetLayerWithName("Debug")
      line:AppendPoint(Pt)
      line:LineTo(Pt1)
      line:LineTo(Pt2)
      layer:AddObject(CreateCadContour(line), true)
      DrawWriter(Note, Pt3, BubbleSize * 0.5, "Debug", 0.0)
      DrawCircle(job, Pt, BubbleSize * 0.5, "Debug")
    else
      DisplayMessageBox("Issue with Point for - " .. Note)
    end
    return true
  end -- function end 

StatusMessage

TopOfPage.png

Useage: (Type of Message, Dialog Header, Question or Message, Err No.)

StatusMessage("Error", "Base Cabinet Settings", "Face Frame Bottom Rail Width - value cannot be 0.", "(9000)")

Note: if the debug flag is on (true) a message box shows the message length, dialog size and error number

function StatusMessage(Type, Header, Question, ErrorNumber)

  local dialog
  local X = 460
  local Y = 124
  local step = 35
  Question = WrapString(Question, step)
  local QL = string.len(Question)
  if (QL > step) and (QL < step * 2) then
    Y = Y + 12
  elseif (QL > (step * 2) +1) and (QL < 105) then
    Y = Y + 24
  elseif (QL > (step * 3) +1) and (QL < (step * 4)) then
    Y = Y + 36
  elseif (QL > (step * 4) +1) and (QL < (step * 5)) then
    Y = Y + 48
  elseif (QL > (step * 5) +1) and (QL < (step * 6)) then
    Y = Y + 60
  elseif (QL > (step * 6) +1) and (QL < (step * 7)) then
    Y = Y + 72
  elseif (QL > (step * 7) +1) and (QL < (step * 8)) then
    Y = Y + 84
  elseif (QL > (step * 8) +1) and (QL < (step * 9)) then
    Y = Y + 96
  elseif (QL > (step * 9) +1) and (QL < (step * 10)) then
    Y = Y + 108
  elseif (QL > (step * 10) +1) and (QL < (step * 11)) then
    Y = Y + 120
  else
    Y = Y + 150
  end
  if Project.Debugger then
    Queston = Question .. " - " .. ErrorNumber
  end
  if Type == "Alert" then
    dialog = HTML_Dialog(true, DialogWindow.myHtml16, X, Y, Header)
  else -- "Error"
    dialog = HTML_Dialog(true, DialogWindow.myHtml17, X, Y, Header)
  end -- if end
  if Project.Debugger then
    Question = Question .. " " .. ErrorNumber
  end
  dialog:AddLabelField("Question", Type .. ": " .. Question)
  dialog:ShowDialog()
  if Project.Debugger then
    DisplayMessageBox("Question Len " .. " = " .. tostring(string.len(Question)) .. ": \nWindow = " .. tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight))
  end
  return true
end 


DebugMarkPoint

TopOfPage.png

Used in debugging drawing issues - Draws a Circle and Text at the provided point(x,y)

call = DebugMarkPoint("Note: Hi", Pt1, 0.125, "Jim")

function DebugMarkPoint(Note, Pt, Size, LayerName)
    if Size == nil then
      Size = 0.125
    end
    if LayerName == nil then
      LayerName = "Debug"
    end
  -- ==== Sub Function
    local function DrawCircle(job, Cpt, CircleRadius, LayerName)  -- Draws a circle
      local pa = Polar2D(Cpt, 180.0, CircleRadius)
      local pb = Polar2D(Cpt,   0.0, CircleRadius)
      local line = Contour(0.0)
      line:AppendPoint(pa); line:ArcTo(pb,1);   line:ArcTo(pa,1)
      local layer = job.LayerManager:GetLayerWithName(LayerName)
      layer:AddObject(CreateCadContour(line), true)
      return true
    end -- sub function end
  -- ====
    local job = VectricJob()
    local Pt1 = Polar2D(Pt, Project.DebugAngle, Size * 2.0)
    local Pt2 = Polar2D(Pt1, 0.0, 0.500 * Size)
    local Pt3 = Polar2D(Pt2, 315.0, (0.500 * Size) * 1.4142135623731)
    local line = Contour(0.0)
    local layer = job.LayerManager:GetLayerWithName(LayerName)
    line:AppendPoint(Pt)
    line:LineTo(Pt1)
    line:LineTo(Pt2)
    layer:AddObject(CreateCadContour(line), true)
    DrawWriter(Note, Pt3, Size, LayerName, 0.0)
    DrawCircle(job, Pt, Size, LayerName)
    return true
  end -- function end 

ShowDialogSize

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function ShowDialogSize()
    DisplayMessageBox(tostring(dialog.WindowWidth) .. " x " ..  tostring(dialog.WindowHeight))
  end -- function end

Dialog and Menu Tools

Back.jpg

This object is a name-value pair that represents a Document.

DialogSize

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function DialogSize(Str)                                -- Returns the X and Y value of the dialogue
  local InText = string.find(string.upper(Str) , "X")
  local DialogX = All_Trim(string.sub(Str, 1, InText - 1))
  local DialogY = All_Trim(string.sub(Str, InText + 1))
  return tonumber(DialogX), tonumber(DialogY)
 end -- function end

ProgressBarAmount

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function ProgressBarAmount(TotalRecords, Record)        -- Calculates the percent amount of progression based on total process
  --[[
  local MyProgressBar
    MyProgressBar = ProgressBar("Working", ProgressBar.LINEAR)                -- Setup Type of progress bar
    MyProgressBar:SetPercentProgress(0)                                       -- Sets progress bar to zero
    MyProgressBar:SetPercentProgress(ProgressAmount(Door.Records, myRecord))  -- sends percent of process progress bar (adds to the bar)
    MyProgressBar:SetPercentProgress(ProgressAmount(12000, 416))              -- sends percent of process progress bar (adds to the bar)
    MyProgressBar:SetText("Compete")                                          -- Sets the label to Complete
    MyProgressBar:Finished()                                                  -- Close Progress Bar
  ]]
    local X1 = (100.0 / TotalRecords)
    local X2 = X1 * Record
    local X3 = math.abs(X2)
    local X4 = (math.floor(X3))
    return (math.floor(math.abs((100.0 / TotalRecords) * Record)))
  end -- function end

OnLuaButton_InquiryGearCalulate

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function OnLuaButton_InquiryGearCalulate(dialog)
  Gear.Addendum         = dialog:GetDoubleField("Gear.Addendum")
  Gear.Dedendum         = dialog:GetDoubleField("Gear.Dedendum")
  Gear.AddendumDiameter = dialog:GetDoubleField("Gear.AddendumDiameter")
  Gear.DedendumDiameter = dialog:GetDoubleField("Gear.DedendumDiameter")
  Gear.ToothTickness    = dialog:GetDoubleField("Gear.ToothTickness")
  Gear.Slotwidth        = dialog:GetDoubleField("Gear.Slotwidth")
  Gear.PitchAmount      = dialog:GetDoubleField("Gear.PitchAmount")
  Gear.FilletRadius     = dialog:GetDoubleField("Gear.FilletRadius")
  Gear.ToplandAmount    = dialog:GetDoubleField("Gear.ToplandAmount")
  Gear.FaceFlankRadius  = dialog:GetDoubleField("Gear.FaceFlankRadius")
  Gear.ToothCount       = dialog:GetDropDownListValue("Gear.ToothCount")
  Gear.ShowLines        = dialog:GetDropDownListValue("Gear.ShowLines")

  dialog:UpdateDoubleField("Gear.Addendum",                      Gear.Addendum)
  dialog:UpdateDoubleField("Gear.Dedendum",                      Gear.Dedendum)
  dialog:UpdateDoubleField("Gear.AddendumDiameter",              Gear.AddendumDiameter)
  dialog:UpdateDoubleField("Gear.DedendumDiameter",              Gear.DedendumDiameter)
  dialog:UpdateDoubleField("Gear.ToothTickness",                 Gear.ToothTickness)
  dialog:UpdateDoubleField("Gear.Slotwidth",                     Gear.Slotwidth)
  dialog:UpdateDoubleField("Gear.PitchAmount",                   Gear.PitchAmount)
  dialog:UpdateDoubleField("Gear.FilletRadius",                  Gear.FilletRadius)
  dialog:UpdateDoubleField("Gear.ToplandAmount",                 Gear.ToplandAmount)
  dialog:UpdateDoubleField("Gear.FaceFlankRadius",               Gear.FaceFlankRadius)

  return true
 end -- function end

InquiryDropList

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryDropList(Header, Quest, DX, DY, DList)
--[[
    Drop list foe user input
    Caller: local y = InquiryDropList("Cabinet Maker", "Select Cabinet Style", 290, 165, IniFile)
    Dialog Header = "Cabinet Maker"
    Quest = "Select Cabinet Style"
    Selection Array = IniFile
    Returns = String
]]
    local myHtml = [[<!DOCTYPE HTML><html lang="en"><head><title>My List Box</title><style>.FormButton{font-weight:700;width:75px;font-size:12px;white-space:nowrap;font-family:Arial,Helvetica,sans-serif font-size: 12px}.h1-l{font-size:12px;font-weight:700;text-align:left;white-space:nowrap}.h1-c{font-size:12px;font-weight:700;text-align:center;white-space:nowrap}table{width:100%;border:0}body,td,th{background-color:#3a4660;background-position:center;overflow:hidden;font-family:arial,helvetica,sans-serif;font-size:12px;color:#fff;background-image:url(']].. DialogWindow.myBackGround ..[[')}html{overflow:hidden}</style></head><body><table><tr><td class="h1-l" id="Questions"><strong class="h2">Message Here</strong></td></tr><tr><td class="h1-c"><select name="DList" size="10" class="h1-c" id="ListBox"><option>My Default 1</option><option selected="selected">My Default 2</option><option>My Default 3</option><option>My Default 4</option></select></td></tr><tr><th class="h1-l" colspan="3" id="QuestionID"></th></tr></table><table><tr><td class="h1-c"><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td></td><td class="h1-c"><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]] ;

    local dialog = HTML_Dialog(true, myHtml, DX, DY, Header)
          dialog:AddLabelField("Questions", Quest)
          dialog:AddDropDownList("ListBox", "DEFAULT")
          dialog:AddDropDownListValue("ListBox", "DEFAULT")
    for index, value in pairs(DList) do
        dialog:AddDropDownListValue("ListBox", value)
    end
    if not dialog:ShowDialog() then
      return "."
    else
      return dialog:GetDropDownListValue("ListBox")
    end
 end -- function end

InquiryFileBox

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryFileBox(Header, Quest, DefaltPath)
--[[
    Dialog Box for user to pick a file
    Caller: local X = InquiryFileBox("Select File", "Where is the file location?", "C:\\")
    Dialog Header = "File Name"
    User Question = "Path name?"
    Default Value = "C:\\"
    Returns = String
  ]]
  local myHtml = [[<html> <head> <title>Easy Tools</title> <style type = "text/css">  html {overflow: hidden; } body {
             background-color: #EBEBEB; overflow:hidden; font-family: Arial, Helvetica, sans-serif; font-size: 12px; } body, td,
             th {font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; color: #000 ; } .FormButton {font-weight: bold ;
             width: 100% ; font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; } body { background-color: #EBEBEB; }
             </style> </head> <body bgcolor = "#EBEBEB" text = "#000000"> <table width = "470" border = "0" cellpadding = "0">
             <tr> <th align = "left" valign = "top" bgcolor = "#EBEBEB" id = "QuestionID"><strong>Message Here</strong></th>
             <th align = "left" valign = "middle" bgcolor = "#EBEBEB"> </th> </tr> <tr>
             <th width = "381" align = "right" valign = "middle" bgcolor = "#EBEBEB" id = "QuestionID">
             <input name = "ReadFile" type = "text" id = "ReadFile" size = "60"></th>
             <th width = "83" align = "center" valign = "middle" bgcolor = "#EBEBEB"> <span style="width: 15%">
             <input id = "FilePicker" class = "FilePicker" name = "FilePicker" type = "button" value = "Path">
             </span></th> </tr> <tr> <td colspan = "2" align = "center" valign = "middle" bgcolor = "#EBEBEB">
             <table border = "0" width = "100%"> <tr align = "right"> <td style = "width: 20%"> </td>
             <td style = "width: 20%"></td> <td style = "width: 25%"></td> <td style = "width: 15%">
             <input id = "ButtonCancel" class = "FormButton" name = "ButtonCancel" type = "button" value = "Cancel"> </td>
             <td style = "width: 15%"> <input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK">
             </td> </tr> </table> </td> </tr> </table> </body>  </html>]]
  -- =============================================
  local dialog = HTML_Dialog(true, myHtml, 505, 150, Header)
    dialog:AddLabelField("QuestionID", Quest)
    dialog:AddTextField("ReadFile", DefaltPath )
    dialog:AddFilePicker(true, "FilePickerButton", "ReadFile", true)
    if not dialog:ShowDialog() then
      return ""
    else
      return dialog:GetTextField("ReadFile")
    end -- if end
  end -- function end

InquiryPathBox

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryPathBox(Header, Quest, DefaltPath)
--[[
    Number Box for user input with default value
    Caller: local X = InquiryPathBox("Select Path", "Where is the file location?", "C:\\")
    Dialog Header = "Tool Name"
    User Question = "Path name?"
    Default Value = "C:\\"
    Returns = String
  ]]
  local myHtml = [[ <html> <head> <title>Easy Tools</title> <style type = "text/css">  html {overflow: hidden; } body {
             background-color: #EBEBEB; overflow:hidden; font-family: Arial, Helvetica, sans-serif; font-size: 12px; } body, td,
             th {font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; color: #000 ; } .FormButton {font-weight: bold ;
             width: 100% ; font-family: Arial, Helvetica, sans-serif ; font-size: 12px ; } body { background-color: #EBEBEB; }
             </style> </head> <body bgcolor = "#EBEBEB" text = "#000000"> <table width = "470" border = "0" cellpadding = "0">
             <tr> <th align = "left" valign = "top" bgcolor = "#EBEBEB" id = "QuestionID"><strong>Message Here</strong></th>
             <th align = "left" valign = "middle" bgcolor = "#EBEBEB"> </th> </tr> <tr>
             <th width = "381" align = "right" valign = "middle" bgcolor = "#EBEBEB" id = "QuestionID">
             <input name = "DInput" type = "text" id = "DInput" size = "60"></th>
             <th width = "83" align = "center" valign = "middle" bgcolor = "#EBEBEB"> <span style="width: 15%">
             <input id = "DirectoryPicker" class = "DirectoryPicker" name = "DirectoryPicker" type = "button" value = "Path">
             </span></th> </tr> <tr> <td colspan = "2" align = "center" valign = "middle" bgcolor = "#EBEBEB">
             <table border = "0" width = "100%"> <tr align = "right"> <td style = "width: 20%"> </td>
             <td style = "width: 20%"></td> <td style = "width: 25%"></td> <td style = "width: 15%">
             <input id = "ButtonCancel" class = "FormButton" name = "ButtonCancel" type = "button" value = "Cancel"> </td>
             <td style = "width: 15%"> <input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK">
             </td> </tr> </table> </td> </tr> </table> </body>  </html>]]
  -- =============================================
  local dialog = HTML_Dialog(true, myHtml, 505, 150, Header)
    dialog:AddLabelField("QuestionID", Quest)
    dialog:AddTextField("DInput", DefaltPath )
    dialog:AddDirectoryPicker("DirectoryPicker",  "DInput",  true)
    if not dialog:ShowDialog() then
      return ""
    else
      return dialog:GetTextField("DInput")
    end -- if end
 end -- function end

InquiryAreYouSureYesNo

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryAreYouSureYesNo(Header, Question1, Question2)
 --[[
     Drop list for user to input project info
     Caller = local y = InquiryAreYouSureYesNo("Pie Question", "Do you want free pie")
     Dialog Header = "Pie Question"
     User Question1 = "Do you want a Free Pie"
     User Question2 = "You only get one"
     Returns = true / false
   ]]
    local myHtml = [[ <html><head><title>Yes or No Question</title>]] .. DialogWindow.Style ..[[</head><body><table><tr><td colspan="3" class="h2-lw" id="Question1">Question1</td></tr><tr><td colspan="3" class="h2-lw" id="Question2">Question2</td></tr><tr><td class="h2-l"> </td></tr><tr><td colspan="3" class="h2-l">Are you sure?</td></tr><tr><td class="h2-l"> </td></tr></table><table><tr><td colspan="3"><h2><span></span></h2></td></tr>
   <tr><td class="h1-l"><input id="ButtonOK" class="FormButton FormBut" name="ButtonOK" type="button" value="  Yes  "> </td> <td class="h1-r"> <input id="ButtonCancel" class="FormButton FormBut" name="ButtonCancel" type="button" value="  No  "></td></tr></table></body></html>]]
-- =========================================================
    local dialog = HTML_Dialog(true, myHtml, 440, 218, Header)
    dialog:AddLabelField("Question1", Question1)
    dialog:AddLabelField("Question2", Question2)
    if not dialog:ShowDialog() then
      return false
    else
      return true
    end
 end -- function end

InquiryDoubleBox

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryDoubleBox(Header, Quest, DefaltN)
--[[
-- nquiryNumberBox for user input with default number value
-- Caller: local x = InquiryNumberBox("Cabinet Maker", "Enter the cabinet height", 30.0)
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the cabinet height"
-- Default value = 30.0
-- Returns = double
]]
   local myHtml = [[<html><head><title>Get Double Value</title><style type="text/css">html{overflow:hidden}body{background-color:#ebebeb;overflow:hidden;font-family:Arial,Helvetica,sans-serif;font-size:12px;text:#000}.h1-l{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:left;white-space:nowrap}.h1-r{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:right;white-space:nowrap}.h1-c{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:700;text-align:center;white-space:nowrap}table{width:100%;border:0;cellpadding:0}.FilePicker{font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:12px;width:50px}.FormButton{font-weight:700;width:65px;font-family:Arial,Helvetica,sans-serif;font-size:12px}</style></head><body><table><tr><td id="QuestionID" class="h1-r"><strong>Message Here</strong></td><td><input type="text" id="NumberInput" size="5"></td></tr><tr><td colspan="2"></td></tr></table><table><tr class="h1-c"><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
   local dialog = HTML_Dialog(true, myHtml, 260, 125, Header)
   dialog:AddLabelField("QuestionID", Quest) ;
   dialog:AddDoubleField("NumberInput", DefaltN) ;
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetDoubleField("NumberInput")
  end
 end -- function end

InquiryIntegerBox

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryIntegerBox(Header, Quest, DefaltI)
--[[
-- InquiryIntegerBox for user input with default number value
-- Caller: local x = InquiryIntegerBox("Cabinet Maker", "Enter the door count", 4)
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the door count"
-- Default value = 4
-- Returns = integer
]]
   local myHtml = [[<html><head><title>Get Integer</title><style type="text/css">html{overflow:auto}body{background-color:#ebebeb}table{width:100%;border:0}body,td,th{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000}.FormButton{font-weight:700;width:85px;font-family:Arial,Helvetica,sans-serif;font-size:12px}body{background-color:#ebebeb;text:#000}</style></head><body><table><tr><td id="QuestionID"><strong>Message Here</strong></td><td><input type="text" id="IntegerInput" size="10"></td></tr><tr><td colspan="2"></td></tr></table><table><tr><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
   local dialog = HTML_Dialog(true, myHtml, 505, 140, Header)
   dialog:AddLabelField("QuestionID", Quest)
   dialog:AddIntegerField("IntegerInput", DefaltI)
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetIntegerField("IntegerInput")
  end
 end -- function end

InquiryTextgBox

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function InquiryTextgBox(Header, Quest, DefaltS)
--[[
-- InquiryStringBox for user input with default number value
-- Caller: local x = InquiryTextgBox("Cabinet Maker", "Enter the cabinet Name", "Jim")
-- Dialog Header: "Cabinet Maker"
-- User Question: "Enter the cabinet Name"
-- Default value = Jim
-- Returns = string
]]
   local myHtml = [[<html><head><title>Get Number</title><style type="text/css">html{overflow:auto}body{background-color:#ebebeb}table{width:100%;border:0}body,td,th{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000}.FormButton{font-weight:700;width:85px;font-family:Arial,Helvetica,sans-serif;font-size:12px}body{background-color:#ebebeb;text:#000}</style></head><body><table><tr><td id="QuestionID"><strong>Message Here</strong></td><td><input type="text" id="StringInput" size="10"></td></tr><tr><td colspan="2"></td></tr></table><table><tr><td><input id="ButtonCancel" class="FormButton" name="ButtonCancel" type="button" value="Cancel"></td><td><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td></tr></table></body></html>]]
   local dialog = HTML_Dialog(true, myHtml, 505, 140, Header)
   dialog:AddLabelField("QuestionID", Quest)
   dialog:AddTextField("StringInput", DefaltS)
  if not dialog:ShowDialog() then
    return -1
  else
    return dialog:GetTextField("NumberInput")
  end
 end -- function end

OnLuaButton_InquiryError

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function OnLuaButton_InquiryError(Message)
    --[[
     Provides user information on an Error
     Caller = local ItWorked = OnLuaButton_InquiryError("No number found")
     Dialog Header = "Something Error"
     User Message = "No Number etc..."
     Returns = True
   ]]
  local myHtml = [[<html><head><title>Error</title><style type = "text/css">.FormButton{font-weight:bold;width:75px;font-family:Arial,Helvetica,sans-serif;font-size:12px;white-space:nowrap}.Error{font-family:Arial,Helvetica,sans-serif;font-size:18px;font-weight:bold;color:#F00;text-align:left;white-space:nowrap;padding-right:4px;padding-left:10px;padding-top:4px;padding-bottom:4px}.ErrorMessage{font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#000;font-weight:bold;text-align:left;white-space:nowrap;padding-right:4px;padding-left:10px;padding-top:4px;padding-bottom:4px}.ErrorTable{background-color:#FFF white-space:nowrap}html{overflow:hidden}</style></head><body text = "#000000"><table width="100%" border="0" cellpadding="0" class="ErrorTable"><tr><th align="center" nowrap="nowrap" class="Error">Error!</th></tr><tr><td id="ErrorMessage"><label class="ErrorMessage">-</label></tr><tr><td width="30%" align="right" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "Exit"></td></tr></table></body></html>]]
  local dialogWide =  (#Message + 300)
  local dialog = HTML_Dialog(true, myHtml, 250, dialogWide, "Gadget Error")
  dialog:AddLabelField("ErrorMessage",   Message)
  dialog:ShowDialog()
  Dovetail.InquiryErrorX = Dialog.WindowWidth
  Dovetail.InquiryErrorY = Dialog.WindowHeight
  WriteRegistry()
  return  true
 end -- function end

PresentMessage

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function PresentMessage(Header, Type, Line)
    --[[
     Provides user information on an Error
     Caller = local ItWorked = OnLuaButton_InquiryError("No number found")
     Dialog Header = "Something Error"
     User Message = "No Number etc..."
     Returns = True
   ]]
  local myHtml = [[<html><head><title>Error</title>]] .. DialogWindow.Style ..[[</head><body>
  <table><tr><th valign="top" id="MessageType" class="Error">-</th><td id="MessageLine"><label class="ErrorMessage">-</label><td></tr>
<tr><td></td><td align="right"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td></tr>
</table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 500, 150, Header)
  dialog:AddLabelField("MessageType", Type .. ": ")
  dialog:AddLabelField("MessageLine", Line)
  dialog:ShowDialog()
  return  true
 end -- function end

OnLuaButton_InquiryAbout

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function OnLuaButton_InquiryAbout()
local myHtml = [[<html><head><title>About</title>]] .. DialogWindow.Style ..[[</head><body text = "#000000"><table width="680" border="0" cellpadding="0"> <tr> <td align="center" nowrap="nowrap" class="header1-c" id="SysName">Easy Cabinet Maker</td> </tr> <tr> <td align="center" nowrap="nowrap" id="Version" class="ver-c">Version</td> </tr> <tr> <td align="center" nowrap="nowrap"><hr></td> </tr> <tr> <td align="center" nowrap="nowrap" class="header2-c">Disclaimer</td> </tr> <tr> <td align="center" class="p1-l"><p class="p1-l">The ]] .. Dovetail.AppName .. [[ Gadget is a plugin for Vectric software, V-Carve Pro and Aspire.<br> Gadgets are an entirely optional add-in to Vectric's core software products.<br> They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.<br> In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.<br> <br> Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:<br> 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.<br> * If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.<br> 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.<br> 3. This notice may not be removed or altered from any source distribution.<br> <br>The author heavily utilized the SDK documentation and supplied code samples in addition to the outstanding user community on the Vectric User forum.</p></td> </tr> <tr> <td align="center"><a href="https://forum.vectric.com" class="webLink-c">Vectric User Forum</a></td> </tr> <tr> <td align="center"><span class="header2-c">JimAndi</span></td> </tr> <tr> <td align="center"><span class="h1-c">Houston, TX.</span></td> </tr> <tr> <td><hr></td> </tr> <tr> <td width="30%" align="center" style = "width: 15%"><input id = "ButtonOK" class = "FormButton" name = "ButtonOK" type = "button" value = "OK"></td> </tr></table></body></html>]]
  local dialog = HTML_Dialog(true, myHtml, 720, 468, "About")
  dialog:AddLabelField("SysName", Project.ProgramName)
  dialog:AddLabelField("Version", "Version: " .. Project.ProgramVersion)
  dialog:ShowDialog()
  Project.AboutXY = tostring(dialog.WindowWidth) .. " x " .. tostring(dialog.WindowHeight)
  return  true
 end -- function end


Color_HTML

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function Color_HTML ()
  MessageBox(" X = " .. tostring(dialog.WindowWidth) ..
             " Y = " .. tostring(dialog.WindowHeight)
 )
-- =====================================================]]
--[[ -- begin HTML for Layer Color
<table>
  <tr>
    <td width="200" align="right" valign="middle" nowrap class="h1-rp">Layer Name</td>
    <td width="300" align="right" valign="middle" nowrap class="h1-l" id="ValueTable">
      <input name="Panel.PinHole" type="text" class="h1-l" id="Panel.PinHole" size="50" maxlength="50"/>
      </td>
    <td width="150"align="right" valign="middle" nowrap class="h1-l"><label for="Panel.LineColor01">Color</label>
      <select name="Panel.LineColor01" id="Panel.LineColor01">
        <option selected="selected">Black</option>
        <option>Blue</option>
        <option>Brown</option>
        <option>Cyan</option>
        <option>Gray</option>
        <option>Green</option>
        <option>Lime</option>
        <option>Magenta</option>
        <option>Maroon</option>
        <option>Navy</option>
        <option>Olive</option>
        <option>Orange</option>
        <option>Purple</option>
        <option>Red</option>
        <option>Silver</option>
        <option>Teal</option>
        <option>White</option>
        <option>Yellow</option>
    </select></td>
  </tr>
</table>
<table width="101%" border="0" id="ButtonTable">
</table>
]] -- end HTML
 end -- function end


Style

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function Style()
-- =====================================================]]
DialogWindow.Style = [[ <style>
.DirectoryPicker {
  font-weight: bold;
  font-size: 12px;
  white-space: nowrap;
  background-color: #663300;
  color: #FFFFFF;
}
.FormButton {
	font-weight: bold;
	width: 75px;
	font-size: 12px;
	white-space: nowrap;
	background-color: #663300;
	color: #FFFFFF;
}
.FormButton-Help {
	font-weight: bold;
	width: 75px;
	font-size: 12px;
	white-space: nowrap;
	background-color: #663300;
	color: #FFFFFF;
	padding-left: 10;
	padding-right: 10;
}
.LuaButton {
	font-weight: bold;
	font-size: 12px;
	background-color: #663300;
	color: #FFFFFF;
}
.ToolNameLabel {
	font-weight: bolder;
	font-size: 12px;
	text-align: left;
	color: #000;
	width: 70%;
}
.ToolPicker {
	font-weight: bold;
	text-align: center;
	font-size: 12px;
	text-align: center;
	width: 50px;
	background-color: #663300;
	color: #FFFFFF;
}
.alert-c {
	font-size: 14px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
}
.alert-l {
	font-size: 14px;
	font-weight: bold;
	text-shadow: 5px 5px 10px #FFF;
	text-align: left;
	width: 100%;
	white-space: nowrap;
}
.alert-r {
	font-size: 14px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
}
.error {
	font-size: 18px;
	font-weight: bold;
	color: #FF0000;
	text-align: left;
	white-space: nowrap;
	padding-right: 4px;
	padding-left: 10px;
	padding-top: 4px;
	padding-bottom: 4px;
}
.errorMessage {
	font-size: 12px;
	color: #000;
	font-weight: bold;
	text-align: left;
	white-space: nowrap;
	padding-right: 4px;
	padding-left: 10px;
	padding-top: 4px;
	padding-bottom: 4px;
}
.errorTable {
	background-color: #FFFFFF;
	white-space: nowrap;
}
.p1-l {
	font-size: 12px;
	text-align: left;
}
.h1-c {
	font-size: 12px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
}
.h1-cOk {
	font-size: 12px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
	width: 15%;
}
.h1-l {
	font-size: 12px;
	font-weight: bold;
	text-align: left;
	white-space: nowrap;
}
.h1-r {
	font-size: 12px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
}
.h1-rP {
	font-size: 12px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
	padding-right: 4px;
	padding-left: 4px;
}
.h1-rPx {
	font-size: 12px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
	padding-right: 8px;
	padding-left: 8px;
}
.h2-c {
	font-size: 14px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
	text-shadow: 2px 2px white;
}
.h2-l {
	font-size: 14px;
	font-weight: bold;
	color: #663300;
	text-align: left;
	white-space: nowrap;
	text-shadow: 2px 2px white;
}
.h2-r {
	font-size: 14px;
	font-weight: bold;
	color: #663300;
	text-align: right;
	white-space: nowrap;
	text-shadow: 2px 2px white;
}
.h3-bc {
	font-size: 16px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
}
.h3-c {
	font-size: 16px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
}
.h3-l {
	font-size: 16px;
	font-weight: bold;
	text-align: left;
	white-space: nowrap;
}
.h3-r {
	font-size: 16px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
}
.h4-c {
	font-size: 18px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
}
.h4-l {
	font-size: 18px;
	font-weight: bold;
	text-align: left;
	white-space: nowrap;
}
.h4-r {
	font-size: 18px;
	font-weight: bold;
	text-align: right;
	white-space: nowrap;
}
.help_But {
	width: 45px;
}
.MyCenter{
	text-align:center;
	width:10;
}
.MyLeft{
	text-align:left;
	width:10;
}
.MyRight{
	text-align:right;
	width:10;
}
.helplabel-r {
	cursor: pointer;
	white-space: nowrap;
	text-align: right;
}
.helplabel-rp {
	cursor: pointer;
	white-space: nowrap;
	text-align: right;
	padding-right: 8px;
}
.jsTag-no-vis {
	font-size: 10px;
	display: none;
	text-align: center;
	color: #00F;
	visibility: hidden;
}
.jsbutton {
	background-color: #663300;
	border: 2px solid #999;
	border-right-color: #000;
	border-bottom-color: #000;
	border-top-color: #FFF;
	border-left-color: #FFF;
	text-align: center;
	text-decoration: none;
	font-size: 12px;
	margin: 1px 1px;
	color: #FFFFFF;
}
.p1-c {
	font-size: 12px;
	text-align: center;
}
.p1-r {
	font-size: 12px;
	text-align: right;
}
.ver-c {
	font-size: 10px;
	font-weight: bold;
	text-align: center;
	white-space: nowrap;
	color: #ffd9b3;
}
.webLink-c {
	font-size: 16px;
	font-weight: bold;
	background-color: yellow;
	text-align: center;
	white-space: nowrap;
}
body {
	background-color: #3a4660;
	background-position: center;
	overflow: hidden;
	font-family: arial, helvetica, sans-serif;
	font-size: 12px;
	color: #FFFFFF;
	background-image: url(]].. DialogWindow.myBackGround ..[[);
}
html {
	overflow: hidden
}
table {
	width: 100%;
	border: 0;
}
</style>]]
 end -- function end

Orgin

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function Orgin()                                       -- Anchor Point
-- ================================
  DialogWindow.Orgin = [[<table><tr><td colspan="2" class="h2-l">Anchor Point</td></tr><tr class="MyLeft"><td class="MyLeft"><table class="MyCenter"><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V1"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V2"></td></tr><tr><td class="auto-style9">|</td><td><input type="radio" name="DrawingOrigin" checked="checked" value="V3"></td><td valign="top">|</td></tr><tr><td><input type="radio" name="DrawingOrigin" checked="checked" value="V4"></td><td><hr></td><td valign="top"><input type="radio" name="DrawingOrigin" checked="checked" value="V5"></td></tr></table></td><td width="81%"><table><tr class="MyLeft"><td>X</td><td><input name="OriginX0" type="text" id="OriginX" size="8" maxlength="8"></td></tr><tr class="MyLeft"><td>Y</td><td><input name="OriginY0" type="text" id="OriginY" size="8" maxlength="8"></td></tr></table></td></tr></table>]]
 end -- function end


GetColor

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function GetColor(str)                                  -- returns the RGB value for the standard color names
-- str = "Purple"
-- returns = 128 0 128
    local Colors = {}
    Colors.Black  = "0,0,0";       Colors.White  = "255,255,255"; Colors.Red    = "255,0,0"
    Colors.Lime   = "0,255,0";     Colors.Blue   = "0,0,255";     Colors.Yellow = "255,255,0"
    Colors.Cyan   = "0,255,255";   Colors.Magenta = "255,0,255";  Colors.Silver = "192,192,192"
    Colors.Gray   = "128,128,128"; Colors.Maroon = "128,0,0";     Colors.Olive  = "128,128,0"
    Colors.Green  = "0,128,0";     Colors.Purple = "128,0,128";   Colors.Teal   = "0,128,128"
    Colors.Navy   = "0,0,128"
    local Red, Green, Blue = 0
    if "" == str then
      DisplayMessageBox("Error: Empty string passed")
    else
      str = Colors[str]
      if "string" == type(str) then
        if string.find(str, ",") then
          Red  = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          str = string.sub(str, assert(string.find(str, ",") + 1))
          Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          Blue = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
        end
      else
        DisplayMessageBox("Error: Color Not Found")
        Red = 0
        Green = 0
        Blue = 0
      end
    end
    return Red, Green, Blue
 end -- function end


StatusMessage

TopOfPage.png

Returns Dialog size in a message box showing the X and Y vaalues.

 function StatusMessage(Type, Header, Question, length) -- Standardize messaging dialogues
  -- StatusMessage("Alert",    "Alert Test",     "This is a test of Alert",    165)
  -- StatusMessage("Question", "Question Test",  "This is a test of Question", 165)
  -- StatusMessage("Tick",     "Tick Test",      "This is a test of Tick",     165)
  -- StatusMessage("Minus",    "Minus Test",     "This is a test of Minus",    165)
  -- StatusMessage("Error",    "Error Test",     "This is a test of Error",    165)
  -- StatusMessage("Success",  "Success Test",   "This is a test of Success",  165)
  -- StatusMessage("Blank",    "Blank Test",     "This is a test of Blank",    165)
  local Image = ""
  if     Type == "Alert" then
    Image = AlertImage()
  elseif Type == "Question" then
    Image = QuestionImage()
  elseif Type == "Tick" then
    Image = TickImage()
  elseif Type == "Minus" then
    Image = MinusImage()
  elseif Type == "Error" then
    Image = ErrorImage()
  elseif Type == "Success" then
    Image = SuccessImage()
  else -- "Status"
    Image = TickImage()
  end -- if end
  local help = [[<html><head><title>]] .. Header ..[[</title><style>
.FormButton {font-family: Arial, Helvetica, sans-serif;font-weight: bold;font-size: 12px;white-space: nowrap;background-color: #663300;color: #FFFFFF;width: 75px;
}table {width: 100%;border: 0;}.h2-lm {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: left;}.h2-r {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: right;white-space: nowrap;}.h2-l {font-family: Arial, Helvetica, sans-serif;font-size: 14px;font-weight: bold;text-align: left;white-space: nowrap;}body {background-color: #3a4660;background-position: center;overflow: hidden;font-family: arial, helvetica, sans-serif;font-size: 12px;color: #FFFFFF;background-image: url(]] .. myBackGround() .. [[);}html {overflow: hidden}</style></head><body><table> <tr>  <td class="h2-l"><]] .. Image .. [[" width="60" height="60"></td>
    <td class="h2-lm" id="Question">]] .. Question .. [[</td></tr><tr><td colspan=2><h2><span></span></h2></td>
    </tr></table><table><tr><td class="h2-r"><input id="ButtonOK" class="FormButton" name="ButtonOK" type="button" value="OK"></td>
    </tr></table></body></html>]]
  local dialog = HTML_Dialog(true, help , 550,  length, Header)
  dialog:ShowDialog()
  return true
end -- function end 

DialogStringChecks

function DialogStringChecks()
  local MyTrue = false
  if Milling.LNBottomProfile == "" then
    MessageBox("Error: Bottom Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSideProfile  == "" then
    MessageBox("Error: Side Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif  Milling.LNSidePocket  == "" then
    MessageBox("Error: Side Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontProfile == "" then
    MessageBox("Error: Front Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNFrontPocket  == "" then
    MessageBox("Error: Front Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackProfile  == "" then
    MessageBox("Error: Back Profile layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBackPocket == "" then
    MessageBox("Error: Back Pocket layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNDrawNotes == "" then
    MessageBox("Error: Draw Notes layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNPartLabels == "" then
    MessageBox("Error: Part Lables layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Milling.LNBlume == "" then
    MessageBox("Error: Blume layer name cannot be blank")
    OnLuaButton_InquiryLayers()
  elseif Project.ProjectName == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactEmail  == "" then
    MessageBox("Error: Contact Email cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactName == "" then
    MessageBox("Error: Contact Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ContactPhoneNumber == "" then
    MessageBox("Error: Project Name cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.DrawerID == "" then
    MessageBox("Error: Contact Phone Number cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  elseif Project.ProjectPath == "" then
    MessageBox("Error: Project Path cannot be blank")
    OnLuaButton_InquiryProjectInfo()
  else
    MyTrue = true
  end -- if end
  return MyTrue
end -- function end

Directory and File Tools

Back.jpg

This object is a name-value pair that represents a Document.


MakeFolder()

TopOfPage.png

Returns Dialog size in a message box showing the X and Y values.

 function MakeFolder(xPath)
    os.execute( "mkdir  " .. xPath)
    return true
  end -- function end

PathFix()

TopOfPage.png
 function PathFix(xPath)              -- Returns path with /
    return string.gsub(xPath, "\\", "/")
  end -- function end

IsDir()

Validates a directory path

TopOfPage.png
function IsDir(path)                     -- Returns true if path is found
    local function exists(file)
      local ok, err, code = os.rename(file, file)
      if not ok then
        if code == 13 then
          return true
        end -- if end
      end -- if end
      return ok, err
    end -- function end
    return exists(path.."/")
  end -- function end



FileExists()

TopOfPage.png

Returns Dialog size in a message box showing the X and Y values.

 function FileExists(name)
-- FileExists(name
-- DisplayMessageBox(name)
    local f=io.open(name,"r")
    if f~=nil then
      io.close(f)
      return true
    else
      return false
    end
  end -- function end

DirectoryProcessor()

TopOfPage.png

Returns number of files that were processed by an operation.

 function DirectoryProcessor(job, dir_name, filter, do_sub_dirs, function_ptr)
      local num_files_processed = 0
      local directory_reader = DirectoryReader()
      local cur_dir_reader = DirectoryReader()
      directory_reader:BuildDirectoryList(dir_name, do_sub_dirs)
      directory_reader:SortDirs()
      local number_of_directories = directory_reader:NumberOfDirs()
      for i = 1, number_of_directories do
        local cur_directory = directory_reader:DirAtIndex(i)
         -- get contents of current directory
         -- dont include sub dirs, use passed filter
        cur_dir_reader:BuildDirectoryList(cur_directory.Name, false)
        cur_dir_reader:GetFiles(filter, true, false)
         -- call passed method for each file:
        local num_files_in_dir = cur_dir_reader:NumberOfFiles()
        for j=1, num_files_in_dir  do
          local file_info = cur_dir_reader:FileAtIndex(j)
          if not function_ptr(job, file_info.Name) then
            return true
          end -- if end
           num_files_processed = num_files_processed + 1
        end -- for end
        -- empty out our directory object ready for next go
        cur_dir_reader:ClearDirs()
        cur_dir_reader:ClearFiles()
      end -- for end
      return num_files_processed
  end -- function end 

Drawing Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.


DrawArrowLineArrow

TopOfPage.png

Draws a dimension line with arrow heads and extension leaders

function DrawArrowLineArrow(Pt1, Ext1, Pt2, Ext2, Off, Str, Layer, scale)
  -- DrawArrowLineArrow(pt1, true, pt3, true, 2.5, "122.5", "TestLayer", 6.0) -- both
  -- DrawArrowLineArrow(pt1, true, pt3, false, 2.5, "122.5", "TestLayer", 6.0) -- first leader only
  -- DrawArrowLineArrow(pt1, false, pt3, true, 2.5, "122.5", "TestLayer", 6.0) -- second leader only
  -- -----------------------------------------------------]]
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: No job loaded")
      return false
    end -- if end
    local DimArrow1Angle = GetPolarDirection(Pt1, Pt2, Polar2D(Pt2, 0.0, 1.0))
    local DimArrow2Angle = DimArrow1Angle + 180.0
    local LederAng       = DimArrow1Angle + 90.0
    local LedDrop        = LederAng + 180.0
    local TxtCenter      =  GetDistance(Pt1, Pt2) * 0.5
    local ArrowLen       = 0.125 * scale
    local StrSet         = (string.len(Str) * ArrowLen) * 0.5
    local PT01A          = Polar2D(Pt1, LederAng, ArrowLen * 2.0)
    local PT02A          = Polar2D(PT01A, LederAng, Off)
    local PT03A          = Polar2D(PT02A, LederAng, ArrowLen)
    local PT01B          = Polar2D(Pt2, LederAng, ArrowLen * 2.0)
    local PT02B          = Polar2D(PT01B, LederAng, Off)
    local PT03B          = Polar2D(PT02B, LederAng, ArrowLen)
    local Apt1           = Polar2D(PT02A, DimArrow1Angle + 15.0, ArrowLen)
    local Apt2           = Polar2D(PT02A, DimArrow1Angle - 15.0, ArrowLen)
    local TxtPt1         = Polar2D(Polar2D(PT02A, DimArrow1Angle, TxtCenter), DimArrow1Angle + 90.0, ArrowLen)
    local TxtPt          = Polar2D(TxtPt1, DimArrow2Angle, StrSet)
    local ArrowHead      = (ArrowLen * 0.333)
    local line1          = Contour(0.0)
    local layer1         = job.LayerManager:GetLayerWithName(Layer)
    line1:AppendPoint(Apt1)
    line1:LineTo(PT02A)
    line1:LineTo(Apt2)
    line1:LineTo(Apt1)
    layer1:AddObject(CreateCadContour(line1), true)
    local Apt3 = Polar2D(PT02B, DimArrow2Angle + 15.0, ArrowLen)
    local Apt4 = Polar2D(PT02B, DimArrow2Angle - 15.0, ArrowLen)
    local line2 = Contour(0.0)
    local layer2 = job.LayerManager:GetLayerWithName(Layer)
    line2:AppendPoint(Apt3)
    line2:LineTo(PT02B)
    line2:LineTo(Apt4)
    line2:LineTo(Apt3)
    layer2:AddObject(CreateCadContour(line2), true)
    if Ext1 then
      local lineA = Contour(0.0)
      local layerA = job.LayerManager:GetLayerWithName(Layer)
      lineA:AppendPoint(PT01A)
      lineA:LineTo(PT03A)
      layerA:AddObject(CreateCadContour(lineA), true)
    end -- if end
    if Ext2 then
      local lineB = Contour(0.0)
      local layerB = job.LayerManager:GetLayerWithName(Layer)
      lineB:AppendPoint(PT01B)
      lineB:LineTo(PT03B)
      layerB:AddObject(CreateCadContour(lineB), true)
    end -- if end
    local lineC = Contour(0.0)
    local layerC = job.LayerManager:GetLayerWithName(Layer)
    lineC:AppendPoint(PT02A)
    lineC:LineTo(PT02B)
    layerC:AddObject(CreateCadContour(lineC), true)
    DrawWriter(Double2Fraction(Str), TxtPt, ArrowLen, Layer, DimArrow1Angle)
    return true
  end -- function end

LayerClear

TopOfPage.png

Deletes Layer if empty.

function LayerClear(LayerName)
   local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
   if Mylayer.IsEmpty then
     Milling.job.LayerManager:RemoveLayer(Mylayer)
   end -- if end
   return true
 end -- function end

LeaderLine

TopOfPage.png
function DrawLeader(Pt1, Pt2, Pt3, Str, Layer, scale)   --Draws a leader with text
  --[[
  DrawLeader(pt1, pt2, "122.5", "TestLayer", 6.0)
  --]]
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: No job loaded")
      return false
    end -- if end
    local ArrowLen       = 0.125 * scale
    local DimArrowAngle  = GetPolarDirection(Pt1, Pt2, Polar2D(Pt2, 0.0, 1.0))
    local TxtAngle       = GetPolarDirection(Pt2, Pt3, Polar2D(Pt3, 0.0, 1.0))
    local TxtPt          = Polar2D(Polar2D(Pt3, TxtAngle, ArrowLen), TxtAngle-45, H(ArrowLen))
    local Apt1           = Polar2D(Pt1, DimArrowAngle + 15.0, ArrowLen)
    local Apt2           = Polar2D(Pt1, DimArrowAngle - 15.0, ArrowLen)
    local ArrowHead      = ArrowLen * 0.333
    local line1          = Contour(0.0)
    local layer1         = job.LayerManager:GetLayerWithName(Layer)
    line1:AppendPoint(Pt1)
    line1:LineTo(Apt2) ;  line1:LineTo(Apt1) ; line1:LineTo(Pt1)
    layer1:AddObject(CreateCadContour(line1), true)
    local lineC = Contour(0.0)
    local layerC = job.LayerManager:GetLayerWithName(Layer)
    lineC:AppendPoint(Pt1)
    lineC:LineTo(Pt2)
    lineC:LineTo(Pt3)
    layerC:AddObject(CreateCadContour(lineC), true)
    if IsAllNumber(Str) then
      DrawWriter(Double2Fraction(Str), TxtPt, ArrowLen, Layer, TxtAngle)
    else
      DrawWriter(Str, TxtPt, ArrowLen, Layer, TxtAngle)
    end -- if end
    return true
  end -- function end

Scale

TopOfPage.png

Provides the correct scale rate-based drawing units.

function Scale(Num)
   local mtl_block = MaterialBlock()
   if mtl_block.InMM then
     return Num * 25.4
   else
     return Num
   end
 end -- function end

AssyHoler

TopOfPage.png

Draws Assy Holes in a stright line (Rabbet and/or Dado).

function AssyHoler(pt1, pt2, PartName)                  -- Draws Assy Holes in a stright line
     local Ang1 = GetPolarDirection(pt1, pt2)
     local Ang2 = GetPolarDirection(pt2, pt1)
            pt1 = Polar2D(pt1, Ang1, Milling.AssemblyHoleStartEnd)
     DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
            pt2 = Polar2D(pt2, Ang2, Milling.AssemblyHoleStartEnd)
     DrawCircle(pt2, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
     local Dist = GetDistance(pt1, pt2)
     if Project.Debugger then
        DMark("pt1", pt1)
        DMark("pt2", pt2)
     end -- if end 
     BaseScrew(2)
     Milling.AssemblyHoleSpace = ((Milling.AssemblyHoleMaxSpace + Milling.AssemblyHoleMinSpace) * 0.5)
     HoleCount = Round(math.floor(Dist / Milling.AssemblyHoleSpace))
     HoleSpacing = (Dist / HoleCount)
     HoleCount = (Dist / HoleSpacing)
     if (Dist > (HoleSpacing * 2.0)) then
     for i = HoleCount, 1, -1 do
       pt1 = Polar2D(pt1, Ang1, HoleSpacing)
       DrawCircle(pt1, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
       if Project.Debugger then
 >       DMark("pt1w", pt1)
       end -- if end
       BaseScrew(1)
     end -- for end
   elseif (Dist > HoleSpacing) then
     ptC = Polar2D(pt1, Ang1, Dist / 2.0)
     if Project.Debugger then
       DMark("ptC", ptC)
     end -- if end
     DrawCircle(ptC, Milling.AssemblyHoleRad, Milling.LNAssemblyHole .. PartName)
   else
     -- Done No Holes
   end -- if end
   return true
 end -- function end

DrawBoneCenter2Pts

TopOfPage.png

Draws dog bone joints.

function DrawBoneCenter2Pts(pt1, pt2, SlotWidth, BitRadius)
   Local Project = {}
   Project.job   = VectricJob()
   Project.ang   = GetPolarDirection(pt1, pt2)
   Project.dis   = H(SlotWidth)
   Project.bit   = math.sin(math.rad(45.0)) * BitRadius
   Project.ptA   = Polar2D(pt1, Project.ang +  90.0, Project.dis)
   Project.ptAa  = Polar2D(Project.ptA, Project.ang, Project.bit)
   Project.ptAb  = Polar2D(Project.ptA, Project.ang + 270.0, Project.bit)
   Project.ptB   = Polar2D(pt1, Project.ang + 270.0, Project.dis)
   Project.ptBa  = Polar2D(Project.ptB, Project.ang +  90.0, Project.bit)
   Project.ptBb  = Polar2D(Project.ptB, Project.ang, Project.bit)
   Project.ptC   = Polar2D(pt2, Project.ang + 270.0, Project.dis)
   Project.ptCa  = Polar2D(Project.ptC, Project.ang +  90.0, Project.bit)
   Project.ptCb  = Polar2D(Project.ptC, Project.ang - 180.0, Project.bit)
   Project.ptD   = Polar2D(pt2, Project.ang +  90.0, Project.dis)
   Project.ptDa  = Polar2D(Project.ptD, Project.ang - 180.0, Project.bit)
   Project.ptDb  = Polar2D(Project.ptD, Project.ang + 270.0, Project.bit)
   Project.line  = Contour(0.0)
   Project.layer = Project.job.LayerManager:GetLayerWithName("DogBone")
   Project.line:AppendPoint(Project.ptAa)
   Project.line:ArcTo(Project.ptAb, 1.0)
   Project.line:LineTo(Project.ptBa)
   Project.line:ArcTo(Project.ptBb, 1.0)
   Project.line:LineTo(Project.ptCb)
   Project.line:ArcTo(Project.ptCa, 1.0)
   Project.line:LineTo(Project.ptDb)
   Project.line:ArcTo(Project.ptDa, 1.0)
   Project.line:LineTo(Project.ptAa)
   Project.layer:AddObject(CreateCadContour(Project.line), true)
   return true
 end -- function end

InsideCornerNipper

TopOfPage.png

Draws the nipping of a corner for easy fitting.

function InsideCornerNipper(AngPlung, BitRadius, CornerPt)
   local NipLength = math.sin(math.rad(45.0)) * ((BitRadius + 0.04) * 2.0)
   local Pt1, Pt2 = Point2D()
   if Material.Orientation == "V" then
     Pt1 = Polar2D(CornerPt, (AngPlung + 90.0) - 45.0, NipLength)
     Pt2 = Polar2D(CornerPt, (AngPlung + 90.0) + 45.0, NipLength)
   else
     Pt1 = Polar2D(CornerPt, (AngPlung + 180.0) - 45.0, NipLength)
     Pt2 = Polar2D(CornerPt, (AngPlung + 180.0) + 45.0, NipLength)
   end
   return Pt1, Pt2
 end -- function end

AddGroupToJob

TopOfPage.png

Builds a Grouping from the layer selection.

function AddGroupToJob(job, group, layer_name)
   --[[  --------------- AddGroupToJob --------------------------------------------------|
   |  Add passed group to the job - returns object created
   |  Parameters:
   |     job              -- job we are working with
   |     group            -- group of contours to   add to document
   |     layer_name       -- name of layer group will be created on|
   |  Return Values:
   |     object created to represent group in document
   ]]
   --  create a CadObject to represent the  group
   local cad_object = CreateCadGroup(group);
   -- create a layer with passed name if it doesnt already exist
   local layer = job.LayerManager:GetLayerWithName(layer_name)
   -- and add our object to it
   layer:AddObject(cad_object, true)
   return cad_object
  end -- function end

DrawArc

TopOfPage.png

Draws an Arc from points provided.

function DrawArc(PtS, PtE, ArcRadius, Layer)
   --[[Draw Arc
   function main(script_path)
   local MyPt1 = Point2D(3.5,3.8)
   local MyPt2 = Point2D(3.5,6.8)
   local layer = "My Arc"
   DrawArc(MyPt1, MyPt2, -0.456, Layer)
   return true
   end -- function end
   -- -----------------------------------------------------]]
       local job = VectricJob()
       if not job.Exists then
         DisplayMessageBox("Error: No job loaded")
         return false
       end
       local line = Contour(0.0)
       local layer = job.LayerManager:GetLayerWithName(Layer)
       line:AppendPoint(PtS)
       line:ArcTo(PtE,1);
       layer:AddObject(CreateCadContour(line), true)
       return true
     end -- function end

DrawEllipse

TopOfPage.png

Draws a DrawEllipse from points provided.

function DrawEllipse(CenterPt, LongAxe, ShortAxe, Layer)
   local LongAngle = 90.0
   local ValueAB = (LongAxe - ShortAxe) * 0.50
   local ValueAC = ValueAB * math.cos(math.rad(LongAngle))
   local job = VectricJob()
   local LRad = LongAxe * 0.50
   local ptT = Polar2D(CenterPt, LongAngle, LRad)
   local X = 0.0
   local pty = Point2D(0.0,0.0)
   local ptx = Point2D(0.0,0.0)
   local mylayer = job.LayerManager:GetLayerWithName(Layer)
   local line = Contour(0.0)
         line:AppendPoint(ptT)
     while (X < 360.0) do
        pty = Polar2D(CenterPt, LongAngle + X, LRad)
    ValueAC = ValueAB * math.cos(math.rad(LongAngle + X))
    if ((LongAngle + X) >= 90.0) then
      ptx = Polar2D(pty, 180.0, ValueAC)
    else
      ptx = Polar2D(pty,   0.0, ValueAC)
    end
    line:LineTo(ptx)
    X = X + 1
   end -- while end
   line:LineTo(ptT)
   mylayer:AddObject(CreateCadContour(line), true)
   return true
 end -- function end

DrawEllipse1

TopOfPage.png

Draws a DrawEllipse from points provided.

function DrawEllipse1(DrawEllipse_CenterPt, DrawEllipse_LongAxe, DrawEllipse_ShortAxe, DrawEllipse_LongAxeAngle, DrawEllipse_Layer)
     -- ---------------------------------------------------]]
     function H(x)                                         -- Returns half the value
       return x * 0.5
     end -- function end
     -- ---------------------------------------------------]]
     function Polar2D(pt, ang, dis)                        -- Calculate a new point based on reference point, angle and distance.
     -- Returns a 2Dpoint(x, y)
       return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
     end -- End Function
     -- ---------------------------------------------------]]
     function GetDistance(objA, objB)
       local xDist = objB.x - objA.x
       local yDist = objB.y - objA.y
       return math.sqrt((xDist ^ 2) + (yDist ^ 2))
     end -- function end
     -- ---------------------------------------------------]]
     function Radius2Bulge (p1, p2, Rad)
       local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
       local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
       local bulge = (2 * seg) / chord
       return bulge
     end -- function end
     -- ---------------------------------------------------]]
   function GetPolarAngle(Start, Corner, End)
     local function GetPolarDirection(point1, point2)              --
       local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
       if point1.X < point2.X then
         if point1.Y < point2.Y then
           ang = ang + 0.0
         else
           ang = 360.0 - ang
         end -- if end
       else
         if point1.Y < point2.Y then
           ang = 180.0 - ang
         else
           ang = ang + 180.0
         end -- if end
       end -- if end
       if ang >=360 then
         ang = ang -360.0
       end -- if end
       return ang
     end -- function end
     return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
   end -- function end
     -- ---------------------------------------------------]]
 
     -- Call = DrawEllipse(2DPoint(20.0, 20.0), 20.0, 10.0, 0.0, "Jim")
     local job = VectricJob()
     local EndRadius = 0.0
     local TopRadius = 0.0
     local ptT = Polar2D(DrawEllipse_CenterPt,  (90.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
     local ptB = Polar2D(DrawEllipse_CenterPt, (270.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_ShortAxe))
     local ptR = Polar2D(DrawEllipse_CenterPt,   (0.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
     local ptL = Polar2D(DrawEllipse_CenterPt, (180.0 + DrawEllipse_LongAxeAngle), H(DrawEllipse_LongAxe))
     local ptC = DrawEllipse_CenterPt
     --[[
       DMark("ptC", ptC)
       DMark("ptT", ptT)
       DMark("ptB", ptB)
       DMark("ptL", ptL)
       DMark("ptR", ptR)]]
     local C_Offset = H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe)
     local LT_SlopeDist = H(GetDistance(ptL, ptT) - H(DrawEllipse_LongAxe - DrawEllipse_ShortAxe))
     local LT_Dist  = GetDistance(ptL, ptT)
     local LT_Angle = math.abs(90.0 - GetAngle(ptT, ptL, ptC))
     local pt_a = Polar2D(ptL, LT_Angle + DrawEllipse_LongAxeAngle, LT_SlopeDist)
     local aT_Dist  = GetDistance(pt_a, ptT)
     local aC_Dist = aT_Dist / (math.tan(math.rad(LT_Angle)))
     local Tc_Dist = math.sqrt(aT_Dist^2 + aC_Dist^2)
     local pt_c = Polar2D(ptT, (270.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
     local cC_Dist  = GetDistance(pt_c, ptC)
     local b_Dist = math.tan(math.rad(LT_Angle)) * cC_Dist
     local pt_b = Polar2D(ptC, (180.0 + DrawEllipse_LongAxeAngle), b_Dist)
     local pt_d = Polar2D(ptB,  (90.0 + DrawEllipse_LongAxeAngle), Tc_Dist)
     local pt_e = Polar2D(ptC,   (0.0 + DrawEllipse_LongAxeAngle), b_Dist)
     local pt1  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
     local pt2  = Polar2D(pt_d, (270.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
     local pt3  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) - LT_Angle, Tc_Dist)
     local pt4  = Polar2D(pt_c,  (90.0 + DrawEllipse_LongAxeAngle) + LT_Angle, Tc_Dist)
     --[[
       DMark("pt1", pt1)
       DMark("pt2", pt2)
       DMark("pt3", pt3)
       DMark("pt4", pt4)
       local line = Contour(0.0)
       local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
       line:AppendPoint(pt1)
       line:LineTo(pt2)
       line:LineTo(pt3)
       line:LineTo(pt4)
       line:LineTo(pt1)
       layer:AddObject(CreateCadContour(line), true)]]
     local T_Sec   = GetDistance(ptC, ptT) - H(GetDistance(pt1, pt4))
     local R_Sec   = GetDistance(ptC, ptR) - H(GetDistance(pt1, pt2))
     local T_Chor  = GetDistance(pt1, pt2)
     local R_Chor  = GetDistance(pt1, pt4)
     local T_Bulge = Radius2Bulge (pt1, pt2, Tc_Dist)
     local L_Bulge = Radius2Bulge (pt1, pt4, GetDistance(ptL, pt_b))
 
     local line = Contour(0.0)
     local layer = job.LayerManager:GetLayerWithName(DrawEllipse_Layer)
     line:AppendPoint(pt1)
     line:ArcTo(pt2, T_Bulge)
     line:ArcTo(pt3, L_Bulge)
     line:ArcTo(pt4, T_Bulge)
     line:ArcTo(pt1, L_Bulge)
     layer:AddObject(CreateCadContour(line), true)
     job:Refresh2DView()
     return true
  end -- function end

DrawBox

TopOfPage.png

Draws a Box from points provided.

function DrawBox(p1, p2, p3, p4, Layer)
     --[[ Draw Box
     function main(script_path)
     local MyPt1 = Point2D(1.0,1.0)
     local MyPt2 = Point2D(1.0,3.0)
     local MyPt3 = Point2D(3.0,1.0)
     local MyPt4 = Point2D(3.0,3.0)
     local layer = "My Box"
     DrawBox(MyPt1 ,MyPt2, MyPt3, MyPt4, Layer)
     return true
     end -- function end
   -- -----------------------------------------------------]]
       local job = VectricJob()
       if not job.Exists then
         DisplayMessageBox("Error: No job loaded")
         return false
       end -- if end
       local line = Contour(0.0)
       local layer = job.LayerManager:GetLayerWithName(Layer)
       line:AppendPoint(p1)
       line:LineTo(p2)
       line:LineTo(p3)
       line:LineTo(p4)
       line:LineTo(p1)
       layer:AddObject(CreateCadContour(line), true)
       return true
 end -- function end

DrawCircle

TopOfPage.png

Draws a circle.

function DrawCircle(Pt1, CenterRadius, Layer)
   --[[ ==Draw Circle==
     function main(script_path)
     local MyPt1 = Point2D(1.0,1.0)
     local MyRad = 3.0
     local layer = "My Box"
     DrawCircle(MyPt1, MyRad, Layer)
     return true
     end -- function end
   -- -----------------------------------------------------]]
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: No job loaded")
       return false
     end -- if end
     local pa = Polar2D(Pt1,   180.0, CenterRadius)
     local pb = Polar2D(Pt1,     0.0, CenterRadius)
     local Contour = Contour(0.0)
     local layer = job.LayerManager:GetLayerWithName(Layer)
     Contour:AppendPoint(pa)
     Contour:ArcTo(pb, 1)
     Contour:ArcTo(pa, 1)
     layer:AddObject(CreateCadContour(Contour), true)
     return true
 end -- function end


DrawLine

TopOfPage.png

Draws a Line from points provided.

function DrawLine(Pt1, Pt2, Layer)
   --[[Draws a line from Pt1 to Pt2 on the layer name.
   function main(script_path)
   local MyPt1 = Point2D(3.5,3.8)
   local MyPt2 = Point2D(3.5,6.8)
   local layer = "My Line"
   DrawLine(MyPt1 , MyPt2, MyPt3, Layer)
   return true
   end -- function end
   -- -----------------------------------------------------]]
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: No job loaded")
       return false
     end
     local line = Contour(0.0)
     local layer = job.LayerManager:GetLayerWithName(Layer)
     line:AppendPoint(Pt1)
     line:LineTo(Pt2)
     layer:AddObject(CreateCadContour(line), true)
     return true
 end -- function end

DrawStar

TopOfPage.png

Draws a Star from points provided.

function DrawStar(pt1, InRadius ,OutRadius, layer)      --This draw function requires the center point, inter star radius, outer star radius and layer name.
   --[[
     function main(script_path)
       local MyPt = Point2D(3.5,3.8)
       local InRadius = 9.0
       local OutRadius= 20.0
       local layer = "My Star"
       DrawStar(MyPt , InRadius ,OutRadius, layer)
       return true
     end -- function end
   -- -----------------------------------------------------]]
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: No job loaded")
       return false
     end
     local p1 =  Polar2D(pt1,  18.0,  OutRadius)
     local p2 =  Polar2D(pt1,  54.0,  InRadius)
     local p3 =  Polar2D(pt1,  90.0,  OutRadius)
     local p4 =  Polar2D(pt1,  126.0, InRadius)
     local p5 =  Polar2D(pt1,  162.0, OutRadius)
     local p6 =  Polar2D(pt1,  198.0, InRadius)
     local p7 =  Polar2D(pt1,  234.0, OutRadius)
     local p8 =  Polar2D(pt1,  270.0, InRadius)
     local p9 =  Polar2D(pt1,  306.0, OutRadius)
     local p0 =  Polar2D(pt1,  342.0, InRadius)
     local line = Contour(0.0)
    -- local layers = job.LayerManager:GetLayerWithName(layer)
     line:AppendPoint(p1);
     line:LineTo(p2);  line:LineTo(p3)
     line:LineTo(p4);  line:LineTo(p5)
     line:LineTo(p6);  line:LineTo(p7)
     line:LineTo(p8);  line:LineTo(p9)
     line:LineTo(p0);  line:LineTo(p1)
     layer:AddObject(CreateCadContour(line), true)
     job:Refresh2DView()
     return true
 end -- function end

DrawTriangle

TopOfPage.png

Draws a Triangle from points provided.

function DrawTriangle(p1, p2, p3, Layer)
   --<nowiki>[[Draw Triangle
     function main(script_path)
       local MyPt1 = Point2D(3.5,3.8)
       local MyPt2 = Point2D(3.5,6.8)
       local MyPt3 = Point2D(9.8,6.8)
       local layer = "My Triangle"
       DrawTriangle(MyPt1 , MyPt2, MyPt3, Layer)
       return true
     end -- function end 
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: No job loaded")
       return false
     end
     local line = Contour(0.0)
     local layer = job.LayerManager:GetLayerWithName(Layer)
     line:AppendPoint(p1)
     line:LineTo(p2)
     line:LineTo(p3)
     line:LineTo(p1)
     layer:AddObject(CreateCadContour(line), true)
     job:Refresh2DView()
     return true
   end -- function end
   -- =====================================================]]
   function Radius2Bulge (p1, p2, Rad)
     local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
     local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
     local bulge = (2 * seg) / chord
     return bulge
   end
   -- =====================================================]]
   function ChordSeg2Radius (Chr, Seg)
     local rad =  (((Chr * Chr)/(Seg * 4)) + Seg) / 2.0
     return rad
 end -- function end

CreateJob

TopOfPage.png

Create a new job/drawing setup.

function CreateJob(job_name, width, height, thickness, in_mm, job_origin, z_on_surface)
 --[[ ----------- CreateJob -------------------------------------------------
   | This function was provided "as is" by Vectric technical team and a part of the gadget API documentation.
   | Create a new empty job with the passed settings]]
   -- we fill in most of our bounds in a Box2D
   local job_bounds = Box2D()
   local blc = Point2D(0, 0)
   local trc = Point2D(width, height)
   local origin_offset = Vector2D(0,0)
   -- calculate bottom left corner offset for chosen origin
   if Template.DXFOrientation == "Vertical" then
     trc = Point2D(height, width)
     if (job_origin == "BLC") then
       origin_offset:Set(0, 0)
     elseif (job_origin == "BRC") then
       origin_offset:Set(height, 0)
     elseif (job_origin == "TRC") then
       origin_offset:Set(height, width)
     elseif (job_origin == "TLC") then
       origin_offset:Set(0, width)
     elseif (job_origin == "CENTRE") then
       origin_offset:Set(height / 2, width / 2)
     elseif (job_origin == "CENTER") then
       origin_offset:Set(height / 2, width / 2)
     else
       MessageBox("Unknown XY origin specified " .. job_origin)
     end
   else
     if (job_origin == "BLC") then
       origin_offset:Set(0, 0)
     elseif (job_origin == "BRC") then
       origin_offset:Set(width, 0)
     elseif (job_origin == "TRC") then
       origin_offset:Set(width, height)
     elseif (job_origin == "TLC") then
       origin_offset:Set(0, height)
     elseif (job_origin == "CENTRE") then
       origin_offset:Set(width / 2, height / 2)
     elseif (job_origin == "CENTER") then
       origin_offset:Set(width / 2, height / 2)
     else
       MessageBox("Unknown XY origin specified " .. job_origin)
     end
   end
   -- subtract the origin offset vector from our 'standard' corner positions to get position for corners for requested origin
   blc = blc - origin_offset
   trc = trc - origin_offset
   job_bounds:Merge(blc)
   job_bounds:Merge(trc)
   local success = CreateNewJob(job_name,job_bounds,thickness,in_mm,z_on_surface)
   return success
 end -- function end

DrawFontGrid - Draws font grid to create letters

TopOfPage.png

Draws the font grid for drawing new letters.

function DrawFontGrid(job)
     local pt = Point2D(0.3,0.3)
     local scl  = 1.0 -- (scl * 0.5)
     local pA0  = pt
     local ang  = 0.0
     local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl))
     local pA2  = Polar2D(pt, ang + 90.0000, (0.5000 * scl))
     local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl))
     local pA4  = Polar2D(pt, ang + 90.0000, (1.0000 * scl))
     local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl))
     local pA6  = Polar2D(pt, ang + 90.0000, (1.5000 * scl))
     local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl))
     local pA8  = Polar2D(pt, ang + 90.0000, (2.0000 * scl))
     local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl))
     local pA10 = Polar2D(pt, ang + 90.0000, (2.5000 * scl))
 
     PointCircle(pA0)
     PointCircle(pA1)
     PointCircle(pA2)
     PointCircle(pA3)
     PointCircle(pA4)
     PointCircle(pA5)
     PointCircle(pA6)
     PointCircle(pA7)
     PointCircle(pA8)
     PointCircle(pA9)
     PointCircle(pA10)
 
     local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl))
     local pB1  = Polar2D(pt, ang + 45.0000, (0.3536 * scl))
     local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl))
     local pB3  = Polar2D(pt, ang + 71.5651, (0.7906 * scl))
     local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl))
     local pB5  = Polar2D(pt, ang + 78.6901, (1.2748 * scl))
     local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl))
     local pB7  = Polar2D(pt, ang + 81.8699, (1.7678 * scl))
     local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl))
     local pB10 = Polar2D(pt, ang + 84.2894, (2.5125 * scl))
 
     PointCircle(pB0)
     PointCircle(pB1)
     PointCircle(pB2)
     PointCircle(pB3)
     PointCircle(pB4)
     PointCircle(pB5)
     PointCircle(pB7)
     PointCircle(pB8)
     PointCircle(pB10)
 
     local pC0 = Polar2D(pt, ang +  0.0000, (0.5000 * scl))
     local pC1 = Polar2D(pt, ang + 26.5650, (0.5590 * scl))
     local pC2 = Polar2D(pt, ang + 45.0000, (0.7071 * scl))
     local pC3 = Polar2D(pt, ang + 56.3099, (0.9014 * scl))
     local pC4 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
     local pC5 = Polar2D(pt, ang + 68.1993, (1.3463 * scl))
     local pC6 = Polar2D(pt, ang + 71.5650, (1.5811 * scl))
     local pC7 = Polar2D(pt, ang + 63.4342, (1.1180 * scl))
     local pC8 = Polar2D(pt, ang + 74.0550, (1.8201 * scl))
     local pC10 = Polar2D(pt, ang + 78.6899, (2.5495 * scl))
 
     PointCircle(pC0)
     PointCircle(pC1)
     PointCircle(pC2)
     PointCircle(pC3)
     PointCircle(pC4)
     PointCircle(pC6)
     PointCircle(pC8)
     PointCircle(pC10)
 
     local pD0 = Polar2D(pt, ang +  0.0000, (0.6250 * scl))
     local pD1 = Polar2D(pt, ang + 21.8014, (0.6731 * scl))
     local pD2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
     local pD4 = Polar2D(pt, ang + 57.9946, (1.1792 * scl))
     local pD7 = Polar2D(pt, ang + 70.3462, (1.8583 * scl))
     local pD8 = Polar2D(pt, ang + 72.6460, (2.0954 * scl))
 
     PointCircle(pD0)
     PointCircle(pD1)
     PointCircle(pD2)
     PointCircle(pD4)
     PointCircle(pD7)
     PointCircle(pD8)
 
     local pE0 = Polar2D(pt, ang +  0.0000, (0.7500 * scl))
     local pE1 = Polar2D(pt, ang + 18.4346, (0.7906 * scl))
     local pE2 = Polar2D(pt, ang + 33.6901, (0.9014 * scl))
     local pE3 = Polar2D(pt, ang + 45.0000, (1.0607 * scl))
     local pE5 = Polar2D(pt, ang + 59.0371, (1.4578 * scl))
     local pE6 = Polar2D(pt, ang + 63.4349, (1.6771 * scl))
     local pE7 = Polar2D(pt, ang + 66.4349, (1.9039 * scl))
     local pE8 = Polar2D(pt, ang + 69.4440, (2.1360 * scl))
 
     PointCircle(pE0)
     PointCircle(pE1)
     PointCircle(pE2)
     PointCircle(pE3)
     PointCircle(pE5)
     PointCircle(pE6)
     PointCircle(pE7)
     PointCircle(pE8)
 
     local pF0 = Polar2D(pt, ang +  0.0000, (1.0000 * scl))
     local pF1 = Polar2D(pt, ang + 14.0360, (1.0308 * scl))
     local pF2 = Polar2D(pt, ang + 26.5651, (1.1180 * scl))
     local pF3 = Polar2D(pt, ang + 36.8699, (1.2500 * scl))
     local pF4 = Polar2D(pt, ang + 45.0000, (1.4142 * scl))
     local pF5 = Polar2D(pt, ang + 51.3425, (1.6006 * scl))
     local pF6 = Polar2D(pt, ang + 56.3099, (1.8025 * scl))
     local pF7 = Polar2D(pt, ang + 60.2551, (2.0156 * scl))
     local pF8 = Polar2D(pt, ang + 63.4349, (2.2361 * scl))
 
     PointCircle(pF0)
     PointCircle(pF1)
     PointCircle(pF2)
     PointCircle(pF3)
     PointCircle(pF4)
     PointCircle(pF5)
     PointCircle(pF6)
     PointCircle(pF7)
     PointCircle(pF8)
 
     local pG0 = Polar2D(pt, ang +  0.0000, (1.2500 * scl))
     local pG1 = Polar2D(pt, ang + 11.3099, (1.2748 * scl))
     local pG2 = Polar2D(pt, ang + 21.8014, (1.3463 * scl))
     local pG3 = Polar2D(pt, ang + 30.9638, (1.4577 * scl))
     local pG4 = Polar2D(pt, ang + 38.6598, (1.6008 * scl))
     local pG5 = Polar2D(pt, ang + 45.0000, (1.7678 * scl))
     local pG6 = Polar2D(pt, ang + 50.1944, (1.9526 * scl))
     local pG7 = Polar2D(pt, ang + 54.4623, (2.1506 * scl))
     local pG8 = Polar2D(pt, ang + 57.9946, (2.3585 * scl))
     local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))
 
     PointCircle(pG0)
     PointCircle(pG1)
     PointCircle(pG2)
     PointCircle(pG3)
     PointCircle(pG4)
     PointCircle(pG5)
     PointCircle(pG6)
     PointCircle(pG7)
     PointCircle(pG8)
     PointCircle(pG10)
 
     local pH0  = Polar2D(pt, ang + 0.0000, (1.5000 * scl))
     local pH10 = Polar2D(pt, 63.4349,      (2.7951 * scl))
     PointCircle(pH0)
     PointCircle(pH10)
     job:Refresh2DView()
     return true
   end
 
 
   -- =========================================================================
   local function AddGroupToJob(job, group, layer_name)
      --  create a CadObject to represent the  group
     local cad_object = CreateCadGroup(group);
      -- create a layer with passed name if it doesnt already exist
     local layer = job.LayerManager:GetLayerWithName(layer_name)
      -- and add our object to it
     layer:AddObject(cad_object, true)
     return cad_object
   end -- end function
 
   -- =========================================================================
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: Not finding a job loaded")
       return false
     end
     local strlen = string.len(what)
     local strup = string.upper(what)
     local x = strlen
     local i = 1
     local y = ""
     local ptx = where
     group = ContourGroup(true)
     while i <=  x do
       y = string.byte(string.sub(strup, i, i))
       ptx = MonoFont(job, ptx, y, size, lay, ang)
       i = i + 1
     end -- while end;
     AddGroupToJob(job, group, lay)
     job:Refresh2DView()
     return true ;
 end -- function end

DrawWriter - Draws Upper and Lower case text on the drawing

TopOfPage.png
function DrawWriter(what, where, size, lay, ang) -- Draws Upper and Lower case text on the drawing.
   --[[ How to use:
   |    local TextMessage = "Your Text Here"
   |    local TextPt = Point2D(3.5,3.8)
   |    local TextHight = 0.5
   |    local TextLayer = "Text Layer"
   |    local TextAng = 20.0
   |    DrawWriter(TextMessage, TextPt , TextHight , TextLayer, TextAng)
   |    -- ==Draw Writer==
   |    -- Utilizing a provided string of text, the program walks the string and reproduces each letter (parametrically) on the drawing using vectors.
   function main()
       -- create a layer with passed name if it doesn't already exist
     local job = VectricJob()
     if not job.Exists then
          DisplayMessageBox("No job loaded")
          return false;
     end
     local TextMessage = "Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz 1 2 3 4 5 6 7 8 9 0 ! @ # $ % & * ( ) { } [ ] ? , . : ; '' ' _ - + = ~ ^ < > |"
     local TextPt = Point2D(0.1, 2.0)
     local TextHight = 0.25
     local TextLayer = "Gadget Text"
     local TextAng = 10.0
     DrawWriter(TextMessage, TextPt, TextHight, TextLayer, TextAng)
     job:Refresh2DView()
     return true
   end
   --]]
   -- =========================================================================
   local function Polar2D(pt, ang, dis)
     return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
   end
   -- =========================================================================
   local function MonoFont(job, pt, letter, scl, lay, ang)
     scl = (scl * 0.5) ;
     local pA0 = pt ;
     local pA1  = Polar2D(pt, ang + 90.0000, (0.2500 * scl)) ;  local pA2   = Polar2D(pt, ang + 90.0000, (0.5000 * scl)) ;
     local pA3  = Polar2D(pt, ang + 90.0000, (0.7500 * scl)) ;  local pA4   = Polar2D(pt, ang + 90.0000, (1.0000 * scl)) ;
     local pA5  = Polar2D(pt, ang + 90.0000, (1.2500 * scl)) ;  local pA6   = Polar2D(pt, ang + 90.0000, (1.5000 * scl)) ;
     local pA7  = Polar2D(pt, ang + 90.0000, (1.7500 * scl)) ;  local pA8   = Polar2D(pt, ang + 90.0000, (2.0000 * scl)) ;
     local pA9  = Polar2D(pt, ang + 90.0000, (2.2500 * scl)) ;  local pA10  = Polar2D(pt, ang + 90.0000, (2.5000 * scl)) ;
     local pB0  = Polar2D(pt, ang +  0.0000, (0.2500 * scl)) ;  local pB1   = Polar2D(pt, ang + 45.0000, (0.3536 * scl)) ;
     local pB2  = Polar2D(pt, ang + 63.4352, (0.5590 * scl)) ;  local pB3   = Polar2D(pt, ang + 71.5651, (0.7906 * scl)) ;
     local pB4  = Polar2D(pt, ang + 75.9638, (1.0308 * scl)) ;  local pB5   = Polar2D(pt, ang + 78.6901, (1.2748 * scl)) ;
     local pB6  = Polar2D(pt, ang + 80.5376, (1.5207 * scl)) ;  local pB7   = Polar2D(pt, ang + 81.8699, (1.7678 * scl)) ;
     local pB8  = Polar2D(pt, ang + 82.8750, (2.0156 * scl)) ;  local pB10  = Polar2D(pt, ang + 84.2894, (2.5125 * scl)) ;
     local pC0  = Polar2D(pt, ang +  0.0000, (0.5000 * scl)) ;  local pC1   = Polar2D(pt, ang + 26.5650, (0.5590 * scl)) ;
     local pC2  = Polar2D(pt, ang + 45.0000, (0.7071 * scl)) ;  local pC3   = Polar2D(pt, ang + 56.3099, (0.9014 * scl)) ;
     local pC4  = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;  local pC5   = Polar2D(pt, ang + 68.1993, (1.3463 * scl)) ;
     local pC6  = Polar2D(pt, ang + 71.5650, (1.5811 * scl)) ;  local pC7   = Polar2D(pt, ang + 63.4342, (1.1180 * scl)) ;
     local pC8  = Polar2D(pt, ang + 75.9640, (2.0616 * scl)) ;  local pC10  = Polar2D(pt, ang + 78.6899, (2.5495 * scl)) ;
     local pD0  = Polar2D(pt, ang +  0.0000, (0.6250 * scl)) ;  local pD1   = Polar2D(pt, ang + 21.8014, (0.6731 * scl)) ;
     local pD2  = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pD4   = Polar2D(pt, ang + 57.9946, (1.1792 * scl)) ;
     local pD7  = Polar2D(pt, ang + 70.3462, (1.8583 * scl)) ;  local pD8   = Polar2D(pt, ang + 72.6460, (2.0954 * scl)) ;
     local pE0  = Polar2D(pt, ang +  0.0000, (0.7500 * scl)) ;  local pE1   = Polar2D(pt, ang + 18.4346, (0.7906 * scl)) ;
     local pE2  = Polar2D(pt, ang + 33.6901, (0.9014 * scl)) ;  local pE3   = Polar2D(pt, ang + 45.0000, (1.0607 * scl)) ;
     local pE5  = Polar2D(pt, ang + 59.0371, (1.4578 * scl)) ;  local pE6   = Polar2D(pt, ang + 63.4349, (1.6771 * scl)) ;
     local pE7  = Polar2D(pt, ang + 66.4349, (1.9039 * scl)) ;  local pE8   = Polar2D(pt, ang + 69.4440, (2.1360 * scl)) ;
     local pF0  = Polar2D(pt, ang +  0.0000, (1.0000 * scl)) ;  local pF1   = Polar2D(pt, ang + 14.0360, (1.0308 * scl)) ;
     local pF2  = Polar2D(pt, ang + 26.5651, (1.1180 * scl)) ;  local pF3   = Polar2D(pt, ang + 36.8699, (1.2500 * scl)) ;
     local pF4  = Polar2D(pt, ang + 45.0000, (1.4142 * scl)) ;  local pF5   = Polar2D(pt, ang + 51.3425, (1.6006 * scl)) ;
     local pF6  = Polar2D(pt, ang + 56.3099, (1.8025 * scl)) ;  local pF7   = Polar2D(pt, ang + 60.2551, (2.0156 * scl)) ;
     local pF8  = Polar2D(pt, ang + 63.4349, (2.2361 * scl)) ;  local pG0   = Polar2D(pt, ang +  0.0000, (1.2500 * scl)) ;
     local pG1  = Polar2D(pt, ang + 11.3099, (1.2748 * scl)) ;  local pG2   = Polar2D(pt, ang + 21.8014, (1.3463 * scl)) ;
     local pG3  = Polar2D(pt, ang + 30.9638, (1.4577 * scl)) ;  local pG4   = Polar2D(pt, ang + 38.6598, (1.6008 * scl)) ;
     local pG5  = Polar2D(pt, ang + 45.0000, (1.7678 * scl)) ;  local pG6   = Polar2D(pt, ang + 50.1944, (1.9526 * scl)) ;
     local pG7  = Polar2D(pt, ang + 54.4623, (2.1506 * scl)) ;  local pG8   = Polar2D(pt, ang + 57.9946, (2.3585 * scl)) ;
     local pG10 = Polar2D(pt,59.0362, (2.9155 * scl))        ;  local pH0   = Polar2D(pt, ang +  0.0000, (1.5000 * scl)) ;
     local pH10 = Polar2D(pt,63.4349, (2.7951 * scl))        ;  local layer = job.LayerManager:GetLayerWithName(lay) ;
     local line = Contour(0.0) ;
    -- ------------------------------------------------------------------------
     if letter == 32 then
       pH0 = pH0
     end
     if letter == 33 then
       line:AppendPoint(pB0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
       line = Contour(0.0) line:AppendPoint(pB3) ;  line:LineTo(pE3) ;  line:LineTo(pE8) ;  line:LineTo(pB8) ;  line:LineTo(pB3) ;  group:AddTail(line) ;
     end
     if letter == 34 then
       line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB7) ;  line:LineTo(pC10) ;
       group:AddTail(line) ;  pH0 = pE0
     end
     if letter == 35 then
       line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
       line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;
       line = Contour(0.0) ;  line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;
     end
     if letter == 36 then
       line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
       line:LineTo(pB4) ;  line:LineTo(pA5) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  group:AddTail(line) ;
       line = Contour(0.0) ;  line:AppendPoint(pC0) ;  line:LineTo(pE0) ;  line:LineTo(pE8) ;  line:LineTo(pC8) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
     end
     if letter == 37 then
       line:AppendPoint(pC6) ;  line:LineTo(pC8) ;  line:LineTo(pA8) ;  line:LineTo(pA6) ;  line:LineTo(pE6) ;  line:LineTo(pG8) ;
       line:LineTo(pA0) ;  line:LineTo(pC2) ;  line:LineTo(pG2) ;  line:LineTo(pG0) ;  line:LineTo(pE0) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
     end
     if letter == 38 then
       line:AppendPoint(pG2) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA3) ;
       line:LineTo(pE6) ;  line:LineTo(pE7) ;  line:LineTo(pD8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA6) ;  line:LineTo(pG0) ;
       group:AddTail(line) ;
     end
     if letter == 39 then
       line:AppendPoint(pA7) ;  line:LineTo(pB10) ;  group:AddTail(line) ;  pH0 = pC0
     end
     if letter == 40 then
       line:AppendPoint(pB8) ;  line:LineTo(pA5) ;  line:LineTo(pA3) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  pH0 = pD0
     end
     if letter == 41 then
       line:AppendPoint(pA8) ;  line:LineTo(pB5) ;  line:LineTo(pB3) ;  line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pG0
     end
     if letter == 42 then
       line:AppendPoint(pA2) ;  line:LineTo(pG6) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;  line:LineTo(pG2) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD7) ;
       line:LineTo(pD1) ;  group:AddTail(line) ;
     end
     if letter == 43 then
       line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD1) ;  line:LineTo(pD7) ;
       group:AddTail(line)
     end
     if letter == 44 then
       line:AppendPoint(pC0) ;  line:LineTo(pE2) ;  line:LineTo(pC2) ;  line:LineTo(pC4) ;  line:LineTo(pF4) ;  line:LineTo(pF2) ;
       line:LineTo(pD0) ;  line:LineTo(pC0) ;  group:AddTail(line) ;
     end
     if letter == 45 then
       line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
     end
     if letter == 46 then
       line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  pH0 = pD0 ;
     end
     if letter == 47 then
       line:AppendPoint(pA0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
     end
     if letter == 48 then
       line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
       line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG8) ;  line:LineTo(pA0) ; group:AddTail(line) ;
     end
     if letter == 49 then
       line:AppendPoint(pA6) ;  line:LineTo(pD8) ;  line:LineTo(pD0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;
       line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 50 then
       line:AppendPoint(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;
       line:LineTo(pA2) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 51 then
       line:AppendPoint(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
       line:LineTo(pG3) ;  line:LineTo(pG1) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;
       line:AppendPoint(pF4) ;  line:LineTo(pB4) ;  group:AddTail(line) ;
     end
     if letter == 52 then
       line:AppendPoint(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;
     end
     if letter == 53 then
       line:AppendPoint(pG8) ;  line:LineTo(pA8) ;  line:LineTo(pA5) ;  line:LineTo(pF4) ;  line:LineTo(pG3) ;  line:LineTo(pG1) ;
       line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA1) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
     end
     if letter == 54 then
       line:AppendPoint(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA1) ;  line:LineTo(pB0) ;
       line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
     end
     if letter == 55 then
       line:AppendPoint(pB0) ;  line:LineTo(pG8) ;  line:LineTo(pA8) ;  group:AddTail(line) ;
     end
     if letter == 56 then
       line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;
       line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;
       line:LineTo(pA3) ;  line:LineTo(pA1) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB4) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
     end
     if letter == 57 then
       line:AppendPoint(pA1) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG3) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;
       line:LineTo(pB8) ;  line:LineTo(pA7) ;  line:LineTo(pA5) ;  line:LineTo(pB4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  group:AddTail(line) ;
     end
     if letter == 58 then
       line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  line:LineTo(pA0) ;  line:LineTo(pA1) ;
       group:AddTail(line) ;  pH0 = pD0 ;
     end
     if letter == 59 then
       line:AppendPoint(pB8) ;  line:LineTo(pA8) ;  line:LineTo(pA7) ;  line:LineTo(pB7) ;  line:LineTo(pB8) ;  line:LineTo(pA8) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB3) ;  line:LineTo(pB4) ;  line:LineTo(pA4) ;  line:LineTo(pA3) ;  line:LineTo(pB3) ;
       line:LineTo(pA0) ;  group:AddTail(line) ;  pH0 = pD0 ;
     end
     if letter == 60 then
       line:AppendPoint(pF8) ;  line:LineTo(pA4) ;  line:LineTo(pG0) ;  group:AddTail(line)
     end
     if letter == 61 then
       line:AppendPoint(pA2) ;  line:LineTo(pG2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA6) ;
       line:LineTo(pG6) ;  group:AddTail(line) ;
     end
     if letter == 62 then
       line:AppendPoint(pA8) ;  line:LineTo(pF4) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 63 then
       line:AppendPoint(pB5) ;  line:LineTo(pA6) ;  line:LineTo(pA7) ;  line:LineTo(pB8) ;  line:LineTo(pE8) ;  line:LineTo(pF7) ;
       line:LineTo(pF5) ;  line:LineTo(pC3) ;  line:LineTo(pC2) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pB0) ;  line:LineTo(pE0) ;
       line:LineTo(pE1) ;  line:LineTo(pB1) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
     end
     if letter == 64 then
       line:AppendPoint(pG0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;
       line:LineTo(pG6) ;  line:LineTo(pG3) ;  line:LineTo(pE2) ;  line:LineTo(pB2) ;  line:LineTo(pB5) ;  line:LineTo(pE5) ;  line:LineTo(pE2) ;
       group:AddTail(line)
     end
     if letter == 65 then
       line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
       line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 66 then
       line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
       line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
     end
     if letter == 67 then
       line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
       line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
     end
     if letter == 68 then
       line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
       line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 69 then
       line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
       line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
     end
     if letter == 70 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
       line:LineTo(pF4) ;  group:AddTail(line) ;
     end
     if letter == 71 then
       line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
       line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
     end
     if letter == 72 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
     end
     if letter == 73 then
       line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
     end
     if letter == 74 then
       line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
       group:AddTail(line) ;
     end
     if letter == 75 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 76 then
       line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 77 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 78 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
     end
     if letter == 79 then
       line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
       line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
     end
     if letter == 80 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
       line:LineTo(pA4) ;  group:AddTail(line) ;
     end
     if letter == 81 then
       line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
       line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
     end
     if letter == 82 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
       line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 83 then
       line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
       line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
     end
     if letter == 84 then
       line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
       line:LineTo(pD0) ;  group:AddTail(line) ;
     end
     if letter == 85 then
       line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
       group:AddTail(line) ;
     end
     if letter == 86 then
       line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
     end
     if letter == 87 then
       line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
     end
     if letter == 88 then
       line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
       line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 89 then
       line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
       line:LineTo(pD4) ;  group:AddTail(line) ;
     end
     if letter == 90 then
       line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
 
     if letter == 91 then
       line:AppendPoint(pC0) ;  line:LineTo(pB0) ;  line:LineTo(pB8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;
     end
     if letter == 92 then
       line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
     end
     if letter == 93 then
       line:AppendPoint(pE0) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  line:LineTo(pE8) ;  group:AddTail(line) ;
     end
     if letter == 94 then
       line:AppendPoint(pD8) ;  line:LineTo(pG6) ;  line:LineTo(pG5) ;  line:LineTo(pD7) ;  line:LineTo(pA5) ;  line:LineTo(pA6) ;
       line:LineTo(pD8) ;  group:AddTail(line) ;
     end
     if letter == 95 then
       line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  group:AddTail(line) ;
     end
     if letter == 96 then
       line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
     end
     -- Start of Lower Case
     if letter == 97 then
       line:AppendPoint(pA0) ;  line:LineTo(pD8) ;  line:LineTo(pG0) ;  line:LineTo(pF3) ;  line:LineTo(pB3) ;
       line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 98 then
       line:AppendPoint(pA4) ;  line:LineTo(pF4) ;  line:LineTo(pG5) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
       line:LineTo(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG1) ;  line:LineTo(pG3) ;  line:LineTo(pF4) ;  group:AddTail(line) ;
     end
     if letter == 99 then
       line:AppendPoint(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;
       line:LineTo(pF8) ;  line:LineTo(pG6) ;  group:AddTail(line) ;
     end
     if letter == 100 then
       line:AppendPoint(pA0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pA8) ;
       line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 101 then
       line:AppendPoint(pG0) ;  line:LineTo(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  line = Contour(0.0) ;
       line:AppendPoint(pA4) ;  line:LineTo(pD4) ;  group:AddTail(line) ;
     end
     if letter == 102 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;
       line:LineTo(pF4) ;  group:AddTail(line) ;
     end
     if letter == 103 then
       line:AppendPoint(pG6) ;  line:LineTo(pG7) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA2) ;
       line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG3) ;  line:LineTo(pE3) ;  line:LineTo(pE2) ;  group:AddTail(line) ;
     end
     if letter == 104 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pG8) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA4) ;  line:LineTo(pG4) ;  group:AddTail(line) ;
     end
     if letter == 105 then
       line:AppendPoint(pB0) ;  line:LineTo(pB8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA0) ;  line:LineTo(pC0) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;  line:LineTo(pC8) ;  group:AddTail(line) ;  pH0 = pE0 ;
     end
     if letter == 106 then
       line:AppendPoint(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;  line:LineTo(pC8) ;
       group:AddTail(line) ;
     end
     if letter == 107 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA2) ;  line:LineTo(pG7) ;
       group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 108 then
       line:AppendPoint(pA8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 109 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 110 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF0) ;  line:LineTo(pF8) ;  group:AddTail(line) ;  pH0 = pG0 ;
     end
     if letter == 111 then
       line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
       line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;
     end
     if letter == 112 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
       line:LineTo(pA4) ;  group:AddTail(line) ;
     end
     if letter == 113 then
       line:AppendPoint(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA6) ;  line:LineTo(pB8) ;  line:LineTo(pF8) ;  line:LineTo(pG6) ;
       line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pG0) ;  line:LineTo(pD4) ; group:AddTail(line)
     end
     if letter == 114 then
       line:AppendPoint(pA0) ;  line:LineTo(pA8) ;  line:LineTo(pF8) ;  line:LineTo(pG7) ;  line:LineTo(pG5) ;  line:LineTo(pF4) ;
       line:LineTo(pA4) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD4) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 115 then
       line:AppendPoint(pG5) ;  line:LineTo(pG6) ;  line:LineTo(pF8) ;  line:LineTo(pB8) ;  line:LineTo(pA6) ;  line:LineTo(pA5) ;
       line:LineTo(pG3) ;  line:LineTo(pG2) ;  line:LineTo(pF0) ;  line:LineTo(pB0) ;  line:LineTo(pA2) ;  line:LineTo(pA3) ;  group:AddTail(line) ;
     end
     if letter == 116 then
       line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD8) ;
       line:LineTo(pD0) ;  group:AddTail(line) ;
     end
     if letter == 117 then
       line:AppendPoint(pA8) ;  line:LineTo(pA2) ;  line:LineTo(pB0) ;  line:LineTo(pF0) ;  line:LineTo(pG2) ;  line:LineTo(pG8) ;
       group:AddTail(line) ;
     end
     if letter == 118 then
       line:AppendPoint(pA8) ;  line:LineTo(pD0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
     end
     if letter == 119 then
       line:AppendPoint(pA8) ;  line:LineTo(pB0) ;  line:LineTo(pD4) ;  line:LineTo(pF0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;
     end
     if letter == 120 then
       line:AppendPoint(pA0) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pA8) ;
       line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     if letter == 121 then
       line:AppendPoint(pA8) ;  line:LineTo(pD4) ;  line:LineTo(pG8) ;  group:AddTail(line) ;  line = Contour(0.0) ;  line:AppendPoint(pD0) ;
       line:LineTo(pD4) ;  group:AddTail(line) ;
     end
     if letter == 122 then
       line:AppendPoint(pA8) ;  line:LineTo(pG8) ;  line:LineTo(pA0) ;  line:LineTo(pG0) ;  group:AddTail(line) ;
     end
     -- End of Lower Case
     if letter == 123 then
       line:AppendPoint(pD0) ;  line:LineTo(pC0) ;  line:LineTo(pB1) ;  line:LineTo(pB2) ;  line:LineTo(pC3) ;  line:LineTo(pA4) ;
       line:LineTo(pC5) ;  line:LineTo(pB6) ;  line:LineTo(pB7) ;  line:LineTo(pC8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
     end
     if letter == 124 then
       line:AppendPoint(pA0) ;  line:LineTo(pA10) ;  line:LineTo(pC10) ;  line:LineTo(pC0) ;  line:LineTo(pA0) ;  group:AddTail(line) ;
     end
     if letter == 125 then
       line:AppendPoint(pD0) ;  line:LineTo(pE0) ;  line:LineTo(pF1) ;  line:LineTo(pF2) ;  line:LineTo(pE3) ;  line:LineTo(pG4) ;
       line:LineTo(pE5) ;  line:LineTo(pF6) ;  line:LineTo(pF7) ;  line:LineTo(pE8) ;  line:LineTo(pD8) ;  group:AddTail(line) ;
     end
     if letter == 126 then
       line:AppendPoint(pA2) ;  line:LineTo(pA3) ;  line:LineTo(pB5) ;  line:LineTo(pF3) ;  line:LineTo(pG5) ;
       line:LineTo(pG4) ;  line:LineTo(pF2) ;  line:LineTo(pB4) ;  line:LineTo(pA2) ;  group:AddTail(line) ;
     end
     return pH0
   end -- function end
 
   -- =========================================================================
   local function AddGroupToJob(job, group, layer_name)
      --  create a CadObject to represent the  group
     local cad_object = CreateCadGroup(group);
      -- create a layer with passed name if it doesnt already exist
     local layer = job.LayerManager:GetLayerWithName(layer_name)
      -- and add our object to it
     layer:AddObject(cad_object, true)
     return cad_object
   end -- end function
 
   -- =========================================================================
     local job = VectricJob()
     if not job.Exists then
       DisplayMessageBox("Error: Not finding a job loaded")
       return false
     end
     local strlen = string.len(what)
     local strup = what
     local x = strlen
     local i = 1
     local y = ""
     local ptx = where
     group = ContourGroup(true)
     while i <=  x do
       y = string.byte(string.sub(strup, i, i))
       if (y >= 97) and (y <= 122) then -- Lower case
         ptx = MonoFont(job, ptx, y, (size * 0.75), lay, ang)
         ptx = Polar2D(ptx, ang, size * 0.05)
       else -- Upper case
         ptx = MonoFont(job, ptx, y, size, lay, ang)
         ptx = Polar2D(ptx, ang, size * 0.07)
       end
       i = i + 1
     end -- while end;
     AddGroupToJob(job, group, lay)
     job:Refresh2DView()
     return true
 end -- function end

Holer - Draws two Holes and groups them

TopOfPage.png

Draws circles based on a layout.

function Holer(pt, ang, dst, dia, lay)
       local job = VectricJob()
       if not job.Exists then
         DisplayMessageBox("Error: No job loaded")
         return false
       end
     --Caller: Holer(ptx, anx, BaseDim.HoleSpace, Milling.ShelfPinRadius, Milling.LNSideShelfPinDrill .. "-Base")
       local function AddGroupToJob(job, group, layer_name)
         local cad_object = CreateCadGroup(group);
         local layer = job.LayerManager:GetLayerWithName(layer_name)
         layer:AddObject(cad_object, true)
         return cad_object
       end
     local group = ContourGroup(true)
     group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
     pt = Polar2D(pt, ang, dst)
     group:AddTail(CreateCircle(pt.x, pt.y, dia, 0.0, 0.0))
     AddGroupToJob(job, group, lay)
     return true
 end -- function end

Data Export Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

LogWriter

TopOfPage.png

Writes a Log items to the log file.

 function LogWriter(LogName, xText)
  -- Adds a new xText Line to a app log file
  -- local LogName = Door.CSVPath .. "\\" .. Door.RuntimeLog .. ".txt"
  local fileW = io.open(LogName,  "a")
  if fileW then
    fileW:write(xText .. "\n")
    fileW:close()
  end -- if end
  Maindialog:UpdateLabelField("Door.Alert", "Note: Errors are logged in the CSF file folder.")
  return true
end -- function end  

Write_CSV

TopOfPage.png

Writes the values to a csv format file.

 function Write_CSV(xFilename) -- Writes the values to a csv format file
 -- Usage: Write_CSV("C:\\Path\\MyName.csv")
 -- Door.CSVPath = dialog:GetTextField("DoorCSVPath")
 -- local filename = Path .. "\\" .. Name .. ".csv"
  local filename = xFilename
  local file = io.open(filename, "w")
  if file then  -- if the file was opened
    file:write("Count,Height,Width\n")  -- Header Line
    if Door.Unit then
      file:write("1,110,595\n");    file:write("1,150,75\n");     file:write("1,175,395\n");     file:write("1,140,495\n")
      file:write("1,175,445\n");    file:write("1,175,595\n");    file:write("2,200,100\n");     file:write("3,250,125\n")
      file:write("1,300,150\n");    file:write("2,350,175\n");    file:write("3,400,200\n");     file:write("1,450,225\n")
      file:write("2,500,250\n");    file:write("3,550,275\n");    file:write("1,600,300\n");     file:write("2,650,325\n")
      file:write("3,700,350\n");    file:write("1,750,375\n");    file:write("2,800,400\n");     file:write("3,850,425\n");
      file:write("1,900,450\n");    file:write("2,950,475\n");    file:write("3,1000,500\n");    file:write("1,1050,525\n");
      file:write("2,1100,550\n");   file:write("3,1150,575\n");   file:write("1,1200,600\n");    file:write("2,1250,625\n");
      file:write("3,1300,650\n");   file:write("1,1350,675\n");   file:write("2,1400,700\n");    file:write("3,1450,725\n");
      file:write("1,1500,750\n");   file:write("2,1550,775\n");   file:write("3,1600,800\n");    file:write("1,1650,825\n");
      file:write("2,1700,850\n");   file:write("3,1750,875\n");   file:write("1,1800,900\n");    file:write("2,1850,925\n");
      file:write("3,1900,950\n");   file:write("1,1950,975\n");   file:write("2,2000,1000\n");   file:write("3,2050,1025\n");
      file:write("1,2100,1050\n");  file:write("2,2150,1075\n");  file:write("3,2200,1100\n");   file:write("1,2250,1125\n");
      file:write("2,2300,1150\n");  file:write("3,2350,1175\n");  file:write("1,2400,1200\n");   file:write("2,2450,1225\n")
    else
      file:write("1,04.5000,23.2500\n");  file:write("1,06.0000,03.3125\n");  file:write("1,06.5000,15.5000\n");  file:write("1,05.3750,19.5000\n");
      file:write("1,07.1875,17.5000\n");  file:write("1,06.1875,23.5000\n");  file:write("2,07.8750,03.8750\n");  file:write("3,09.8750,05.0000\n");
      file:write("1,11.7500,05.8750\n");  file:write("2,13.7500,06.6750\n");  file:write("3,15.7500,07.8750\n");  file:write("1,17.1250,08.8250\n");
      file:write("2,19.5000,09.5000\n");  file:write("3,21.1250,10.3750\n");  file:write("1,23.6250,11.1250\n");  file:write("2,25.5000,12.1250\n");
      file:write("3,27.6250,13.7500\n");  file:write("1,29.5000,14.7500\n");  file:write("2,31.4375,15.7500\n");  file:write("3,33.4375,16.7500\n");
      file:write("1,35.4375,17.7500\n");  file:write("2,37.4375,18.6250\n");  file:write("3,39.3750,19.6250\n");  file:write("1,41.3750,20.6250\n");
      file:write("2,43.3750,21.6250\n");  file:write("3,45.1875,22.6250\n");  file:write("1,47.2500,23.6250\n");  file:write("2,49.1875,24.6250\n");
      file:write("3,51.1250,25.5000\n");  file:write("1,53.1250,26.5000\n");  file:write("2,55.1250,27.5000\n");  file:write("3,57.1250,28.5000\n");
      file:write("1,59.1250,29.5000\n");  file:write("2,61.2500,30.5000\n");  file:write("3,62.9375,31.4375\n");  file:write("1,64.9375,32.4375\n");
      file:write("2,66.9375,33.4375\n");  file:write("3,68.8125,34.4375\n");  file:write("1,70.8750,35.3750\n");  file:write("2,72.9375,36.4375\n");
      file:write("3,74.8750,37.4375\n");  file:write("1,76.9375,38.3750\n");  file:write("2,78.7500,39.3750\n");  file:write("3,80.7500,40.3750\n");
      file:write("1,82.6250,41.3750\n");  file:write("2,84.6250,42.3750\n");  file:write("3,86.6250,43.3750\n");  file:write("1,88.5000,44.2500\n");
      file:write("2,90.6250,45.2500\n");  file:write("3,92.6250,46.2500\n");  file:write("1,94.4375,47.2500\n");  file:write("2,95.4375,48.2500\n")
    end -- if end
    file:close() -- closes the open file
  end -- if end
  return  true
end -- function end 

Text File Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

LengthOfFile

TopOfPage.png

Returns file line count

 function LengthOfFile(filename)
    Returns: number]]
    local len = 0
    if FileExists(filename) then
      local file = io.open(filename)
      if file then
      for _ in file:lines() do
        len = len + 1
      end
      file:close()
    end -- if end
    end
    return len
end -- function end 

NameValidater - Checks File Name for Valid Chars

TopOfPage.png

Returns file line count

 function NameValidater(FileName)
    local MyTrue = true
    local strlen = string.len(FileName)
    local strup = string.upper(FileName)
    local i = 1
    local y = ""
    while i <=  strlen do
      y = string.byte(string.sub(strup, i, i))
      if y == 32 then   --  Space
        MyTrue = false
        break
      elseif y == 45 then  -- Dash
        MyTrue = false
        break
      elseif y == 127 then  -- Delete
        MyTrue = false
        break
      elseif y == 126 then  -- Delete
        MyTrue = false
        break

       elseif y == 123 then  -- Open brace
        MyTrue = false
        break
      elseif y == 124 then  -- Pipe
        MyTrue = false
        break
      elseif y == 125 then  -- Close brace
        MyTrue = false
        break

      elseif  -- Illegal Filename Characters
      (y == 33) or -- !	Exclamation mark
      (y == 34) or -- "	Double Quotes
      (y == 35) or -- #	Hash
      (y == 36) or -- $	Dollar
      (y == 37) or -- %	Percent
      (y == 38) or -- &	Ampersand
      (y == 39) or -- '	Apostrophe
      (y == 42) or -- *	Asterisk
      (y == 43) or -- +	Plus
      (y == 44) or -- ,	Comma
      (y == 47) or -- /	Slash
      (y == 58) or -- :	Colon
      (y == 59) or -- ;	Semi-colon
      (y == 60) or -- <	Less than
      (y == 62) or -- >	Greater than
      (y == 63) or -- ?	Question mark
      (y == 64) or -- @	At
      (y == 92) or -- \	Backslash
      (y == 96) or -- `	Single Quotes
      (y == 123) or -- { Open brace
      (y == 124) or -- | Pipe
      (y == 125)    -- } Close brace
      then
        MyTrue = false
        break
      elseif (y <= 31) then -- Control Codes
        MyTrue = false
        break
      elseif (y >= 48) and (y <= 57) then -- Numbers
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      elseif (y >= 97) and (y <= 122) then -- Lowercase A to Z
        MyTrue = false
        break
      elseif (y >= 65) and (y <= 90) then -- Uppercase A to Z
        MyTrue = false
        break
      end -- if end
      i = i + 1  end -- while end;
    return MyTrue
end -- function end 

CopyFileFromTo

TopOfPage.png

Copy Old File to Newfile

 function CopyFileFromTo(OldFile, NewFile)
    if FileExists(NewFile) then
      DisplayMessageBox("File copy " .. File .. " failed. \n\nFile found at: " .. NewFile  .. "\n" )
      return false
    elseif not FileExists(OldFile) then
      DisplayMessageBox("File copy of " .. File .. " failed. \n\nFile not found at: " .. OldFile .. "\n" )
      return false
    else
      local fileR = io.open(OldFile)      -- reader file
      local fileW = io.open(NewFile, "w") -- writer file
      if fileR and fileW then  -- if both files are open
        for Line in fileR:lines() do
          fileW:write(Line .. "\n")
        end -- for end
      end
      if fileR then fileR:close() end
      if fileW then fileW:close() end
      return true
    end -- for end
end -- function end 

ValidateName

TopOfPage.png

Returns True if the file name is safe to use

 function ValidateName(FileName) 
  local MyTrue = true
  local strlen = string.len(FileName)
  local strup = string.upper(FileName)
  local i = 1
  local y = ""
  while i <=  strlen do
    y = string.byte(string.sub(strup, i, i))
    if y == 32 then -- Space
      MyTrue = true
    elseif y == 45 then -- hyphn
      MyTrue = true
    elseif (y >= 48) and (y <= 57) then -- numbers
      MyTrue = true
    elseif (y >= 65) and (y <= 90) then -- Uppercase
      MyTrue = true
    else
      MyTrue = false
      break
    end -- if end
    i = i + 1
  end -- while end
  return MyTrue
  end -- function end 

FileExists

TopOfPage.png

Returns True if file is found

 function FileExists(name)  
  -- call = ans = FileExists("sample.txt")
    local f=io.open(name,"r")
    if f~=nil then io.close(f) return true else io.close(f) return false end
  end -- function end 

FileAccess

TopOfPage.png

Returns true if file is available for update.

 function FileAccess(FileName) 
    if (not(os.rename(FileName, FileName))) then
      StatusMessage("Error", FileName, "The Gadget cannot access the ".. FileName ..
        " The OS has blocked write access. " ..
        "Verify the full path is correct and No application has the file open. ", "(1405)")
        return false
  else
    return true
  end -- if end
end -- function end 

IsDir

TopOfPage.png

Returns true if path is found

 function IsDir(path)                                  -- 
  local function exists(file)
    local ok, err, code = os.rename(file, file)
    if not ok then
      if code == 13 then
        return true
      end
    end
    return ok, err
  end
  return exists(path.."/")
end -- function end 

Sheetlabel

TopOfPage.png

Returns file line count of a txt (assic) file

 function Sheetlabel(Wpt, xTextHeight,  xThickness, xType, YY) -- Constructs sheet label
  local pt1Text = Point2D()
  local Pang    = 0.0
  local Tang    = 0.0
  if YY then
    pt1Text = Polar2D(Polar2D(Wpt, 90.0,  YY), 90.0,  6.0 * JimAndi.Cal)
    Pang = 270.0
    Tang = 0.0
  else
    if Material.Orientation == "V" then
      pt1Text = Polar2D(Wpt, 90.0, Milling.MaterialBlockWidth + (4.0 * JimAndi.Cal))
    else
      pt1Text = Polar2D(Wpt, 90.0,  Milling.MaterialBlockHeight + (4.0 * JimAndi.Cal))
    end
    Pang = 270.0
    Tang = 0.0
  end
  DrawWriter(Project.ProgramName, pt1Text, Milling.TextHeight * 3.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 3.35)
  DrawWriter("Cabinet ID: " .. Project.DrawerID, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
  DrawWriter("Cabinet Name: " .. Project.CabinetName, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  pt1Text = Polar2D(pt1Text, Pang, Milling.TextHeight * 2.75)
  if xThickness then
    DrawWriter("Material: " .. xThickness .. " " .. xType, pt1Text, JimAndi.TextHeight * 2.0, JimAndi.LNDrawNotes, Tang)
  end -- if end
end -- function end 

DiskRights

TopOfPage.png

Returns true if you have write access to path.

 function DiskRights(path)                             -- 
  local xx = io.open(path, "w")
  if xx == nil then
      io.close()
      return false
  else
      xx:close()
      return true
  end
end -- function end 

Geometry Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

SheetNew

TopOfPage.png

Adds a new sheet to the drawing

 function SheetNew()                                     -- Adds a new sheet to the drawing
  if GetVersion() >= 10.5 then then
    local layer_manager = Milling.job.LayerManager
    -- get current sheet count - note sheet 0 the default sheet counts as one sheet
    local orig_num_sheets = layer_manager.NumberOfSheets
    -- get current active sheet index
    local orig_active_sheet_index = layer_manager.ActiveSheetIndex
    -- set active sheet to last sheet
    local num_sheets = layer_manager.NumberOfSheets
    layer_manager.ActiveSheetIndex = num_sheets - 1
    -- Add a new sheet
    layer_manager:AddNewSheet()
    -- set active sheet to last sheet we just added
    num_sheets = layer_manager.NumberOfSheets
    layer_manager.ActiveSheetIndex = num_sheets - 1
    Milling.job:Refresh2DView()
  end -- if end
  return true
end   

GetDiameterAndCentre

TopOfPage.png
function GetDiameterAndCentre(cadcontour, point2d)
  local contour = cadcontour:GetContour()
  local arc = contour:GetFirstSpan()
  local point3d = Point3D();
  arc = CastSpanToArcSpan(arc)
  local diameter = arc:RadiusAndCentre(point3d) * 2.0
  point2d = Point2D(point3d.x, point3d.y)
  -- MessageBox("Diameter = " .. diameter)
  return diameter, point2d
end

IsCircle

TopOfPage.png
function IsCircle(cadcontour)                           -- Returns True if conture is a circle
  local contour = cadcontour:GetContour()
  -- Does it consist only of arcs?
  if contour.ContainsBeziers then
    return false
  end
  if not contour.ContainsArcs then
    return false
  end
  -- Does is contain 4 contours?
  if contour.Count ~= 4 then
    return false
  end
  -- Check the arcs end and initial points make a square.
  local arcs = {}
  local count = 1;
  local pos = contour:GetHeadPosition()
  local object
  while pos ~= nil do
    object, pos = contour:GetNext(pos)
    arcs[count] = object
    count = count + 1
  end
  local x_1 =(arcs[1]).StartPoint2D.x
  local y_1 =(arcs[1]).StartPoint2D.y
  local x_3 =(arcs[3]).StartPoint2D.x
  local y_3 =(arcs[3]).StartPoint2D.y
  local x_2 =(arcs[2]).StartPoint2D.x
  local y_2 =(arcs[2]).StartPoint2D.y
  local x_4 =(arcs[4]).StartPoint2D.x
  local y_4 =(arcs[4]).StartPoint2D.y
  local horizontal_distance = (x_1 - x_3)*(x_1 - x_3) + (y_1 - y_3)*(y_1 - y_3)
  local vertical_distance = (x_4 - x_2)*(x_4 - x_2) + (y_2 - y_4)*(y_2 - y_4)
  if math.abs(horizontal_distance - vertical_distance) > 0.04 then
    return false
  end
  -- Check the bulge factor is 90
  local bulge = 0;
  for _, arc_span in ipairs(arcs) do
    bulge = CastSpanToArcSpan(arc_span).Bulge;
    if math.abs(math.abs(bulge)  - g_bulge90) > 0.04 then
      return false
    end
  end
  return true
end

SheetSet

TopOfPage.png
function SheetSet(Name)                    -- Move focus to a named sheet
  local job = VectricJob()
  local sheet_manager = job.SheetManager
  local sheet_ids = sheet_manager:GetSheetIds()
  for id in sheet_ids do
    if(sheet_manager:GetSheetName(id) == Name) then
    sheet_manager.ActiveSheetId = id
    end
  end
end

SheetNextSize

TopOfPage.png
function SheetNextSize(X, Y)               -- Make New Sheet to size (x, y)
  if X == nil then
    X = Milling.MaterialBlockWidth
  else
    X = X + (2 * Milling.Cal)
  end
  if Y == nil then
    Y = Milling.MaterialBlockHeight
  else
    Y = Y + (2 * Milling.Cal)
  end
  Milling.Sheet = Milling.Sheet + 1
  local sheet_manager = Milling.job.SheetManager
  local sheet_ids = sheet_manager:GetSheetIds()
  for id in sheet_ids do
    if(sheet_manager:GetSheetName(id) == "Sheet 1") then
     sheet_manager:CreateSheets(1, id, Box2D(Point2D(0, 0), Point2D(X, Y)))
    end
  end
  SheetSet("Sheet " .. tostring(Milling.Sheet))
  return true
end

GetPolarAngle

TopOfPage.png
function GetPolarAngle(Start, Corner, End)           -- Returns the Polar Angle
  local function GetPolarDirection(point1, point2)   
    local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
    if point1.X < point2.X then
      if point1.Y < point2.Y then
        ang = ang + 0.0
      else
        ang = 360.0 - ang
      end -- if end
    else
      if point1.Y < point2.Y then
        ang = 180.0 - ang
      else
        ang = ang + 180.0
      end -- if end
    end -- if end
    if ang >=360 then
      ang = ang -360.0
    end -- if end
    return ang
  end -- function end
  return  math.abs(GetPolarDirection(Corner, Start) - GetPolarDirection(Corner, End))
end -- function end

GetOrientation

TopOfPage.png
function GetOrientation(point1, point2)                 -- Orientation of left, right, up or down
  if DecimalPlaces(point1.X,8) == DecimalPlaces(point2.X,8) then
    if point1.Y < point2.Y then
      return 90.0
    else
      return 270.0
    end
  elseif DecimalPlaces(point1.Y,8) == DecimalPlaces(point2.Y,8) then
    if point1.X < point2.X then
      return 0.0
    else
      return 180.0
    end
  else
    return nil
  end
end -- function end

GetPolarDirection

TopOfPage.png
function GetPolarDirection(point1, point2)              -- Retuens and amgle from two points
  local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
  if point1.X < point2.X then
    if point1.Y < point2.Y then
      ang = ang + 0.0
    else
      ang = 360.0 - ang
    end -- if end
  else
    if point1.Y < point2.Y then
      ang = 180.0 - ang
    else
      ang = ang + 180.0
    end -- if end
  end -- if end
  if ang >=360 then
    ang = ang -360.0
  end -- if end
  return ang
end -- function end

CenterArc

TopOfPage.png
function CenterArc(A, B, RadiusD)                       -- Returns 2DPoint from Arc point and Radius
  local radius = ((tonumber(RadiusD) or 0) * g_var.scl)
  local horda = (A - B).Length
  if math.abs(radius) < (horda / 2) and radius ~= 0 then
--D("Too small radius " .. radius .. "\nreplaced by the smallest possible " .. (horda / 2))
    radius = (horda / 2)
  end
  return Point2D(((A.x + B.x) / 2 + (B.y - A.y) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda), ((A.y + B.y) / 2 + (A.x - B.x) * math.sqrt(math.abs(radius) ^ 2 - (horda / 2) ^ 2) / horda))
end -- function end

Polar2D

TopOfPage.png

The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance. Returns 2DPoint from Known Point, Angle direction, and Projected distance.

function Polar2D(pt, ang, dis)                        
-- The Polar2D function will calculate a new point in space based on a Point of reference, Angle of direction, and Projected distance.
-- ::''Returns a 2Dpoint(x, y)''
  return Point2D((pt.X + dis * math.cos(math.rad(ang))), (pt.Y + dis * math.sin(math.rad(ang))))
end -- End Function

GetDistance

TopOfPage.png

Returns Double from two Points

 function GetDistance(objA, objB)                        -- Returns Double from two Points
  local xDist = objB.x - objA.x
  local yDist = objB.y - objA.y
  return math.sqrt((xDist ^ 2) + (yDist ^ 2))
end -- function end

GetAngle

TopOfPage.png
  -- ===========================================================]]
  function GetAngle(point1, point2)
 local ang = math.abs(math.deg(math.atan((point2.Y - point1.Y) / (point2.X - point1.X))))
 if point1.X < point2.X then
   if point1.Y < point2.Y then
     ang = ang + 0.0
   else
     ang = 360.0 - ang
   end -- if end
 else
   if point1.Y < point2.Y then
     ang = 180.0 - ang
   else
     ang = ang + 180.0
   end -- if end
 end -- if end
 if ang >=360.0 then
   ang = ang -360.0
 end -- if end
 return ang

end -- function end</nowiki>


Arc2Bulge

TopOfPage.png
  -- ===========================================================]]
  function Arc2Bulge(p1, p2, Rad)                         -- Returns the Bulge factor for an arc
 local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
 local seg = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
 local bulge = (2 * seg) / chord
 return bulge

end -- function end</nowiki>


TrigIt

Calculates Right Angle

TopOfPage.png
function TrigIt()                                       -- Calculates Right Angle
-- ==Trig Function==
-- VECTRIC LUA SCRIPT
-- =====================================================]]
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- They are provided 'as-is', without any express or implied warranty, and you
--   make use of them entirely at your own risk.
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages
--   arising from their use.
-- Permission is granted to anyone to use this software for any purpose,
-- including commercial applications, and to alter it and redistribute it freely,
-- subject to the following restrictions:
-- 1. The origin of this software must not be misrepresented; you must not
--    claim that you wrote the original software.
-- 2. If you use this software in a product, an acknowledgement in the product
--    documentation would be appreciated but is not required.
-- 3. Altered source versions must be plainly marked as such, and must not be
--    misrepresented as being the original software.
-- 4. This notice may not be removed or altered from any source distribution.
--
-- Right Triangle TrigFunction is written by Jim Anderson of Houston Texas 2020
-- =====================================================]]
-- Code Debugger
-- require("mobdebug").start()
-- =====================================================]]
-- Global Variables --
    Trig = {}
-- =====================================================]]
  function TrigTest() -- Test the All Right Angle
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 1: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 2: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 3: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 4: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  4.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 5: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj = * " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  36.86897645844
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  5.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 6: \n" ..
    " Trig.A  = * " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp = * " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
    " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
    )
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  3.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  9.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test 7: \n" ..
    " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
    " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
    " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
    " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
    " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
    " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
    " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
    " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
    " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
    " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
    )
    -- =====================================================]]
    TrigClear()
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  9.0
    Trig.Area =  0.0
    Trig.OutRadius =  0.0
    Trig.InRadius =  0.0
    Trig.Parameter =  0.0
    TrigIt()
    DisplayMessageBox("Test Error: \n" ..
      " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
      " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
      " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
      " Trig.Opp = * " .. tostring(Trig.Opp) .. " \n" ..
      " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
      " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
      " Trig.Slope = * " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
      " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
      " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
      " Trig.Circumscribing =  " .. tostring(Trig.Circumscribing) .. " \n" ..
      " Trig.Inscribing =  " .. tostring(Trig.Inscribing) .. " \n"
    )
    return true
  end -- function end --
-- =====================================================]]
  function TrigClear()   -- Clears and resets Trig Table
    Trig.A  =  0.0
    Trig.B  =  0.0
    Trig.C  = 90.0
    Trig.Opp =  0.0  -- Rise  or (B2C)
    Trig.Adj =  0.0  -- Base  or (A2C)
    Trig.Hyp =  0.0  -- Slope or (A2B)
    Trig.Slope =  0.0
    return true
  end -- function end
-- =====================================================]]
      local function BSA()
        Trig.B  = (Trig.C - Trig.A)
        Trig.Slope = math.tan(math.rad(Trig.A)) * 12.0
        Trig.Area =  (Trig.Opp * Trig.Adj) * 0.5
        Trig.Inscribing = ((Trig.Opp + Trig.Adj) - Trig.Hyp) * 0.5
        Trig.Circumscribing =  Trig.Hyp * 0.5
        Trig.Parameter = Trig.Opp + Trig.Adj + Trig.Hyp
      end
      if Trig.A == 0.0 and Trig.B > 0.0 and Trig.Slope == 0.0 then
        Trig.A = Trig.C - Trig.B
      elseif Trig.A == 0.0 and Trig.B == 0.0 and Trig.Slope > 0.0 then
        Trig.A = math.deg(math.atan(Trig.Slope / 12.0))
      end -- if end
-- test 4
      if (Trig.A > 0.0) and (Trig.Opp >  0.0) then -- A and Rise or (B2C)
        Trig.Adj =  Trig.Opp / (math.tan(math.rad(Trig.A)))
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        BSA()
        return true
      -- test 6
      elseif (Trig.A > 0.0) and (Trig.Hyp >  0.0)  then -- A and Slope or (A2B)
        Trig.Adj = math.cos(math.rad(Trig.A)) * Trig.Hyp
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
        BSA()
        return true
      -- test 5
      elseif (Trig.A > 0.0) and (Trig.Adj >  0.0)  then -- A and Base or (A2C)
        Trig.Opp = math.tan(math.rad(Trig.A)) * Trig.Adj
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        BSA()
        return true
        -- test 1
      elseif (Trig.Opp >  0.0) and (Trig.Adj >  0.0) then -- Rise and Base
        Trig.Hyp = math.sqrt((Trig.Opp * Trig.Opp ) + ( Trig.Adj * Trig.Adj))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      elseif (Trig.Adj >  0.0) and (Trig.Hyp >  0.0) then -- Rise and Slope
-- test 2
        Trig.Opp = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Adj * Trig.Adj))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      elseif (Trig.Opp >  0.0) and (Trig.Hyp >  0.0) then -- Base and Slope
-- test 3
        Trig.Adj = math.sqrt((Trig.Hyp * Trig.Hyp ) - ( Trig.Opp * Trig.Opp))
        Trig.A  = math.deg(math.atan(Trig.Opp / Trig.Adj))
        BSA()
        return true
      else
        DisplayMessageBox("Error: Trig Values did not match requirements: \n" ..
                          " Trig.A  =  " .. tostring(Trig.A) .. " \n" ..
                          " Trig.B  =  " .. tostring(Trig.B) .. " \n" ..
                          " Trig.C  =  " .. tostring(Trig.C) .. " \n" ..
                          " Trig.Opp =  " .. tostring(Trig.Opp) .. " \n" ..
                          " Trig.Adj =  " .. tostring(Trig.Adj) .. " \n" ..
                          " Trig.Hyp =  " .. tostring(Trig.Hyp) .. " \n" ..
                          " Trig.Slope =  " .. tostring(Trig.Slope) .. " on 12 inch \n" ..
                          " Trig.Area =  " .. tostring(Trig.Area) .. " \n" ..
                          " Trig.Parameter =  " .. tostring(Trig.Parameter) .. " \n" ..
                          " Trig.OutRadius =  " .. tostring(Trig.OutRadius) .. " \n" ..
                          " Trig.InRadius =  " .. tostring(Trig.InRadius) .. " \n"
                          )
        return false
      end
    end -- function end
-- =====================================================]]
end -- Geometry Tools end


INI File Tools

Back.jpg

These functions manipulate the INI files for the storage and retrieval of data.


INI_NameStrip

TopOfPage.png

Convert string to the correct data type.

Local Words = NameStrip("KPSDFKSPSK - 34598923", "-") -- returns "KPSDFKSPSK"


Source Code

 function INI_NameStrip(str, var)
    if "" == str then
      DisplayMessageBox("Error in string")
    else
      if string.find(str, var) then
        local j = assert(string.find(str, var) - 1)
        return All_Trim(string.sub(str, 1, j))
      else
        return str
      end
    end
  end -- function end 

INI_HeadStrip

TopOfPage.png

Convert string to the correct data type.

  function INI_HeadStrip(str, var)                            -- convert string to the correct data type
-- Local Words = HeadStrip("LastName23 = Smith", "=") -- returns "Smith"
    if "" == str then
      DisplayMessageBox("Error in string")
    else
      if string.find(str, var) then
        local j = assert(string.find(str, var) + 1)
        return All_Trim(string.sub(str, j))
      else
        return str
      end
    end
  end -- function end 

INI_AreDupGroups

TopOfPage.png

Checks if there are duplicate groups.

function INI_AreDupGroups(xPath, xFile)
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
      CleanNames = RemoveDups(GroupNames)
    if TableLength(GroupNames) == TableLength(CleanNames)then
      return true
    else
      return false
    end
  end -- function end 

INI_FixDupGroups

TopOfPage.png

Find and fix duplicate groups

 function INI_FixDupGroups(xPath, xFile)
    local GroupNames = {}
    local CleanNames = {}
    local DupGroups  = {}
      GroupNames = INI_ReadGroups(xFile, aName)
    return true
  end -- function end

INI_DeleteGroup

TopOfPage.png

Deletes only the first find of xGroup

 function INI_DeleteGroup(xPath, xFile, xGroup)
-- Deletes old ini (.bak) file
-- Copy's the .ini to a backup (.bak) new file
-- Reads the new backup file and writes a new file to the xGroup value
-- Stops Writing lines until next Group is found
-- Writes to end of file
-- Call: DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
    if FileExists(OfileName) then
      os.remove(OfileName)
    end
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
--    os.rename(NfileName, OfileName) -- makes backup copy file
    if CopyFileFromTo(NfileName, OfileName) then
      local fileR   = io.open(OfileName)
      local fileW   = io.open(NfileName,  "w")
      local groups  = false
      local writit  = true
      local MyTxt   = ""
      local txt = ""
      if fileR and fileW then  -- files are open
        for Line in fileR:lines() do  -- read each line of the backup file
          txt = Line  -- copy line from file to txt
          if All_Trim(Line) == "[" .. All_Trim(xGroup) ..  MyTxt .. "]" then  -- look for a match
            groups = true
            txt = ""
          end -- if end
          if groups and MyTxt == "" then  -- if group is true turn off the write function
            writit = false
            if "[" == string.sub(All_Trim(txt), 1, 1) then  -- turns write function on if next group is found
              groups = false
              xGroup = "-"
              writit = true
              MyTxt   = "--"
            else
              writit = false
            end -- if end
          end -- if end
          if writit then
            fileW:write(txt .. "\n")
            txt = ""
          end -- if end
        end -- for end
        os.remove(OfileName)
      end -- if end
      if fileR then fileR:close() end
      if fileW then fileW:close() end
    end
    return true
  end -- function end

INI_RenameGroup

TopOfPage.png

Renames a group

 function INI_RenameGroup(xOldGroup, xNewGroup)
--Deletes old ini Hardware.bak file
--Copys the ini file to a backup copy file
--Reads the backup file and writes a new ini file to the xGroup
--Writes new file with new group  to the new ini file
  local NfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".ini"
  local OfileName = Project.AppPath .. "\\" .. "EasyDrawerHardware" .. ".bak"
  os.remove(OfileName)
  CopyFileFromTo(NfileName, OfileName) -- makes backup file
  local fileR = io.open(OfileName)
  local fileW = io.open(NfileName, "w")
  if fileR and fileW then
    local groups = false
    local txt = ""
    for Line in fileR:lines() do
      if All_Trim(Line) == "[" .. All_Trim(xOldGroup) .. txt .. "]" then -- Group
        fileW:write(xNewGroup .. "\n")
        txt = "-"
      else
        fileW:write(Line .. "\n")
      end -- if end
    end -- for end
    fileR:close()
    fileW:close()
    os.remove(OfileName)
  end -- if end
  return true
end -- function end

INI_DeleteItem

TopOfPage.png

Deleates a group

 function INI_DeleteItem(xPath, xFile, xGroup, xItem)
-- Deletes old ini (.bak) file
-- Copys the .ini to a backup (.bak) new file
-- Reads the new backup file and writes a new file to the xGroup value
-- Stops Writing lines until next Group is found
-- Writes to end of file
-- DeleteGroup("C:\\Users\\James\\OneDrive\\Documents\\DoorGadget\\Clients\\Marcin", "ProjectList", "Boston")
  local NfileName = xPath .. "\\" .. xFile .. ".ini"
  local OfileName = xPath .. "\\" .. xFile .. ".bak"
  os.remove(OfileName)
  CopyFileFromTo(NfileName, OfileName) -- makes backup copy file
  local fileR = io.open(OfileName)
  local fileW = io.open(NfileName,  "w")
  if fileR and fileW then
    local groups = false
    local writit = true
    local txt = ""
    for Line in fileR:lines() do
      txt = Line
      if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then
        groups = true
      end -- if end
      if groups then
  -- ===================
        if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
          writit = false
          groups = false
        end -- if end
      end -- if end
  -- ===================
      if writit then
        fileW:write(txt .. "\n")
      end -- if end
      writit = true
    end -- for end
    os.remove(OfileName)
    fileR:close()
    fileW:close()
  end -- if end
  return true
end -- function end

INI_ValidateGroup

TopOfPage.png

Reads INI file and returns true if group is found

 function INI_ValidateGroup(xFile, xGroup)
  -- Reads INI file and returns true if the group is found
  local fileR = io.open(xFile)
  local group = false
  for Line in fileR:lines() do
    if string.upper(All_Trim(Line)) == "[" .. string.upper(All_Trim(xGroup)) .. "]" then  -- Group
    group = true
    break
    end -- if end
  end -- for end
  fileR:close()
  return group
end -- function end

INI_ValidateItem

TopOfPage.png

Reads INI file and returns true if group and item is found

 function INI_ValidateItem(xFile, xGroup, xItem)
    local fileR = io.open(xFile)
    if fileR then
      local group = false
      local item = false
      local ItemLen = string.len(xItem)
      for Line in fileR:lines() do
        if All_Trim(Line) == "[" ..  string.upper(All_Trim(xGroup)) .. "]" then  -- Group
        group = true
        end -- if end
        if group then
          if string.upper(xItem) == string.upper(string.sub(Line, 1, string.len(xItem)))  then  -- Item
            item = true
            break
          end -- if end
        end -- if end
      end -- for end
      fileR:close()
    end -- if end
    return group
  end -- function end

INI_StrValue

TopOfPage.png

Reads INI file and returns string value

 function INI_StrValue(str, ty)
-- Convert string to the correct data type
    if nil == str then
      DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
    else
      if "" == All_Trim(str) then
        DisplayMessageBox("Error in Ini file - looking for a " .. ty .. " value")
      else
        local j = (string.find(str, "=") + 1)
        if ty == "D" then -- Double
          return tonumber(string.sub(str, j))
        end -- if end
        if ty == "I" then  -- Intiger
          return math.floor(tonumber(string.sub(str, j)))
        end -- if end
        if ty == "S" then  -- String
          return All_Trim(string.sub(str, j))
        end -- if end
        if ty == "B" then  -- Bool
          if "TRUE" == All_Trim(string.sub(str, j)) then
            return true
          else
            return false
          end -- if end
        end -- if end
      end -- if end
    end -- if end
    return nil
  end -- function end

INI_GetValue

TopOfPage.png

Reads INI file and returns value

 function INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)
    -- ==INI_GetValue(xPath, FileName, GroupName, ItemName, ValueType)==
    -- Returns a value from a file, group, and Item
    -- Usage: XX.YY = GetIniValue("C:/temp", "ScrewDia", "[Screws]", "Diameter", "D")
    local filenameR = xPath .. "\\" .. FileName .. ".ini"
    local FL = LengthOfFile(filenameR)
    local file = io.open(filenameR, "r")
    local dat = "."
    local ItemNameLen = string.len(ItemName)
    if file then
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if dat == "[" .. string.upper(GroupName) .. "]" then
          break
        else
          FL = FL - 1
        end -- if end
      end -- while end
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if string.upper(ItemName) == string.sub(dat, 1, ItemNameLen)  then
          break
        else
          FL = FL - 1
          if FL == 0 then
            dat = "Error - item not  found"
            break
          end -- if end
        end -- if end
      end -- while end
      file:close()-- closes the open file
    end -- if end
    local XX = StrIniValue(dat, ValueType)
    return XX
  end -- function end

INI_GetIDFor

TopOfPage.png

Reads INI file and returns ID for a value

 function INI_GetIDFor(xPath, FileName, GroupName, ItemValue)
    -- == INI_GetIDFor(xPath, FileName, GroupName, ItemValue) ==
    -- Returns a ItemID from a file, group, and ItemValue
    -- Usage: XX.YY = INI_GetIDFor("C:/temp", "UserList", "[Users]", "Anderson")
    -- returns: "UserLastName22"
    local filenameR = xPath .. "\\" .. FileName .. ".ini"
    local FL = LengthOfFile(filenameR)
    local file = io.open(filenameR, "r")
    if file then
      local dat = "."
      local ItemValueLen = string.len(ItemValue)
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if dat == "[" .. string.upper(GroupName) .. "]" then
          break
        else
          FL = FL - 1
        end -- if end
      end -- while end
      while (FL >= 1) do
        dat = string.upper(All_Trim(file:read()))
        if string.upper(ItemValue) == HeadStrip(dat, "=")  then
          break
        else
          FL = FL - 1
          if FL == 0 then
            dat = "Error - item not  found"
            break
          end -- if end
        end -- if end
      end -- while end
      file:close()-- closes the open file
    end -- if end
    local XX = NameStrip(dat, "=")
    return XX
  end -- function end

INI_ReadGroups

TopOfPage.png

Reads INI file group and returns true if found

 function INI_ReadGroups(xFile, aName)
  --[[Reads INI and returns a list contain the [Headers] as Array
  IniFile = {} Global variables
  xPath = script_path
  ]]
    local filename = xFile
    local file = io.open(filename, "r")
    if file then
      local fLength = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (fLength >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (aName, string.sub(dat, 2, -2))
        end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          file:close()-- closes the open file
          return true
        end
        fLength = fLength - 1
      end -- while
    end -- if
     if file then file:close() end
    return true
  end -- function end

INI_ProjectHeaderReader

TopOfPage.png

Reads INI file group and returns the INI Header values of a ini file and uploads to "IniFile" Array

 function INI_ProjectHeaderReader(xPath)
    local filename = xPath .. "/CabinetProjects.ini"
    local file = io.open(filename, "r")
    if file then
      local Cabing = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (Cabing >= 1) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (Projects, string.sub(dat, 2, -2))
        end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          return true
        end
        Cabing = Cabing - 1
      end
      file:close()
    end
    return true
  end -- function end

INI_AddNewProject

TopOfPage.png

Appends a New Project to CabinetProjectQuestion.ini

 function INI_AddNewProject(xPath, xGroup)
    local filename = xPath .. "/ProjectList.ini"
    local file = io.open(filename, "a")
    if file then
      file:write("[" .. All_Trim(xGroup) .. "] \n")
      file:write("load_date = " .. StartDate(true) .. " \n")
      file:write("#====================================== \n")
      file:close()-- closes the open file
    end
    return true
  end -- function end

INI_StdHeaderReader

TopOfPage.png

Gets the INI Header values of a ini file and uploads to "IniFile" Array

 function INI_StdHeaderReader(xPath, Fname)
    local filename = xPath .. "\\" .. Fname .. ".ini"
    local file = io.open(filename, "r")
    if file then
      local WallMilling = (LengthOfFile(filename) - 1)
      local dat = All_Trim(file:read())
      while (WallMilling >= 0) do
        if "[" == string.sub(dat, 1, 1) then
          table.insert (IniFile, string.sub(dat, 2, -2))
        end -- if end
        dat = file:read()
        if dat then
          dat = All_Trim(dat)
        else
          return true
        end -- if end
        WallMilling = WallMilling - 1
      end -- while end
      file:close()
    end
    return true
  end -- function end

INI_ReadProjectinfo

TopOfPage.png

Reads an ini files group and sets the table.names

 function INI_ReadProjectinfo(Table, xPath, xGroup, xFile)
    Table.ProjectContactEmail       = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactEmail", "S")
    Table.ProjectContactName        = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactName", "S")
    Table.ProjectContactPhoneNumber = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectContactPhoneNumber", "S")
    Table.ProjectName               = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectName", "S")
    Table.ProjectPath               = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.ProjectPath", "S")
    Table.StartDate                 = GetIniValue(xPath, xFile, xGroup, "ProjectQuestion.StartDate", "S")
    return true
  end -- function end

INI_UpdateItem

TopOfPage.png

Deletes old ini (.bak) file

Copys the .ini to a backup (.bak) new file

Reads the new backup file and writes a new file to the xGroup

Writes new xValue for the for the xItem

Reads and writes a new file to end of file

 function INI_UpdateItem(xPath, xFile, xGroup, xItem, xValue)
    local NfileName = xPath .. "\\" .. xFile .. ".ini"
    local OfileName = xPath .. "\\" .. xFile .. ".bak"
    os.remove(OfileName)
    if CopyFileFromTo(NfileName, OfileName) then-- makes backup file
      local fileR = io.open(OfileName)
      local fileW = io.open(NfileName,  "w")
      if fileR and fileW then
        local groups = false
        local txt = ""
        for Line in fileR:lines() do
          txt = Line
          if All_Trim(Line) == "[" .. All_Trim(xGroup) .. "]" then -- Group
            groups = true
          end -- if end
          if xItem == string.sub(Line, 1, string.len(xItem))  then  -- Item
            if groups then
              txt = xItem .. " = " .. xValue
              groups = false
            end -- if end
          end -- if end
          fileW:write(txt .. "\n")
          txt = ""
        end -- for end
        os.remove(OfileName)
        fileR:close()
        fileW:close()
      end
    end
    return true
  end -- function end

INI_ReadProject

TopOfPage.png

Reads the ini file for project data

 function INI_ReadProject(xPath, xFile, xGroup)
  -- Milling = {}
    Milling.LayerNameBackPocket          = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameBackPocket", "S")
    Milling.LayerNameTopBottomCenterDado = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameTopBottomCenterDado", "S")
    Milling.LayerNameDrawNotes           = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawNotes", "S")
    Milling.LayerNameDrawFaceFrame       = GetIniValue(xPath, xFile, xGroup, "Milling.LayerNameDrawFaceFrame", "S")
    Milling.BackPocketDepthWall          = GetIniValue(xPath, xFile, xGroup, "Milling.BackPocketDepthWall", "N")
    Milling.BlindDadoSetbackWall         = GetIniValue(xPath, xFile, xGroup, "Milling.BlindDadoSetbackWall", "N")
    Milling.CabDepthWall                 = GetIniValue(xPath, xFile, xGroup, "Milling.CabDepthWall", "N")
    return true
  end -- function end

INI_TestDeleteDups

TopOfPage.png

Reads the ini file for dups and deletes

 function INI_TestDeleteDups()
    --[[ Requires 3 global variables
    clean  = {}
    dups   = {}
    Names  = {}
    ]]
    local myPath = "C:\\Users\\CNC\\Documents\\test"
    local myName = "Tester"
    local myfile = "C:\\Users\\CNC\\Documents\\test\\Tester.ini"
    INI_ReadGroups(myfile, Names)
    FindDups(Names, dups, clean)
    for i,v in ipairs(dups) do
      INI_DeleteGroup(myPath, myName, v)
    end
    return true
 end -- function end

Data Import Tools

Back.jpg

This object is used to import data to a gadget.

Read_CSV

Reads a CSV file based on header and format (Requires modifications per usage)

 function Read_CSV(xFile, Header)
  --Read_CSV(Door.CSVFile, true)
  local fileR = io.open(xFile)
  local xLine = ""
  local result = {}
  if fileR then
    for Line in fileR:lines() do
      xLine = Line
      if Header then
        Header = false
      else
        xLine = All_Trim(Line)
        for match in (xLine..","):gmatch("(.-)"..",") do
          table.insert(result, match)
        end -- for end
        Door.Count     = tonumber(result[1])
        Door.Height    = tonumber(result[2])
        Door.Width     = tonumber(result[3])

        result = {}
        while Door.Count > 0 do
          if      Door.Style == StyleA.Name then
            DoorStyleA()
          elseif  Door.Style == StyleB.Name then
            DoorStyleB()
          elseif  Door.Style == StyleC.Name then
            DoorStyleC()
          elseif  Door.Style == StyleE.Name then
            DoorStyleE()
          elseif  Door.Style == StyleF.Name then
            DoorStyleF()
          elseif  Door.Style == StyleG.Name then
            DoorStyleG()
          else
            DisplayMessageBox("No Style Select!")
          end --if end
          Door.Count =  Door.Count - 1
        end -- for end
      end --if end
      Door.Record = Door.Record + 1
      MyProgressBar:SetPercentProgress(ProgressAmount(Door.Record))
    end --for end
  end --if end
  return true
end -- function end 

Job Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

function ValidJob()
  -- A better error message
    local job = VectricJob()
    if not job.Exists then
      DisplayMessageBox("Error: Cannot run Gadget, no drawing found \n" ..
                        "Please create a new file (drawing) and \n" ..
                        "specify the material dimensions \n"
      )
      return false
    else
      return true
    end  -- if end
  end -- ValidJob end


MoveSetectedVectors

TopOfPage.png
function MoveSetectedVectors(job, NewBasePoint)
    local Selection = job.Selection
    if Selection.IsEmpty then
      MessageBox("LayoutImportedVectors: No vectors selected!")
      return false
    end
    local MySelection = Selection:GetBoundingBox();
    if not NewBasePoint then
      NewBasePoint = Point2D(0,0)
    end
    local MyNewLocatioin = BasePoint - MySelection.BLC
    local Txform = TranslationMatrix2D(MyNewLocatioin)
    Selection:Transform(Txform)
    return true
  end 

FixPath

 function FixPath(path)                                -- Lua Returns a fixed path
    return path:gsub("%\\", "/")
  end -- function end

----

  function FixPath(myPath) {                            -- JavaScript Tool Returns a fixed path
    /* myPath  = "C:\\User\\Bob\\Home\\Drawings"; */
    /* NewPath = "C:/User/Bob/Home/Drawings"; */
    var NewPath = "";
    var myLetter = "";
    var CheckPathLen = myPath.length;
    for (let i = 0; i < myPath.length; i++) {
      myLetter = myPath.charAt(i)
      if myLetter.charCodeAt(0) == 92 {
        NewPath = NewPath + "/";
      } else {
        NewPath = NewPath + myLetter;
      }
    }
    return NewPath;
  }

RotateSetectedVectors

 function RotateSetectedVectors(job, NewBasePoint, NewAngle)
    local Selection = job.Selection
    if not NewBasePoint then
      NewBasePoint = Point2D(0,0)
    end -- if end
    if not NewAngle then
      NewAngle = 0.0
    end -- if end
    if Selection.IsEmpty then
      MessageBox("Error: Rotation function: No vectors selected!")
      return false
    end -- if end
    local MySelection = Selection:GetBoundingBox();
    local MyNewLocatioin = BasePoint - MySelection.BLC
    local Txform = RotationMatrix2D(NewBasePoint, NewAngle)
    Selection:Transform(Txform)
    return true
  end 

GetUnits

TopOfPage.png
function GetUnits(UTable)                               -- returns Drawing Units data
    local mtl_block = MaterialBlock()
    if mtl_block.InMM then
      UTable.Units  = "Drawing Units: mm"
      UTable.Unit = true
      UTable.UnitCheck = {"metric", "kilometer", "kilometers", "kh", "meter", "meters", "m", "decimeter", "decimeters", "dm", "centimeter", "centimeters", "cm", "millimeter", "millimeters", "mm"}
      UTable.Cal = 25.4
    else
      UTable.Units  = "Drawing Units: inches"
      UTable.Unit = false
      UTable.UnitCheck = {"imperial", "miles", "mile", "mi", "yards", "yard", "yd", "feet", "foot", "ft", "inches", "inch", "in", "fractions", "fraction"}
      UTable.Cal = 1.0
    end
    return true
  end -- end function

CheckTheUnits

TopOfPage.png
function CheckTheUnits(UTable, Value)                     -- Checks if the unit of messure in of drawing units
  local goodtogo = false
  for i=1, #UTable.UnitCheck  do
    if string.upper(Value) == string.upper(UTable.UnitCheck[i]) then
      goodtogo = true
      break
    end -- if end
  end -- for end
  if goodtogo then
    return true
  else
    return false
  end -- if end
end -- function end

GetMatlBlk

TopOfPage.png
function GetMatlBlk(Table)
    local mtl_block = MaterialBlock()
    if mtl_block.InMM then
      Table.Units = "Drawing Units: mm"
      Table.Unit = true
    else
      Table.Units = "Drawing Units: inches"
      Table.Unit = false
    end
    if mtl_block.Width> mtl_block.Height then
      Table.MaterialThickness = mtl_block.Height
      Table.MaterialLength = mtl_block.Width
      Table.Orantation = "H"
    else
      Table.MaterialThickness = mtl_block.Width
      Table.MaterialLength = mtl_block.Height
      Table.Orantation = "V"
    end
    Table.FrontThickness = Dovetail.MaterialThickness
    Table.SideThickness = Dovetail.MaterialThickness
    if mtl_block.Height == mtl_block.Width then
        MessageBox("Error! Material block cannot square")
    end
    return true
  end -- end function

GetBoxJointMaterialSettings

TopOfPage.png
function GetBoxJointMaterialSettings(Table)
    local mtl_block = MaterialBlock()
    --local units
    if mtl_block.InMM then
      Table.Units = "Drawing Units: mm"
      Table.Unit = true
    else
      Table.Units = "Drawing Units: inches"
      Table.Unit = false
    end
    if mtl_block.Width > mtl_block.Height then
      Table.MaterialThickness = mtl_block.Height
      Table.MaterialLength = mtl_block.Width
      Table.Orantation = "H"
    else
      Table.MaterialThickness = mtl_block.Width
      Table.MaterialLength = mtl_block.Height
      Table.Orantation = "V"
    end
    if mtl_block.Height == mtl_block.Width then
      MessageBox("Error! Material block cannot square")
    end
    -- Display material XY origin
    local xy_origin_text = "invalid"
    local xy_origin = mtl_block.XYOrigin
    if  xy_origin == MaterialBlock.BLC then
        Table.xy_origin_text = "Bottom Left Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 90.0
        Table.Direction2 = 0.0
        Table.Direction3 = 270.0
        Table.Direction4 = 180.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 90.0
        Table.Direction3 = 180.0
        Table.Direction4 = 270.0
        Table.Bulge = -1.0
      end
    elseif xy_origin == MaterialBlock.BRC then
      Table.xy_origin_text = "Bottom Right Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 90.0
        Table.Direction2 = 180.0
        Table.Direction3 = 270.0
        Table.Direction4 = 0.0
        Table.Bulge = -1.0
      else
        Table.Direction1 = 180.0
        Table.Direction2 = 90.0
        Table.Direction3 = 0.0
        Table.Direction4 = 270.0
        Table.Bulge = 1.0
      end
    elseif xy_origin == MaterialBlock.TRC then
      Table.xy_origin_text = "Top Right Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 270.0
        Table.Direction2 = 180.0
        Table.Direction3 = 90.0
        Table.Direction4 = 0.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 180.0
        Table.Direction2 = 270.0
        Table.Direction3 = 0.0
        Table.Direction4 = 90.0
        Table.Bulge = -1.0
      end
    elseif xy_origin == MaterialBlock.TLC then
      Table.xy_origin_text = "Top Left Corner"
      if Table.Orantation == "V" then
        Table.Direction1 = 270.0
        Table.Direction2 = 0.0
        Table.Direction3 = 90.0
        Table.Direction4 = 180.0
        Table.Bulge = -1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 270.0
        Table.Direction3 = 180.0
        Table.Direction4 = 90.0
        Table.Bulge = 1.0
      end
    elseif xy_origin == MaterialBlock.CENTRE then  -- NOTE: English spelling for Centre!
      Table.xy_origin_text = "Center"
      if Table.Orantation == "V" then
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = 1.0
      else
        Table.Direction1 = 0.0
        Table.Direction2 = 0.0
        Table.Direction3 = 0.0
        Table.Direction4 = 0.0
        Table.Bulge = -1.0
      end
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
    else
        Table.xy_origin_text = "Unknown XY origin value!"
        MessageBox("Error! " .. xy_origin_text .. " Must be set at a corner of the Material")
      if Table.Orantation == "V" then
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
      else
        Table.Direction1 = 0
        Table.Direction2 = 0
        Table.Direction3 = 0
        Table.Direction4 = 0
      end
    end
    -- Setup Fingers and Gaps
    Table.NoFingers0 = 1 + (Rounder(BoxJoint.MaterialLength / BoxJoint.MaterialThickness, 0))
    Table.NoFingers2 = Rounder(BoxJoint.NoFingers0 / 2, 0)
    Table.FingerSize = BoxJoint.MaterialLength /  BoxJoint.NoFingers0
    Table.NoFingers1 = BoxJoint.NoFingers0 - BoxJoint.NoFingers2
    return true
  end -- function end

GetMaterialSettings

TopOfPage.png
function GetMaterialSettings(Table)
  local MaterialBlock = MaterialBlock()
  Table.MaterialBlockThickness = MaterialBlock.Thickness
  Table.xy_origin = MaterialBlock.XYOrigin
  if MaterialBlock.InMM then
    Table.Units  = "Drawing Units: mm"
    Table.Unit = true
    Table.Cal = 25.4
  else
    Table.Units  = "Drawing Units: inches"
    Table.Unit = false
    Table.Cal = 1.0
  end
  --local units
	if MaterialBlock.Width > MaterialBlock.Height then
    Table.Orantation = "H" -- Horizontal
	elseif MaterialBlock.Width < MaterialBlock.Height then
    Table.Orantation = "V"  -- Vertical
  else
    Table.Orantation = "S" -- Squair
	end
  if Table.xy_origin == MaterialBlock.BLC then
    Table.XYorigin = "Bottom Left Corner"
  elseif Table.xy_origin == MaterialBlock.BRC then
    Table.XYorigin = "Bottom Right Corner"
  elseif Table.xy_origin == MaterialBlock.TRC then
    Table.XYorigin = "Top Right Corner"
  else
    Table.XYorigin = "Top Left Corner"
  end -- if end
  Table.UnitDisplay  = "Note: Units: (" .. Table.Units ..")"
  return true
end -- end function

IsSingleSided

TopOfPage.png
function IsSingleSided(Table)
    local SingleSided = Table.job.IsSingleSided
    if not SingleSided then
      DisplayMessageBox("Error: Job must be a single sided job")
      return false
    end  -- if end
  end -- function end

IsDoubleSided

TopOfPage.png
function IsDoubleSided(Table)
  if not Table.job.IsDoubleSided then
    DisplayMessageBox("Error: Job must be a Double Sided Project")
    return false
  else
    return true
  end  -- if end
end-- function end

ShowSetting

TopOfPage.png
function ShowSetting(Table)
  local name = ""
      DisplayMessageBox(
    name .. " MaterialThickness = " .. tostring(Table.MaterialThickness) .."\n" ..
    name .. " BottleRad         = " .. tostring(Table.BottleRad)         .."\n" ..
    name .. " SideLenght        = " .. tostring(Table.SideLenght)        .."\n" ..
    name .. " SideHight         = " .. tostring(Table.SideHight)         .."\n" ..
    name .. " EndLenght         = " .. tostring(Table.EndLenght)         .."\n" ..
    name .. " EndHight          = " .. tostring(Table.EndHight)          .."\n" ..
    name .. " TopLenght         = " .. tostring(Table.TopLenght)         .."\n" ..
    name .. " TopWidht          = " .. tostring(Table.TopWidht)          .."\n" ..
    name .. " HandleLenght      = " .. tostring(Table.HandleLenght)      .."\n" ..
    name .. " HandleWidht       = " .. tostring(Table.HandleWidht)       .."\n" ..
    name .. " HandleRad         = " .. tostring(Table.HandleRad)         .."\n" ..
    name .. " MillingBitRad     = " .. tostring(Table.MillingBitRad)     .."\n" ..
    "\n")
end -- function end

MakeLayers

TopOfPage.png
function MakeLayers()
  local Red, Green, Blue = 0, 0, 0
  local function GetColor(str) -- returns color value for a Color Name
    local sx = str
    local Red = 0
    local Green = 0
    local Blue = 0
    local Colors = {}
    Colors.Black = "0,0,0"
    Colors.Red = "255,0,0"
    Colors.Blue = "0,0,255"
    Colors.Yellow = "255,255,0"
    Colors.Cyan = "0,255,255"
    Colors.Magenta = "255,0,255"
    Colors.Green = "0,128,0"
    if "" == str then
      DisplayMessageBox("Error: Empty string passed")
    else
      str = Colors[str]
      if "string" == type(str) then
        if string.find(str, ",") then
          Red   = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          str  = string.sub(str, assert(string.find(str, ",") + 1))
          Green = tonumber(string.sub(str, 1, assert(string.find(str, ",") - 1)))
          Blue  = tonumber(string.sub(str, assert(string.find(str, ",") + 1)))
        end
      else
        DisplayMessageBox("Error: Color " .. sx .. " not Found" )
        Red = 0
        Green = 0
        Blue = 0
      end
    end
    return Red, Green, Blue
  end
  local layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackPocket)
        Red, Green, Blue = GetColor(Milling.LNBackPocketColor)
        layer:SetColor (Red, Green, Blue)
        layer = Milling.job.LayerManager:GetLayerWithName(Milling.LNBackProfile)
        Red, Green, Blue = GetColor(Milling.LNBackProfileColor)
        layer:SetColor (Red, Green, Blue)
  return true
end -- function end

MyLayerClear

TopOfPage.png
function MyLayerClear(LayerName)
  local Mylayer = Milling.job.LayerManager:GetLayerWithName(LayerName)
     if Mylayer.IsEmpty then
        Milling.job.LayerManager:RemoveLayer(Mylayer)
     end -- if end
  return true
end -- function end

LayerClear

TopOfPage.png
function LayerClear()                       --  calling MyLayerClear
  MyLayerClear(Milling.LNBackPocket  .. "-Wall")
  MyLayerClear(Milling.LNBackPocket  .. "-Base")
  MyLayerClear(Milling.LNBackProfile .. "-Wall")
  MyLayerClear(Milling.LNBackProfile .. "-Base")
  MyLayerClear("PartLabels")
  return true
end -- function end

Logic and Test Tools

Back.jpg

These functions are named as per there function or action.


CheckNumber

TopOfPage.png
function CheckNumber(num)
  if type(num) == "number" then
    return true
  else
   return false
  end -- if end
end -- function end

AboveZero

TopOfPage.png
function AboveZero(num)
  if (type(num) == "number") and (num > 0.0)then
    return true
  else
   return false
  end -- if end
end -- function end




IsNumber()

TopOfPage.png
function IsNumber(Val)                     --Return true if Val is number
    if tonumber(x) ~= nil then
      return true
    end -- if end
    return false
  end -- end function

IsEven()

TopOfPage.png
function IsEven(IsEven_Number)             -- Returns True/False if number is even
    if (IsEven_Number % 2 == 0) then
      return true
    else
      return false
    end -- if end
  end -- function end

IsOdd()

TopOfPage.png
function IsOdd(IsOdd_Number)                          -- Returns True/False if number is odd
    if(IsOdd_Number%2 == 0) then
      return false
    end -- end if
    return true
  end -- function end

IsNegative()

TopOfPage.png
function IsNegative(x)                     -- Returns True/False if number is a negative number  
  if x >=0.0 then
    return false
  else
    return true
  end -- if end
end -- function end

IsAllNumber()

TopOfPage.png
function IsAllNumber(str)                  -- Returns True/False if finds all numbers in string
  local out = true                                     
  local let = ""
  for i = 1, #str do
    let = str:byte(i)
    if (let ~= 48) and (let ~= 49) and (let ~= 50) and (let ~= 51) and
       (let ~= 52) and (let ~= 53) and (let ~= 54) and (let ~= 55) and
       (let ~= 56) and (let ~= 57) and (let ~= 46) then
      out = false
    end -- if end
  end -- for end
  return out        -- send out the return
end  -- function end

NonNumber()

TopOfPage.png
function NonNumber(Val)                    -- Return true if val is not number
    if tonumber(x) ~= nil then
      return false
    end -- if end
    return true
  end -- end function

NumberType()

TopOfPage.png
function NumberType(Val)                   -- Return true if val is not number
    if math.type(x) == "integer" then
      return "integer"
    else
      return "float"
    end -- if end
  end -- end function

Math Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.


ArcSegment()

TopOfPage.png
function ArcSegment(p1, p2, Rad)                       -- Returns the Arc Segment
  local chord = math.sqrt(((p2.x - p1.x) ^ 2) + ((p2.y - p1.y) ^ 2))
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - chord^2))))
  return segment
end -- function end

D(x) Doubles x

TopOfPage.png
function D(x)                                           -- Returns double the value
  return x * 2.0
end -- function end

H(x) Halfs x

TopOfPage.png
function H(x)                                           -- Returns half the value
  return x * 0.5
end -- function end

C(x) Returns x by scale

TopOfPage.png
function C(x)                                           -- Returns scale value
  return x * Project.Cal
end -- function end

ChordSag2Radius()

TopOfPage.png
function ChordSag2Radius (Chr, Seg)                     -- Returns the Rad from Chord and Seg
  local rad = ((((Chr * Chr)/(Seg * 4)) + Seg) / 2.0)
  return rad
end -- function end

RadSag2Chord()

TopOfPage.png
function RadSag2Chord(Rad, Seg)                         -- Returns the Chord from Rad and Seg
  local Ang = 2 * math.acos(1 - (Seg/Rad))
  local Chord = (2 * Rad) * math.sin(Ang * 0.5)
  return Chord
end -- function end

RadChord2Segment()

TopOfPage.png
function RadChord2Segment (Rad, Chord)       -- Returns the Arc Segment from Rad and Chord
  local segment = (Rad - (0.5 * (math.sqrt((4.0 * Rad^2) - Chord^2))))
  return segment
end -- function end

RoundTo()

TopOfPage.png
function RoundTo(Num, Per)                   -- Returns the number from
  local Head = Num < 0 and math.ceil(Num) or math.floor(Num)
  local Tail = Num - Head
  local Value = Head + tonumber(string.sub(tostring(Tail), 1, Per + 2))
  return Value
end -- function end

Round()

TopOfPage.png
function Round(x)
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end

DecimalPlaces()

TopOfPage.png
function DecimalPlaces(Dnum, Plac)
  return tonumber(string.sub(tostring(Dnum)  .. "000000000000000000000000000000000000",1, string.len(tostring(math.floor(Dnum))) + 1 + Plac))
end

ToInteger()

TopOfPage.png
function ToInteger( x )
    local num = tonumber( x )
    return num < 0 and math.ceil( num ) or math.floor( num )
end 

TrigIt

Finds all 5 properties of a triangle

function TrigIt(A, B, AB, AC, BC)
-- Sub Function to help other functions
-- Call = A, B, AB, AC, BC = Trig(A, B, AB, AC, BC)
-- C is the corner, A = small ang and B is the big angle
-- returns all values
-- A, B = angles
-- C = 90.0 Deg
-- B to C (BC) is Run - Base - adjacent
-- A to C (AC) is Rise - Height - opposite
-- A to B (AB) is Slope - hypotenuse
    if (B > 0.0) and (A == 0.0) then
      A = math.deg(math.rad(90) - math.rad(B))
    end
    if (A > 0.0) and (B == 0.0) then
      B = math.deg(math.rad(90) - math.rad(A))
    end
    if  (AC > 0.0) and (BC > 0.0) then
      AB = math.sqrt((AC ^ 2) + (BC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (AB > 0.0) and (BC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (BC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (AB > 0.0) and (AC > 0.0) then
      AB = math.sqrt((AB ^ 2) - (AC ^ 2))
      A = math.deg(math.atan(BC/AC))
      B = math.deg(math.rad(90) - math.rad(A))
    elseif (A > 0.0) and (AC > 0.0) then
      AB = AC / math.cos(math.rad(A))
      BC = AB * math.sin(math.rad(A))
    elseif (A > 0.0) and (BC > 0.0) then
      AB = BC / math.sin(math.rad(A))
      AC = AB * math.cos(math.rad(A))
    elseif (A > 0.0) and (AB > 0.0) then
      BC = AB * math.sin(math.rad(A))
      AC = AB * math.cos(math.rad(A))
    else
      MessageBox("Error: No Missing Value")
    end -- if end
    return A, B, AB, AC, BC
  end

Registry Read and Write Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.


DocVarChk()

TopOfPage.png
function DocVarChk(Name, Value)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:DocumentVariableExists(Name)
end -- function end

DocVarGet()

TopOfPage.png
function DocVarGet(Name)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:GetDocumentVariable(Name, 0.0)
end -- function end

DocVarSet()

TopOfPage.png
function DocVarSet(Name, Value)
  local job = VectricJob()
  local document_variable_list = job.DocumentVariables
  return document_variable_list:SetDocumentVariable(Name, Value)
end -- function end

RegistryReadMaterial()

TopOfPage.png
function RegistryReadMaterial()                -- Read from Registry Material values for LUA Bit
  local RegistryRead              = Registry("Material")
  Milling.SafeZGap                = Rounder(RegistryRead:GetString("SafeZGap",              "0.500"), 4)
  Milling.StartZGap               = Rounder(RegistryRead:GetString("StartZGap",             "0.500"), 4)
  Milling.HomeX                   = Rounder(RegistryRead:GetString("HomeX",                 "0.000"), 4)
  Milling.HomeY                   = Rounder(RegistryRead:GetString("HomeY",                 "0.000"), 4)
  Milling.HomeZGap                = Rounder(RegistryRead:GetString("HomeZGap",              "0.750"), 4)
  return true
end -- function end

RegistryLastTenFiles()

TopOfPage.png
function RegistryLastTenFiles(FileName)        -- Adds to the top ten Log file list
  local Registry = Registry(RegName)
  LogFile.File10 = Registry:GetString("LogFile.File09", "No Log Yet" )
  LogFile.File09 = Registry:GetString("LogFile.File08", "No Log Yet" )
  LogFile.File08 = Registry:GetString("LogFile.File07", "No Log Yet" )
  LogFile.File07 = Registry:GetString("LogFile.File06", "No Log Yet" )
  LogFile.File06 = Registry:GetString("LogFile.File05", "No Log Yet" )
  LogFile.File05 = Registry:GetString("LogFile.File04", "No Log Yet" )
  LogFile.File04 = Registry:GetString("LogFile.File03", "No Log Yet" )
  LogFile.File03 = Registry:GetString("LogFile.File02", "No Log Yet" )
  LogFile.File02 = Registry:GetString("LogFile.File01", "No Log Yet" )
  LogFile.File01 = FileName
  return FileName
end -- function end

RegistryRead()

TopOfPage.png
function RegistryRead()                        -- Read from Registry values
  local RegistryRead = Registry("RegName")
  local Yes_No       = RegistryRead:GetBool("BaseDim.Yes_No", ture)
  local CabHeight    = RegistryRead:GetDouble("BaseDim.CabHeight", 35.500)
  local CabCount     = RegistryRead:GetInt("BaseDim.CabCount", 36)
  local Name         = RegistryRead:GetString("BaseDim.Name", "Words")

  Milling.MillTool1.FeedRate                = RegistryRead:GetDouble("Milling.MillTool1.FeedRate",              30.000)
  Milling.MillTool1.InMM                    = RegistryRead:GetBool("Milling.MillTool1.InMM ",                   false)
  Milling.MillTool1.Name                    = RegistryRead:GetString("Milling.MillTool1.Name",                  "No Tool Selected")
  Milling.MillTool1.BitType                 = RegistryRead:GetString("Milling.MillTool1.BitType",               "END_MILL") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool1.RateUnits               = RegistryRead:GetInt("Milling.MillTool1.RateUnits",                4)
  Milling.MillTool1.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool1.SpindleSpeed",             20000)
  Milling.MillTool1.ToolNumber              = RegistryRead:GetInt("Milling.MillTool1.ToolNumber",               1)
  Milling.MillTool1.Stepdown                = RegistryRead:GetDouble("Milling.MillTool1.Stepdown",              0.2000)
  Milling.MillTool1.Stepover                = RegistryRead:GetDouble("Milling.MillTool1.Stepover",              0.0825)
  Milling.MillTool1.ToolDia                 = RegistryRead:GetDouble("Milling.MillTool1.ToolDia",               0.1250)
  Milling.MillTool1.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool1.PlungeRate",            15.000)

  Milling.MillTool2.FeedRate                = RegistryRead:GetDouble("Milling.MillTool2.FeedRate",              30.000)
  Milling.MillTool2.InMM                    = RegistryRead:GetBool("Milling.MillTool2.InMM ",                   false)
  Milling.MillTool2.Name                    = RegistryRead:GetString("Milling.MillTool2.Name",                  "No Tool Selected")
  Milling.MillTool2.BitType                 = RegistryRead:GetString("Milling.MillTool2.BitType",               "BALL_NOSE") -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool2.RateUnits               = RegistryRead:GetInt("Milling.MillTool2.RateUnits",                4)
  Milling.MillTool2.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool2.SpindleSpeed",             20000)
  Milling.MillTool2.ToolNumber              = RegistryRead:GetInt("Milling.MillTool2.ToolNumber",               2)
  Milling.MillTool2.Stepdown                = RegistryRead:GetDouble("Milling.MillTool2.Stepdown",              0.2000)
  Milling.MillTool2.Stepover                = RegistryRead:GetDouble("Milling.MillTool2.Stepover",              0.0825)
  Milling.MillTool2.ToolDia                 = RegistryRead:GetDouble("Milling.MillTool2.ToolDia",               0.1250)
  Milling.MillTool2.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool2.PlungeRate",            15.000)

  Milling.MillTool3.FeedRate                = RegistryRead:GetDouble("Milling.MillTool3.FeedRate",              30.000)
  Milling.MillTool3.InMM                    = RegistryRead:GetBool("Milling.MillTool3.InMM",                    false)
  Milling.MillTool3.Name                    = RegistryRead:GetString("Milling.MillTool3.Name",                  "No Tool Selected")
  Milling.MillTool3.BitType                 = RegistryRead:GetString("Milling.MillTool3.BitType",               "END_MILL")  -- BALL_NOSE, END_MILL, VBIT
  Milling.MillTool3.RateUnits               = RegistryRead:GetInt("Milling.MillTool3.RateUnits",                4)
  Milling.MillTool3.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool3.SpindleSpeed",             20000)
  Milling.MillTool3.ToolNumber              = RegistryRead:GetInt("Milling.MillTool3.ToolNumber",               3)
  Milling.MillTool3.Stepdown                = RegistryRead:GetDouble("Milling.MillTool3.Stepdown",              0.2000)
  Milling.MillTool3.Stepover                = RegistryRead:GetDouble("Milling.MillTool3.Stepover",              0.0825)
  Milling.MillTool3.ToolDia                 = RegistryRead:GetDouble("Milling.MillTool3.ToolDia",               0.1250)
  Milling.MillTool3.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool3.PlungeRate",            15.000)

  Milling.MillTool4.FeedRate                = RegistryRead:GetDouble("Milling.MillTool4.FeedRate",              30.000)
  Milling.MillTool4.InMM                    = RegistryRead:GetBool("Milling.MillTool4.InMM ",                   false)
  Milling.MillTool4.Name                    = RegistryRead:GetString("Milling.MillTool4.Name",                  "No Tool Selected")
  Milling.MillTool4.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool4.PlungeRate",            15.000)
  Milling.MillTool4.RateUnits               = RegistryRead:GetInt("Milling.MillTool4.RateUnits",                4)
  Milling.MillTool4.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool4.SpindleSpeed",             20000)
  Milling.MillTool4.Stepdown                = RegistryRead:GetDouble("Milling.MillTool4.Stepdown",              0.2000)
  Milling.MillTool4.Stepover                = RegistryRead:GetDouble("Milling.MillTool4.Stepover",              0.0825)
  Milling.MillTool4.ToolDia                 = RegistryRead:GetDouble("Milling.MillTool4.ToolDia",               0.1250)
  Milling.MillTool4.ToolNumber              = RegistryRead:GetInt("Milling.MillTool4.ToolNumber",               5)

  Milling.MillTool5.FeedRate                = RegistryRead:GetDouble("Milling.MillTool5.FeedRate",              30.000)
  Milling.MillTool5.InMM                    = RegistryRead:GetBool("Milling.MillTool5.InMM ",                   false)
  Milling.MillTool5.Name                    = RegistryRead:GetString("Milling.MillTool5.Name",                  "No Tool Selected")
  Milling.MillTool5.PlungeRate              = RegistryRead:GetDouble("Milling.MillTool5.PlungeRate",            15.000)
  Milling.MillTool5.RateUnits               = RegistryRead:GetInt("Milling.MillTool5.RateUnits",                4)
  Milling.MillTool5.SpindleSpeed            = RegistryRead:GetInt("Milling.MillTool5.SpindleSpeed",             20000)
  Milling.MillTool5.Stepdown                = RegistryRead:GetDouble("Milling.MillTool5.Stepdown",              0.2000)
  Milling.MillTool5.Stepover                = RegistryRead:GetDouble("Milling.MillTool5.Stepover",              0.0825)
  Milling.MillTool5.ToolDia                 = RegistryRead:GetDouble("Milling.MillTool5.ToolDia",               0.1250)
  Milling.MillTool5.ToolNumber              = RegistryRead:GetInt("Milling.MillTool5.ToolNumber",               6)
  return true
end -- function end

RegistryWrite()

TopOfPage.png
function RegistryWrite()                       -- Write to Registry values
  local RegistryWrite = Registry("RegName")
  local RegValue
  RegValue = RegistryWrite:SetBool("ProjectQuestion.CabinetName", true)
  RegValue = RegistryWrite:SetDouble("BaseDim.CabDepth", 23.0000)
  RegValue = RegistryWrite:SetInt("BaseDim.CabHeight", 35)
  RegValue = RegistryWrite:SetString("BaseDim.CabLength", "Words")

  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.FeedRate" ,     Milling.MillTool1.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool1.InMM",            Milling.MillTool1.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool1.Name",          Milling.MillTool1.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool1.BitType",       Milling.MillTool1.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.PlungeRate" ,   Milling.MillTool1.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.RateUnits",        Milling.MillTool1.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.SpindleSpeed",     Milling.MillTool1.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepdown" ,     Milling.MillTool1.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.Stepover" ,     Milling.MillTool1.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool1.ToolDia" ,      Milling.MillTool1.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool1.ToolNumber",       Milling.MillTool1.ToolNumber)

  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.FeedRate" ,     Milling.MillTool2.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool2.InMM",            Milling.MillTool2.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool2.Name",          Milling.MillTool2.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool2.BitType",       Milling.MillTool2.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.PlungeRate" ,   Milling.MillTool2.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.RateUnits",        Milling.MillTool2.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.SpindleSpeed",     Milling.MillTool2.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepdown" ,     Milling.MillTool2.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.Stepover" ,     Milling.MillTool2.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool2.ToolDia" ,      Milling.MillTool2.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool2.ToolNumber",       Milling.MillTool2.ToolNumber)

  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.FeedRate" ,     Milling.MillTool3.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool3.InMM",            Milling.MillTool3.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool3.Name",          Milling.MillTool3.Name)
  RegValue = RegistryWrite:SetString("Milling.MillTool3.BitType",       Milling.MillTool3.BitType)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.PlungeRate",    Milling.MillTool3.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.RateUnits",        Milling.MillTool3.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.SpindleSpeed",     Milling.MillTool3.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepdown" ,     Milling.MillTool3.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.Stepover" ,     Milling.MillTool3.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool3.ToolDia" ,      Milling.MillTool3.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool3.ToolNumber",       Milling.MillTool3.ToolNumber)

  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.FeedRate" ,     Milling.MillTool4.FeedRate)
  RegValue = RegistryWrite:SetBool("Milling.MillTool4.InMM",            Milling.MillTool4.InMM)
  RegValue = RegistryWrite:SetString("Milling.MillTool4.Name",          Milling.MillTool4.Name)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.PlungeRate" ,   Milling.MillTool4.PlungeRate)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.RateUnits",        Milling.MillTool4.RateUnits)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.SpindleSpeed",     Milling.MillTool4.SpindleSpeed)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepdown" ,     Milling.MillTool4.Stepdown)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.Stepover" ,     Milling.MillTool4.Stepover)
  RegValue = RegistryWrite:SetDouble("Milling.MillTool4.ToolDia" ,      Milling.MillTool4.ToolDia)
  RegValue = RegistryWrite:SetInt("Milling.MillTool4.ToolNumber",       Milling.MillTool4.ToolNumber)
  return true
end -- function end

REG_CheckRegistryBool()

TopOfPage.png
function REG_CheckRegistryBool()               -- Checks Registry for Bool values
  local RegistryRead = Registry("RegName")
  if RegistryRead:BoolExists("ProjectQuestion.Runtool") then
    DisplayMessageBox("Alert: The Runtool value is saved.")
  else
    DisplayMessageBox("Alert: The Runtool value is not saved.")
  end -- if end
  return true
end -- function end

REG_CheckRegistryDouble()

TopOfPage.png
function REG_CheckRegistryDouble()             -- Checks Registry for Double values
  local RegistryRead = Registry("RegName")
  if RegistryRead:DoubleExists("ProjectQuestion.ProjectCost") then
    DisplayMessageBox("Alert: The project cost is saved.")
  else
    DisplayMessageBox("Alert: The Project Cost is not saved.")
  end -- if end
  return true
end -- function end

REG_CheckRegistryInt()

TopOfPage.png
function REG_CheckRegistryInt()                -- Checks Registry for Int values
  local RegistryRead = Registry("RegName")
  if RegistryRead:IntExists("ProjectQuestion.ProjectCount") then
    DisplayMessageBox("Alert: The Project Count is saved.")
  else
    DisplayMessageBox("Alert: The Project Count is not saved.")
  end -- if end
  return true
end -- function end

REG_CheckRegistryString()

TopOfPage.png
function REG_CheckRegistryString()             -- Checks Registry for String values
  local RegistryRead = Registry("RegName")
  if RegistryRead:StringExists("ProjectQuestion.ProjectPath") then
    DisplayMessageBox("Alert: The Project path is saved.")
  else
    DisplayMessageBox("Alert: The Project path is not saved.")
  end
  return true
end -- function end

String Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.


StringToArraySplit

TopOfPage.png
function StringToArraySplit(s, delimiter)
--[[
split_string = StringToArraySplit("Hello World,Jim,Bill,Tom", ",")
Returns = array
-- split_string[1] = "Hello World,)
-- split_string[2] = "Jim"
]]
  result = {};
  for match in (s..delimiter):gmatch("(.-)"..delimiter) do
      table.insert(result, match)
  end
  return result
end
  

WrapString

TopOfPage.png
function WrapString(Str, Wid)                           -- wraps text at the nearest space and puts a return char in the space location
  --[[  How to use:
  Call WrapString(string, Number)
 WrapString("Jim is a tall man that lives in Texas. He was raised in North East Texas on 1000 acres from 1970 to 1982. This is a man that knows numbers of great people from a round the world.", 40)
 returns "Jim is a tall man that lives in Texas.\n
          He was raised in North East Texas on\n
          1000 acres from 1970 to 1982. This is a man\n
          that knows numbers of great people from\n
          a round the world."
 ]]
  local Wider = Wid
  local Posx = string.len(Str)
  local StrLen = string.len(Str)
  local pt = 0
  local function FindSpace(MyStr)
  local Pos = string.len(MyStr)
  local str = MyStr
    if string.find(MyStr, " ") ~= nil then
      while Pos>0 do
        Pos = Pos - 1
          if (string.byte(string.sub(str,-1)) == 32) then
            break
          else
            str = string.sub(str, 1, Pos)
          end
        end
    end
    return Pos
  end
  if StrLen > Wider then
    while Wider < Posx do
      pt = FindSpace(string.sub(Str,1, Wider))
      Str = string.sub(Str, 1, pt) .. "\n" ..  string.sub(Str, pt +2)
      Wider = Wider + Wid
    end
  end
  return Str
end -- function end
  

CleanString

TopOfPage.png
function CleanString(inStr)                         -- Check for ascii letters below 127
  local outStr, str1 = ""
  local inStrLen = string.len(inStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(inStr, i, i)
    if string.byte(str1) <= 127 then
     outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
  

GetDiameterAndCentre

TopOfPage.png
function CheckString(YourStr)                          -- Check string for specal bite chars for HTML
  local function FindLetter(TheStr, TestChar)
    local outStr = false
    local strChar = ""
    local TheStrLen = string.len(TheStr)
    for i = 1, TheStrLen ,1 do
      strChar = string.sub(TheStr, i, i)
      if string.byte(strChar) == string.byte(TestChar) then
        outStr = true
        break
      end
    end
    return outStr
  end -- function end
  

GetDiameterAndCentre

TopOfPage.png
  local StrTest = false
  StrTest = SwitchLetter(YourStr,  "&")  -- Non frendly File Name letters
  StrTest = SwitchLetter(YourStr,  "#")
  StrTest = SwitchLetter(YourStr,  "@")
  StrTest = SwitchLetter(YourStr,  "^")
  StrTest = SwitchLetter(YourStr,  "$")
    return outStr
end -- function end
  

MakeHTMLReady()

TopOfPage.png
function MakeHTMLReady(MyStr)                          -- fix's string with special bite chars for HTML
  local function SwitchLetter(MyStr, MyChar, NewStr)
  local outStr, str1 = ""
  local inStrLen = string.len(MyStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(MyStr, i, i)
    if string.byte(str1) == string.byte(MyChar) then
     outStr=outStr .. NewStr
     else
         outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
  

SwitchLetterTest

TopOfPage.png
function SwitchLetterTest(MyStr)
  local outStr = ""
  outStr = SwitchLetter(MyStr, "!",	"!")
  outStr = SwitchLetter(outStr, "#",	"#")
  outStr = SwitchLetter(outStr, "$",	"$")
  outStr = SwitchLetter(outStr, "%",	"%")
  outStr = SwitchLetter(outStr, "&",	"&")
  outStr = SwitchLetter(outStr, "'",	"'")
  outStr = SwitchLetter(outStr, "(",	"(")
  outStr = SwitchLetter(outStr, ")",	")")
  outStr = SwitchLetter(outStr, "*",	"*")
  outStr = SwitchLetter(outStr, "+",	"+")
  outStr = SwitchLetter(outStr, ",",	",")
  outStr = SwitchLetter(outStr, "-",	"-")
  outStr = SwitchLetter(outStr, ".",	".")
  outStr = SwitchLetter(outStr, "/",	"/")
  outStr = SwitchLetter(outStr, ":",	":")
  outStr = SwitchLetter(outStr, ";",	";")
  outStr = SwitchLetter(outStr, "<",	"<")
  outStr = SwitchLetter(outStr, "=",	"=")
  outStr = SwitchLetter(outStr, ">",	">")
  outStr = SwitchLetter(outStr, "?",	"?")
  outStr = SwitchLetter(outStr, "@",	"@")
  outStr = SwitchLetter(outStr, "[",	"[")
  outStr = SwitchLetter(outStr, "]",	"]")
  outStr = SwitchLetter(outStr, "^",	"^")
  outStr = SwitchLetter(outStr, "_",	"_")
  outStr = SwitchLetter(outStr, "`",	"`")
  outStr = SwitchLetter(outStr, "{",	"&#123")
  outStr = SwitchLetter(outStr, "|",	"&#124")
  outStr = SwitchLetter(outStr, "}",	"&#125")
  outStr = SwitchLetter(outStr, "~",	"&#126")
    return outStr
end -- function end
  

SwitchLetter()

TopOfPage.png
function SwitchLetter(MyStr, MyChar, NewStr)            -- swwap a leter for another letter
  local outStr, str1 = ""
  local inStrLen = string.len(MyStr)
  for i = 1, inStrLen ,1 do
    str1 = string.sub(MyStr, i, i)
    if string.byte(str1) == string.byte(MyChar) then
     outStr=outStr .. NewStr
     else
         outStr=outStr .. str1
    end
  end
  return outStr
end -- function end
  

PadC

TopOfPage.png
function PadC(str, lenth)                        -- Adds spaces to front and back to center text in lenth
-- Local Word = PadC("K", 12) -- returns "     K      "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  if string.len(str) < lenth then
  local a = math.floor(lenth - string.len(str) * 0.5) - 2
  local b = math.ceil(lenth - string.len(str) * 0.5) - 2
  --print ("a = " .. a)
  for _ = 1, a, 1 do
    str =  " " .. str
  end
  for _ = 1, b, 1 do
    str =  str .. " "
  end
  --print ("str len = " .. #str)
  end
  return str
end -- function end
  

PadR()

TopOfPage.png
function PadR(str, len)                        -- Adds spaces to Back of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "KPSDFKSPSK  "
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = str .. " "
  end
  return str
end -- function end

PadL()

TopOfPage.png
function PadL(str, len)              -- Adds spaces to Front of string
-- Local Word = Pad("KPSDFKSPSK", 12) -- returns "  KPSDFKSPSK"
  if type(str) ~= "string" then
    str = tostring(str)
  end
  while string.len(str) < len do
    str = " " .. str
  end
  return str
end -- function end

NumberPad()

TopOfPage.png
function NumberPad(str, front, back) -- Adds spaces to front and zeros to the back of string
  local mychar
  local  a,b,c,d = 0,0,0,0
  local x,y,z = "","",""
  if type(str) ~= "string" then
    str = tostring(str)
  end
  c = string.len(str)
  for i = 1, c, 1 do
    mychar = string.byte(string.sub(str, i,i))
    if mychar == 46 then
      b = i
    end
  end
--  print("b = " .. b)
  if b == 0 then
    str = str .. "."
    c = c + 1
    b = c
  end -- if loc
  x = string.sub(str, 1, b-1)
  y = string.sub(str, b+1)
  a = c - b
  a = #x
  d = #y
  if a < front then
    front = front - (a - 1)
    for _ = 1, front -1 do
      x = " " .. x
    end -- end for front
  end
  back = back - (c - b)
  for i = 1, back  do
    y = y .. "0"
  end -- end for back
  str =   x .. "." .. y
  return str
end -- function end
  

All_Trim()

TopOfPage.png
function All_Trim(s)                           -- Trims spaces off both ends of a string
  return s:match( "^%s*(.-)%s*$" )
end -- function end
  

MakeProperCase()

TopOfPage.png
function MakeProperCase(str)
  local str=string.gsub(string.lower(str),"^(%w)", string.upper)
  return string.gsub(str,"([^%w]%w)", string.upper)
end
  

ifT()

TopOfPage.png
function ifT(x)                                -- Converts Boolean True or False to String "Yes" or "No"
-- ===ifT(x)===
  if x then
    return "Yes"
  else
    return "No"
  end-- if end
end -- function end
  

ifY()

TopOfPage.png
function ifY(x)                                -- Converts String "Yes" or "No" to Boolean True or False
-- ===ifY(x)===
  if string.upper(x) == "YES" then
    return true
  else
    return false
  end-- if end
end -- function end

Seed Documents

(top)

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

-- =====================================================]]
╔═╗╔═╗╔═╗╔╦╗  ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔
╚═╗║╣ ║╣  ║║  ╠╣ ║ ║║║║║   ║ ║║ ║║║║
╚═╝╚═╝╚═╝═╩╝  ╚  ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝
-- =====================================================]]
  -- VECTRIC LUA SCRIPT
-- =====================================================]]
-- Gadgets are an entirely optional add-in to Vectric's core software products.
-- They are provided 'as-is', without any express or implied warranty, and you make use of them entirely at your own risk.
-- In no event will the author(s) or Vectric Ltd. be held liable for any damages arising from their use.
-- Permission is granted to anyone to use this software for any purpose,
-- including commercial applications, and to alter it and redistribute it freely,
-- subject to the following restrictions:
-- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
-- 2. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required.
-- 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-- 4. This notice may not be removed or altered from any source distribution.
-- Easy Seed Gadget Master is written by Jim Anderson of Houston Texas 2020
-- =====================================================]]
-- require("mobdebug").start()
-- require "strict"
local Tools
-- Global Variables --
local Ver = "1.0"  -- Version 7: Aug 2021 - Clean Up and added Ver to Dialog

-- Table Names
Milling = {}
Project = {}
-- =====================================================]]
function main(script_path)
--[[
	Gadget Notes: Dec 2019 - My New Gadget

  ]]
-- Localized Variables --

-- Job Validation --
  local job = VectricJob()
  if not job.Exists then
    DisplayMessageBox("Error: No job loaded")
    return false
  end

  Tools = assert(loadfile(script_path .. "\\EasyGearToolsVer" .. Ver .. ".xlua")) (Tools) -- Load Tool Function
-- Get Data --

-- Calculation --

-- Do Something --


  return true
end  -- function end

Setup Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.

-- =====================================================]]
╔═╗╔═╗╔╦╗╦ ╦╔═╗
╚═╗║╣  ║ ║ ║╠═╝
╚═╝╚═╝ ╩ ╚═╝╩
function SetupAndLetter Seeds()
-- =====================================================]]
  function LUA_Seed()
    -- VECTRIC LUA SCRIPT
    -- ==============================================================================
    --  Gadgets are an entirely optional add-in to Vectric's core software products.
    --  They are provided 'as-is', without any express or implied warranty, and you
    --  make use of them entirely at your own risk.
    --  In no event will the author(s) or Vectric Ltd. be held liable for any damages
    --  arising from their use.
    --  Permission is granted to anyone to use this software for any purpose,
    --  including commercial applications, and to alter it and redistribute it freely,
    --  subject to the following restrictions:
    --  1. The origin of this software must not be misrepresented;
    --     you must not claim that you wrote the original software.
    --     If you use this software in a product, an acknowledgement in the product
    --     documentation would be appreciated but is not required.
    --  2. Altered source versions must be plainly marked as such, and
    --     must not be misrepresented as being the original software.
    --  3. This notice may not be removed or altered from any source distribution.
    -- ==============================================================================
    -- "AppName Here" was written by JimAndi Gadgets of Houston Texas
    -- ==============================================================================
    -- =====================================================]]
    -- require("mobdebug").start()
    -- require "strict"
    -- =====================================================]]
    -- Global variables
    -- =====================================================]]
  end -- lua function
-- =====================================================]]
  function Install_letter()
  -- Steps to Install:

  -- 1. Download the gadget x.zip that is attached to this post.
  -- 2. Rename it from x.zip to x.vgadget
  -- 3. In Vectric Pro or Aspire click on Gadgets -> Install Gadget and navigate to where you downloaded the file to, select it and click Ok.

  -- It should give you a pop up saying the gadget was installed and you should see x in the Gadgets menu.

  -- Image Here

  -- Steps for Use:
  -- 1. Select a layer that you want to calculate for
  -- 2. Enter the cut depth
  -- 3. Enter the percentage of coverage for the area that will be filled in
  -- 4. Enter the hardner to resin percentage
  -- 5. Click the Calculate Button and the results will be displayed below in the Results Pane.
  end -- install function

end -- Header function
-- =====================================================]]


Toolpathing Tools

Back.jpg

This object is a name-value pair that represents a Document Variable within a VectricJob.


CreateLayerProfileToolpath

TopOfPage.png
function CreateLayerProfileToolpath(name, layer_name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
    -- clear current selection
    local selection = job.Selection
    selection:Clear()
    -- get layer
    local layer = job.LayerManager:FindLayerWithName(layer_name)
    if layer == nil then
      DisplayMessageBox("No layer found with name = " .. layer_name)
      return false
    end
    -- select all closed vectors on the layer
    if not SelectVectorsOnLayer(layer, selection, true, false, true) then
      DisplayMessageBox("No closed vectors found on layer " .. layer_name)
      return false
    end
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT

    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local profile_data = ProfileParameterData()
    -- start depth for toolpath
    profile_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    profile_data.CutDepth = cut_depth
    -- direction of cut - ProfileParameterData.
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- side we machine on - ProfileParameterData.
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
    -- ProfileParameterData.PROFILE_ON
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
    -- Allowance to leave on when machining
    profile_data.Allowance = 0.0
    -- true to preserve start point positions, false to reorder start
    -- points to minimise toolpath length
    profile_data.KeepStartPoints = false
    -- true if want to create 'square' external corners on toolpath
    profile_data.CreateSquareCorners = false
    -- true to perform corner sharpening on internal corners (only with v-bits)
    profile_data.CornerSharpen = false
    -- true to use tabs (position of tabs must already have been defined on vectors)
    profile_data.UseTabs = false
    -- length for tabs if being used
    profile_data.TabLength = 5.0
    -- Thickness for tabs if being used
    profile_data.TabThickness = 1.0
    -- if true then create 3d tabs else 2d tabs
    profile_data.Use3dTabs = true
    -- if true in Aspire, project toolpath onto composite model
    profile_data.ProjectToolpath = false
    -- Create object used to control ramping
    local ramping_data = RampingData()
    -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
    -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
    -- or RampingData.CONSTRAIN_ANGLE
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
    -- if we are constraining ramp by distance, distance to ramp over
    ramping_data.RampDistance = 100.0
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function

CreateProfileToolpath

TopOfPage.png
function CreateProfileToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC ...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local profile_data = ProfileParameterData()
    -- start depth for toolpath
    profile_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    profile_data.CutDepth = cut_depth
    -- direction of cut - ProfileParameterData.
    -- CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION
    profile_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- side we machine on - ProfileParameterData.
    -- PROFILE_OUTSIDE, ProfileParameterData.PROFILE_INSIDE or
    -- ProfileParameterData.PROFILE_ON
    profile_data.ProfileSide = ProfileParameterData.PROFILE_OUTSIDE
    -- Allowance to leave on when machining
    profile_data.Allowance = 0.0
    -- true to preserve start point positions, false to reorder start
    -- points to minimise toolpath length
    profile_data.KeepStartPoints = false
    -- true if want to create 'square' external corners on toolpath
    profile_data.CreateSquareCorners = false
    -- true to perform corner sharpening on internal corners (only with v-bits)
    profile_data.CornerSharpen = false
    -- true to use tabs (position of tabs must already have been defined on vectors)
    profile_data.UseTabs = false
    -- length for tabs if being used
    profile_data.TabLength = 5.0
    -- Thickness for tabs if being used
    profile_data.TabThickness = 1.0
    -- if true then create 3d tabs else 2d tabs
    profile_data.Use3dTabs = true
    -- if true in Aspire, project toolpath onto composite model
    profile_data.ProjectToolpath = false
    -- Create object used to control ramping
    local ramping_data = RampingData()
    -- if true we do ramping into toolpath
    ramping_data.DoRamping = false
    -- type of ramping to perform RampingData.RAMP_LINEAR , RampingData.RAMP_ZIG_ZAG
    -- or RampingData.RAMP_SPIRAL
    ramping_data.RampType = RampingData.RAMP_ZIG_ZAG
    -- how ramp is contrained - either by angle or distance RampingData.CONSTRAIN_DISTANCE
    -- or RampingData.CONSTRAIN_ANGLE
    ramping_data.RampConstraint = RampingData.CONSTRAIN_ANGLE
    -- if we are constraining ramp by distance, distance to ramp over
    ramping_data.RampDistance = 100.0
    -- if we are contraining ramp by angle , angle to ramp in at (in degrees)
    ramping_data.RampAngle = 25.0
    -- if we are contraining ramp by angle, max distance to travel before 'zig zaging'
    -- if zig zaging
    ramping_data.RampMaxAngleDist = 15
    -- if true we restrict our ramping to lead in section of toolpath
    ramping_data.RampOnLeadIn = false
    -- Create object used to control lead in/out
    local lead_in_out_data = LeadInOutData()
    -- if true we create lead ins on profiles (not for profile on)
    lead_in_out_data.DoLeadIn = false
    -- if true we create lead outs on profiles (not for profile on)
    lead_in_out_data.DoLeadOut = false
    -- type of leads to create LeadInOutData.LINEAR_LEAD or LeadInOutData.CIRCULAR_LEAD
    lead_in_out_data.LeadType = LeadInOutData.CIRCULAR_LEAD
    -- length of lead to create
    lead_in_out_data.LeadLength = 10.0
    -- Angle for linear leads
    lead_in_out_data.LinearLeadAngle = 45
    -- Radius for circular arc leads
    lead_in_out_data.CirularLeadRadius = 5.0
    -- distance to 'overcut' (travel past start point) when profiling
    lead_in_out_data.OvercutDistance = 0.0
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateProfilingToolpath(name, tool, profile_data, ramping_data, lead_in_out_data, pos_data, geometry_selector, create_2d_previews, display_warnings )
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function

CreatePocketingToolpath

TopOfPage.png
function CreatePocketingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_stepover_percent, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * (tool_stepover_percent / 100)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC,...
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * (tool_stepover_percent / 100) -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass pocketing options
    local pocket_data = PocketParameterData()
    -- start depth for toolpath
    pocket_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    pocket_data.CutDepth = cut_depth
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or
    -- ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- Allowance to leave on when machining
    pocket_data.Allowance = 0.0
    -- if true use raster clearance strategy , else use offset area clearance
    pocket_data.DoRasterClearance = true
    -- angle for raster if using raster clearance
    pocket_data.RasterAngle = 0
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
    -- if true we ramp into pockets (always zig-zag)
    pocket_data.DoRamping = false
    -- if ramping, distance to ramp over
    pocket_data.RampDistance = 10.0
    -- if true in Aspire, project toolpath onto composite model
    pocket_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- if we are doing two tool pocketing define tool to use for area clearance
    local area_clear_tool = nill
    -- we just create a tool twice as large for testing here
    area_clear_tool = Tool("Lua Clearance End Mill", Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    area_clear_tool.InMM = tool_in_mm
    area_clear_tool.ToolDia = tool_dia * 2
    area_clear_tool.Stepdown = tool_stepdown * 2
    area_clear_tool.Stepover = tool_dia * 2 *(tool_stepover_percent / 100)
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC..
    area_clear_tool.FeedRate = 30
    area_clear_tool.PlungeRate = 10
    area_clear_tool.SpindleSpeed = 20000
    area_clear_tool.ToolNumber = 1
    area_clear_tool.VBit_Angle = 90.0 -- used for vbit only
    area_clear_tool.ClearStepover = tool_dia*2*(tool_stepover_percent/100) -- used for vbit
  -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreatePocketingToolpath(name,tool,area_clear_tool,pocket_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nill then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function

CreateDrillingToolpath

TopOfPage.png
function CreateDrillingToolpath(name, start_depth, cut_depth, retract_gap, tool_dia, tool_stepdown, tool_in_mm)
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua Drill", Tool.THROUGH_DRILL) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local drill_data = DrillParameterData()
    -- start depth for toolpath
    drill_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    drill_data.CutDepth = cut_depth
    -- if true perform peck drilling
    drill_data.DoPeckDrill = retract_gap > 0.0
    -- distance to retract above surface when peck drilling
    drill_data.PeckRetractGap = retract_gap
    -- if true in Aspire, project toolpath onto composite model
    drill_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view,
    -- if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateDrillingToolpath(name,tool,drill_data,pos_data,geometry_selector,create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function

CreateVCarvingToolpath

TopOfPage.png
function CreateVCarvingToolpath(name, start_depth, flat_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
    --[[ -------------- CreateVCarvingToolpath --------------
    |
    | Create a VCarving toolpath within the program for the currently selected vectors
    | Parameters:
    | name, -- Name for toolpath
    | start_depth -- Start depth for toolpath below surface of material
    | flat_depth -- flat depth - if 0.0 assume not doing flat bottom
    | vbit_angle -- angle of vbit to use
    | vbit_dia -- diameter of VBit to use
    | vbit_stepdown -- stepdown for tool
    | tool_stepover_percent - percentage stepover for tool
    | tool_in_mm -- true if tool size and stepdown are in mm
    |
    | Return Values:
    | true if toolpath created OK else false
    |
  ]]
  -- Create tool we will use to machine vectors
    local tool = Tool("Lua VBit",Tool.VBIT )-- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = vbit_dia
    tool.Stepdown = vbit_stepdown
    tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()    
    vcarve_data:SetHomePosition(Milling.HomeX, Milling.HomeY, Milling.HomeZGap ) -- vcarve_data:SetHomePosition(0, 0, 1.0)
    vcarve_data.SafeZGap = Milling.SafeZGap -- vcarve_data.SafeZGap = 0.5
    local vcarve_data = VCarveParameterData() -- Create object used to pass pocketing options - used for area clearance only
    vcarve_data.StartDepth = start_depth    -- start depth for toolpath
    vcarve_data.DoFlatBottom = flat_depth > 0.0    -- flag indicating if we are creating a flat bottomed toolpath
    vcarve_data.FlatDepth = flat_depth    -- cut depth for toolpath this is depth below start depth
    vcarve_data.ProjectToolpath = false    -- if true in Aspire, project toolpath onto composite model
    vcarve_data.UseAreaClearTool = true    -- set flag indicating we are using flat tool
    local pocket_data = PocketParameterData()    -- Create object used to pass pocketing options - used for area clearance only
    pocket_data.StartDepth = start_depth    -- start depth for toolpath
    pocket_data.CutDepth = flat_depth    -- cut depth for toolpath this is depth below start depth
    pocket_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData

    -- if true use raster clearance strategy , else use offset area clearance
    pocket_data.DoRasterClearance = false
    -- set flag indicating we are using flat tool
    pocket_data.UseAreaClearTool = true
    -- angle for raster if using raster clearance
    pocket_data.RasterAngle = 0
    -- type of profile pass to perform PocketParameterData.PROFILE_NONE ,
    -- PocketParameterData.PROFILE_FIRST orPocketParameterData.PROFILE_LAST
    pocket_data.ProfilePassType = PocketParameterData.PROFILE_LAST
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- if we are doing two tool pocketing define tool to use for area clearance
    local area_clear_tool = nil
    -- we just create a 10mm end mill
    area_clear_tool = Tool("Lua Clearance End Mill",Tool.END_MILL) -- BALL_NOSE, END_MILL, VBIT
    area_clear_tool.InMM = true
    area_clear_tool.ToolDia = 10
    area_clear_tool.Stepdown = 3
    area_clear_tool.Stepover = 3
    area_clear_tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    area_clear_tool.FeedRate = 30
    area_clear_tool.PlungeRate = 10
    area_clear_tool.SpindleSpeed = 20000
    area_clear_tool.ToolNumber = 2
    local geometry_selector = GeometrySelector()    -- Create object which can be used to automatically select geometry
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateVCarvingToolpath(name,tool, area_clear_tool,vcarve_data, pocket_data,pos_data,geometry_selector, create_2d_previews,display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end
    return true
end -- end function

CreatePrismToolpath

TopOfPage.png
function CreatePrismToolpath(name, start_depth, cut_depth, vbit_angle, vbit_dia, vbit_stepdown, tool_stepover_percent, tool_in_mm)
  --[[ ------------------- CreatePrismToolpath -------------------
  |
  | Create a prism toolpath within the program for the currently selected vectors
  | Parameters:
  | name, -- Name for toolpath
  | start_depth -- Start depth for toolpath below surface of material
  | cut_depth -- cut depth for drilling toolpath
  | vbit_angle -- angle of vbit to use
  | vbit_dia -- diameter of VBit to use
  | vbit_stepdown -- stepdown for tool
  | tool_stepover_percent - percentage stepover for tool
  | tool_in_mm -- true if tool size and stepdown are in mm
  |
  | Return Values:
  | true if toolpath created OK else false
  |
  ]]
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua VBit", Tool.VBIT ) -- BALL_NOSE, END_MILL, VBIT
    tool.InMM = tool_in_mm
    tool.ToolDia = vbit_dia
    tool.Stepdown = vbit_stepdown
    tool.Stepover = vbit_dia * (tool_stepover_percent / 100)
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = vbit_dia * (tool_stepover_percent / 100) * 2 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass profile options
    local prism_data = PrismCarveParameterData()
    -- start depth for toolpath
    prism_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    prism_data.CutDepth = cut_depth
    -- direction of cut for offet clearance - ProfileParameterData.CLIMB_DIRECTION
    -- or ProfileParameterData.CONVENTIONAL_DIRECTION - NOTE: enum from ProfileParameterData
    prism_data.CutDirection = ProfileParameterData.CLIMB_DIRECTION
    -- calculate the minimum cut depth to fully form the bevel on the current
    -- selection with the current tool
    local min_bevel_depth = prism_data:CalculateMinimumBevelDepth(tool, true)
    if min_bevel_depth > cut_depth then
      DisplayMessageBox("A prism will not be fully formed with a depth of " .. cut_depth .. "\r\n" ..
                        "A depth of " .. min_bevel_depth .. " is required to fully form the prism")
    end -- if end
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreatePrismCarvingToolpath(name, tool, prism_data, pos_data, geometry_selector, create_2d_previews, display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    end -- if end
    return true
end -- end function

CreateFlutingToolpath

TopOfPage.png
function CreateFlutingToolpath(name, start_depth, cut_depth, tool_dia, tool_stepdown, tool_in_mm)
    --[[ ----------------- CreateFlutingToolpath -----------------
  | Create a flutting toolpath within the program for the currently selected vectors
  | Parameters:
  | name, -- Name for toolpath
  | start_depth -- Start depth for toolpath below surface of material
  | cut_depth -- cut depth for toolpath
  | tool_dia -- diameter of tool to use
  | tool_stepdown -- stepdown for tool
  | tool_in_mm -- true if tool size and stepdown are in mm
  |
  | Return Values:
  | true if toolpath created OK else false
  |
  ]]
    -- Create tool we will use to machine vectors
    local tool = Tool("Lua Ball Nose", Tool.BALL_NOSE) -- BALL_NOSE, END_MILL, VBIT, THROUGH_DRILL
    tool.InMM = tool_in_mm
    tool.ToolDia = tool_dia
    tool.Stepdown = tool_stepdown
    tool.Stepover = tool_dia * 0.25
    tool.RateUnits = Tool.MM_SEC -- MM_SEC, MM_MIN, METRES_MIN, INCHES_SEC, INCHES_MIN, FEET_MIN
    tool.FeedRate = 30
    tool.PlungeRate = 10
    tool.SpindleSpeed = 20000
    tool.ToolNumber = 1
    tool.VBit_Angle = 90.0 -- used for vbit only
    tool.ClearStepover = tool_dia * 0.5 -- used for vbit only
    -- Create object used to set home position and safez gap above material surface
    local pos_data = ToolpathPosData()
    pos_data:SetHomePosition(0, 0, 1.0)
    pos_data.SafeZGap = 5.0
    -- Create object used to pass fluting options
    local fluting_data = FlutingParameterData()
    -- start depth for toolpath
    fluting_data.StartDepth = start_depth
    -- cut depth for toolpath this is depth below start depth
    fluting_data.CutDepth = cut_depth
    -- type of fluting FULL_LENGTH, RAMP_START or RAMP_START_END
    fluting_data.FluteType = FlutingParameterData.RAMP_START_END
    -- type of ramping RAMP_LINEAR, RAMP_SMOOTH
    fluting_data.RampType = FlutingParameterData.RAMP_LINEAR
    -- if true use ratio field for controling ramp length else absolute length value
    fluting_data.UseRampRatio = false
    -- length of ramp as ratio of flute length(range 0 - 1.0)
    -- (for start and end - ratio is of half length)
    fluting_data.RampRatio = 0.2
    -- length to ramp over - if UseRampRatio == false
    fluting_data.RampLength = 15
    -- if true in Aspire, project toolpath onto composite model
    fluting_data.ProjectToolpath = false
    -- Create object which can be used to automatically select geometry
    local geometry_selector = GeometrySelector()
    -- if this is true we create 2d toolpaths previews in 2d view, if false we dont
    local create_2d_previews = true
    -- if this is true we will display errors and warning to the user
    local display_warnings = true
    -- Create our toolpath
    local toolpath_manager = ToolpathManager()
    local toolpath_id = toolpath_manager:CreateFlutingToolpath(name, tool, fluting_data, pos_data, geometry_selector, create_2d_previews, display_warnings)
    if toolpath_id == nil then
      DisplayMessageBox("Error creating toolpath")
      return false
    else
      return true
    end

    end -- end function

SelectVectorsOnLayer

TopOfPage.png
function SelectVectorsOnLayer(layer, selection, select_closed, select_open, select_groups)
    -- Please Note: SelectVectorsOnLayer is provided by Vectric and can be found in the SDK and Sample Gadget files.
    --[[  ---------------- SelectVectorsOnLayer ----------------
    -- |   SelectVectorsOnLayer("Stringer Profile", selection, true, falus, falus)
    -- |   Add all the vectors on the layer to the selection
    -- |     layer,            -- layer we are selecting vectors on
    -- |     selection         -- selection object
    -- |     select_closed     -- if true  select closed objects
    -- |     select_open       -- if true  select open objects
    -- |     select_groups     -- if true select grouped vectors (irrespective of open / closed state of member objects)
    -- |  Return Values:
    -- |     true if selected one or more vectors|
    --]]
    local objects_selected = false
    local warning_displayed = false
    local pos = layer:GetHeadPosition()
    while pos ~= nil do
      local object
      object, pos = layer:GetNext(pos)
      local contour = object:GetContour()
      if contour == nil then
        if (object.ClassName == "vcCadObjectGroup") and select_groups then
          selection:Add(object, true, true)
          objects_selected = true
        else
          if not warning_displayed then
            local message = "Object(s) without contour information found on layer - ignoring"
            if not select_groups then
              message = message ..  "\r\n\r\n" ..
              "If layer contains grouped vectors these must be ungrouped for this script"
            end -- if end
            DisplayMessageBox(message)
            warning_displayed = true
          end -- if end
        end -- if end
      else  -- contour was NOT nil, test if Open or Closed
        if contour.IsOpen and select_open then
          selection:Add(object, true, true)
          objects_selected = true
        elseif select_closed then
          selection:Add(object, true, true)
          objects_selected = true
        end -- if end
      end -- if end
    end -- while end
    -- to avoid excessive redrawing etc we added vectors to the selection in 'batch' mode
    -- tell selection we have now finished updating
    if objects_selected then
      selection:GroupSelectionFinished()
    end -- if end
    return objects_selected
  end -- function end

References

Please Note: The base material for the contents found in this WiKi was sourced from Vectric Lua Interface for Gadgets, version 10.0, published August 21, 2019. by Vectric Ltd. Most current document from Vertric can be downloaded at Vertric Developer Information