-- tkz_elements_path.lua -- date 2025/05/25 -- version 4.00c -- Copyright 2025 Alain Matthes -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3 -- of this license or (at your option) any later version. -- The latest version of this license is in -- http://www.latex-project.org/lppl.txt -- and version 1.3 or later is part of all distributions of LaTeX -- version 2005/12/01 or later. -- This work has the LPPL maintenance status “maintained”. -- The Current Maintainer of this work is Alain Matthes. path = {} path.__index = path function path:new(data) if data ~= nil and type(data) ~= "table" then error("Expected table or nil in path constructor, got " .. type(data), 2) end return setmetatable(data or {}, self) end setmetatable(path, { __call = function(cls, ...) return cls:new(...) end }) function path.__add(p1, p2) local result = {} for _, pt in ipairs(p1) do result[#result + 1] = pt end for _, pt in ipairs(p2) do result[#result + 1] = pt end return path:new(result) end function path.__unm(p) local result = {} for i = #p, 1, -1 do result[#result + 1] = p[i] end return path:new(result) end function path.__sub(p1, p2) return p1 + (-p2) end function path:__tostring() return "path: { " .. table.concat(self, " , ") .. " }" end function path:add_point(z, decimals) table.insert(self, utils.format_point(z, decimals)) end function path:concat(sep) sep = sep or " " return table.concat(self, sep) end function path:add_pair_to_path(z1, z2, decimals) decimals = decimals or 5 local x1 = utils.format_coord(z1.re, decimals) local y1 = utils.format_coord(z1.im, decimals) local x2 = utils.format_coord(z2.re, decimals) local y2 = utils.format_coord(z2.im, decimals) local pt = string.format("%s/%s/%s/%s", x1, y1, x2, y2) table.insert(self, pt) end path.add_pair = path.add_pair_to_path function path:show() for _, pt in ipairs(self) do tex.print(pt) end end function path:copy() local c = {} for i, pt in ipairs(self) do c[i] = pt end return path:new(c) end -- Translation function path:translate(dx, dy) local moved = {} for _, pt in ipairs(self) do local x, y = utils.parse_point(pt) local newx = x + dx local newy = y + dy table.insert(moved, string.format("(%s,%s)", checknumber(newx), checknumber(newy))) end return path:new(moved) end -- Homothétie de centre (cx, cy), rapport k function path:homothety(center, k) local scaled = {} for _, pt in ipairs(self) do local x, y = utils.parse_point(pt) local newx = center.re + k * (x - center.re) local newy = center.im + k * (y - center.im) table.insert(scaled, string.format("(%s,%s)", utils.checknumber(newx), utils.checknumber(newy))) end return path:new(scaled) end -- Rotation autour de (cx, cy) d'un angle theta en radians function path:rotate(center, theta) local rotated = {} local cos_t = math.cos(theta) local sin_t = math.sin(theta) for _, pt in ipairs(self) do local x, y = utils.parse_point(pt) local dx, dy = x - center.re, y - center.im local newx = center.re + dx * cos_t - dy * sin_t local newy = center.im + dx * sin_t + dy * cos_t table.insert(rotated, string.format("(%s,%s)", utils.checknumber(newx), utils.checknumber(newy))) end return path:new(rotated) end -- Fermeture function path:close() if #self == 0 then return self end local x1, y1 = utils.parse_point(self[1]) local x2, y2 = utils.parse_point(self[#self]) if x1 ~= x2 or y1 ~= y2 then local closed = {} for i, pt in ipairs(self) do closed[i] = pt end closed[#closed + 1] = self[1] return path:new(closed) else return self end end -- Sous-chemin function path:sub(i1, i2) local subp = {} for i = i1 or 1, i2 or #self do subp[#subp + 1] = self[i] end return path:new(subp) end return path