mesh "holds" all the points. points are numbered in the mesh from 0 ... mesh:CountPoints()-1
mesh also holds "curves" - which are ordered lists of points. Curves are numbered form 0 ... mesh:CountCurves()-1
a path (a curve) is made up of points. Points are ALSO numbered in a curve from 0 ... curve:CountPoints()-1 Note that these numbers are different -- e.g. Curve(1): Point(3) might be Mesh:Point(44)
a curve is made up of segments. They are numbered 0 ... curve:CountSegments() -1. Generally the start point of segment (x) is point in curve (x). If the curve is closed (i.e. a loop) segments = points; if it's not, there's one more point than segments.
a shape has edges; they are numbered 0 ... Shape:CountEdges()-1. An edge is a segment of a curve. One segment can be in many shapes.
The following is a diagnostic routine I use to explore shapes in a mesh. It is designed to run inside my test harness and has a two-way reliance on services in the harness (it requests and gets data from the UI in the harness; it uses the harness to display information). So you can't just run it... but it might illustrate some of the info above. (You'll probably also notice that it doesn't try to catch being invoked on a non-mesh layer ... if ever this plus harness are ruggedized for public use that would be on the to-do list.)
Code: Select all
HS_ListShapes = {}
local thisUUT = "C" -- this is used in "print" services to tell the harness which output stream to use.
function HS_ListShapes:Test() -- this tells the harness that the code here wishes to run as a harness plug-in
return true
-- return false
end
function HS_ListShapes:Name()
return "About shapes"
end
function HS_ListShapes:Version()
return "version 1.20f"
end
-- display options
local showDetails, showDetailsText
showDetails = false
-- showDetails = true -- true => show point count, edge count etc
showDetailsText = "Basics "
local showColours, showColoursText
-- showColours = false
showColours = true
showColoursText = "Fill / Stroke Colours "
local showControl, showControlText
-- showControl = false
showControl = true
showControlText = "Control Handles "
local showPoints, showPointsText
-- showPoints = false
showPoints = true
showPointsText = "Points "
local showWidth, showWidthText
showWidth = false
-- showWidth = true
showWidthText = "Line Width "
local showEdges, showEdgesText
showEdges = false
-- showEdges = true
showEdgesText = "Edges "
local showSegments, showSegmentsText
showSegments = false
-- showSegments = true
showSegmentsText = "Segments "
local showBrush, showBrushText
showBrush = false
-- showBrush = true
showBrushText = "Brush "
local showAllShapes, showAllShapesTextTrue, showAllShapesTextFalse
showAllShapes = false -- false => show only selected shapes
-- showAllShapes = true
showAllShapesTextTrue = "All shapes"
showAllShapesTextFalse = "Selected shapes"
function HS_ListShapes:RequestData () -- this is called by the harness to set up the harness UI
local dataTags = {
{"Basics ", HS_Bool+HS_Optional},
{"Fill / Stroke Colours ", HS_Bool+HS_Optional},
{"Contol Handles ", HS_Bool+HS_Optional},
{"Points ", HS_Bool+HS_Optional},
{"Line Width ", HS_Bool+HS_Optional},
{"Edges ", HS_Bool+HS_Optional},
{"Segments ", HS_Bool+HS_Optional},
{"Brush ", HS_Bool+HS_Optional},
{"All shapes", HS_Bool+HS_Optional}
}
return dataTags
end
--
-- ** the :Run() function
--
function HS_ListShapes:Run(moho, view) -- this is invoked by the harness when valid data has been input
local i, s, q
local sel = {}
sel = HS_Test_harness:GetData () -- this is a call to the harness to provide the requested data
if not sel or #sel ~= 9 then
HS_Test_harness:tracePrint (thisUUT, self:Name(), self:Version(), "Bad data request", type(sel), #sel)
return false
end
showDetails = sel[1]
showColours = sel[2]
showControl = sel[3]
showPoints = sel[4]
showWidth = sel[5]
showEdges = sel[6]
showSegments = sel[7]
showBrush = sel[8]
showAllShapes = sel[9]
s = "Show info for "
if showAllShapes then
s = s .. showAllShapesTextTrue
else
s = s .. showAllShapesTextFalse
end
q = ""
if showDetails then q = q .. showDetailsText end
if showColours then q = q .. showColoursText end
if showControl then q = q .. showControlText end
if showBrush then q = q .. showBrushText end
if showWidth then q = q .. showWidthText end
if showPoints then q = q .. showPointsText end
if showEdges then q = q .. showEdgesText end
if showSegments then q = q .. showSegmentsText end
HS_Test_harness:tracePrint (thisUUT, self:Name(), self:Version(), s, q)
local layer = moho.layer
local i, j, k, m, n, p, w
local ch, offset, theta, scale
local Pos = LM.Vector2:new_local()
local min = LM.Vector2:new_local()
local max = LM.Vector2:new_local()
local mesh = moho:Mesh()
local when = moho.frame
local shape, curve
local pt
local colour, width
--
-- ** Report a given segment
--
local function reportSegment (edge, curve, seg)
local s, sl
local TanS = LM.Vector2:new_local()
local TanE = LM.Vector2:new_local()
local NormS = LM.Vector2:new_local()
local NormE = LM.Vector2:new_local()
local startPercent, endPercent
local segDirn0, segDirn1
local normDirn0, normDirn1
sl = curve:SegmentLength(seg)
if curve:IsSegmentSelected(seg) then
s = "Selected"
else
s = ""
end
HS_Test_harness:diagnosePrint (thisUUT, "Edge", edge, s, "Length", sl)
pt = curve:Point(seg) -- point at start of segment
HS_Test_harness:diagnosePrint (thisUUT, "Start point is mesh point", mesh:PointID(pt))
if seg + 1 < curve:CountPoints() then
pt = curve:Point(seg+1) -- end of segment point
elseif curve.fClosed then
pt = curve:Point(0)
else
HS_Test_harness:diagnosePrint (thisUUT, "point out of range in segment", seg, "curve has", curve:CountPoints(), "points")
return
end
HS_Test_harness:diagnosePrint (thisUUT, "End point is mesh point", mesh:PointID(pt))
startPercent, endPercent = 0,0
startPercent, endPercent = curve:GetSegmentRange(seg)
HS_Test_harness:diagnosePrint (thisUUT, "In Curve, seg range % is", startPercent, endPercent)
TanS = curve:GetPercentTangent(startPercent)
NormS = TanS:GetOrthogonal()
TanE = curve:GetPercentTangent(endPercent)
NormE = TanE:GetOrthogonal()
segDirn0 = math.deg (math.atan2 (TanS.y, TanS.x))
segDirn1 = math.deg (math.atan2 (TanE.y, TanE.x))
normDirn0 = math.deg (math.atan2 (NormS.y, NormS.x))
normDirn1 = math.deg (math.atan2 (NormE.y, NormE.x))
HS_Test_harness:diagnosePrint (thisUUT, "Start Tangent", HS_Test_harness:diagnoseVec2 (TanS), segDirn0, "Mag",
TanS:Mag(), "Norm", HS_Test_harness:diagnoseVec2 (NormS), normDirn0)
HS_Test_harness:diagnosePrint (thisUUT, "End Tangents", HS_Test_harness:diagnoseVec2 (TanE), segDirn1, "Mag",
TanE:Mag(), "Norm", HS_Test_harness:diagnoseVec2 (NormE), normDirn1)
end
--
-- ** report a given shape
--
local function reportShape(i, when)
local smax, smin
shape = mesh:Shape(i)
local p = shape:CountPoints()
local s = ""
if shape.fSelected and showAllShapes then
s = "Selected"
else
s = ""
end
HS_Test_harness:tracePrint (thisUUT, "shape", i, shape:Name(), "internal Id:", shape:ShapeID(), s, "at frame", when)
if showDetails then
HS_Test_harness:diagnosePrint (thisUUT, "Shape has", shape:CountEdges(), "edges", p, "points",
" Filled?", shape.fHasFill, " Stroke?", shape.fHasOutline)
shape:ShapeBounds(min, max)
smin = "{" .. tostring (min.x) .. "," .. tostring (min.y) .. "} "
smax = "{" .. tostring (max.x) .. "," .. tostring (max.y) .. "} "
HS_Test_harness:diagnosePrint (thisUUT, "Bounds", smin .. smax, "Xlen =", max.x-min.x, "Ylen =", max.y-min.y)
end
if shape.fHasFill and showColours then
colour = shape.fMyStyle.fFillCol.value
HS_Test_harness:diagnosePrint (thisUUT, "fill colour is", colour.r, colour.g, colour.b, colour.a)
end
if shape.fHasFill and showControl then
min:Set(shape:EffectHandle1())
smin = "{" .. tostring (min.x) .. "," .. tostring (min.y) .. "}"
max:Set(shape:EffectHandle2())
smax = "{" .. tostring (max.x) .. "," .. tostring (max.y) .. "}"
Pos = max - min
HS_Test_harness:diagnosePrint (thisUUT, "control handle 1:", smin, "control handle 2:", smax, "length:", Pos:Mag())
Pos:Set(shape:ShapeCenter())
HS_Test_harness:diagnosePrint (thisUUT, "centre", Pos.x, Pos.y)
ch = shape.fEffectOffset
Pos:Set(ch:GetValue(when))
ch = shape.fEffectScale
scale = ch:GetValue(when)
ch = shape.fEffectRotation
theta = ch:GetValue(when)
HS_Test_harness:diagnosePrint (thisUUT, "Effect offset:", Pos.x, Pos.y, "Scale", scale, "Rotation", math.deg(theta))
end
if shape.fHasOutline and showColours then
colour = shape.fMyStyle.fLineCol.value
HS_Test_harness:diagnosePrint (thisUUT, "line colour is", colour.r, colour.g, colour.b, colour.a)
end
if shape.fHasOutline and showWidth then
HS_Test_harness:diagnosePrint (thisUUT, "line width is", shape.fMyStyle.fLineWidth)
end
if shape.fHasOutline and showBrush then
s = shape.fMyStyle.fBrushName:Buffer()
if s ~= "" then
HS_Test_harness:diagnosePrint (thisUUT, "brush is", s, "random order?", shape.fMyStyle.fBrushRandomOrder)
else
HS_Test_harness:diagnosePrint (thisUUT, "no brush")
end
end
if showPoints then
HS_Test_harness:diagnosePrint (thisUUT, "All pts selected?", shape:AllPointsSelected())
for j = 0, p-1 do
n = shape:GetPoint(j)
pt = mesh:Point(n)
Pos:Set(pt.fPos)
HS_Test_harness:diagnosePrint (thisUUT, "Point", j, "is mesh point", n,
"at", Pos.x, Pos.y, "Selected?", pt.fSelected)
if shape.fHasOutline and showWidth then
HS_Test_harness:diagnosePrint (thisUUT, "Width at point is", pt.fWidth:GetValue(when))
end
end
end
if showEdges or showSegments then
for j = 0, shape:CountEdges()-1 do
local curveID, segID = -1, -1 -- any initial value will do
curveID, segID = shape:GetEdge(j)
if showEdges then
HS_Test_harness:diagnosePrint (thisUUT, ">>>>Edge", j, "in shape", i, "is seg", segID, "of curve", curveID)
end
if showSegments then
curve = mesh:Curve(curveID)
reportSegment (j, curve, segID)
end
end
end
end
--
-- >>>>>> MAINLINE actual RUN Starts here...
--
--
-- ** About shapes and their points...
--
local ct = mesh:CountShapes()
HS_Test_harness:tracePrint (thisUUT, "mesh has", ct, "shapes") -- shape 0 is at the bottom; shape (ct-1) is at the top
for i = 0, ct-1 do
shape = mesh:Shape(i)
if shape.fSelected or showAllShapes then
reportShape(i, when)
end
end
end