In light of the structure of Graphics
, the best bet is to write a parser. Here is one I wrote. It is not complete, as I keep discovering directives I've missed, but it is close.
(* Utility for turning printing on/off. *)
(* --- Mr.Wizard's version of BlockPrint --- *)
ClearAll[BlockPrint];
SetAttributes[BlockPrint, HoldRest];
BlockPrint[True , body_] := Block[{Print}, body]
BlockPrint[False, body_] := body
(* Parser proper. Invoked by: parser@Graphics[...] *)
ClearAll[parser, parser`iparser, parser`directive, parser`primitive];
Options[parser] = {Verbose -> False};
parser[a_, opts:OptionsPattern[]] :=
Block[{parser`state = {}, parser`primList, parser`unknownfcn},
parser`unknownfcn[_]:= Sequence[];
BlockPrint[!OptionValue[Verbose],
Flatten[parser`iparser[a]] /. parser`primList -> List
]
]
(* Better isolation*)
Begin["parser`"];
(* Note the changes for v10 *)
directive := _AbsolutePointSize | _Arrowheads | _CapForm | _Dashing |
_EdgeForm | _FaceForm | _Glow | _JoinForm |
_Opacity | _PointSize | _Specularity | _Thickness |
If[ $VersionNumber < 10,
_CMYKColor | _RGBColor | _GrayLevel | _Hue,
_?ColorQ
];
primitive := _Arrow | _BezierCurve | _BSplineCurve | _BSplineSurface | _Circle |
_Cone | _Cuboid | _Cylinder | _Disk | _FilledCurve | _Inset |
_JoinedCurve | _Line | _Point | _Polygon | _Raster | _Raster3D |
_Rectangle | _Sphere | _Text | _Tube |
If[ $VersionNumber >= 10,
_Ball | _Circumsphere |
_ConicHullRegion | _HalfLine |
_HalfPlane | _Hexahedron | _InfiniteLine |
_Parallelepiped | _Parallelogram | _Prism | _Pyramid |
_Simplex | _Tetrahedron | _Triangle,
##&[]
] |
If[ $VersionNumber >= 10.2,
_AffineHalfSpace | _AffineSpace | _Annulus | _CapsuleShape |
_Cuboid | _DiskSegment | _HalfSpace | _Hyperplane | _InfinitePlane |
_Insphere | _RegularPolygon | _SphericalShell | _StadiumShape,
##&[]
];
(*
AASTriangle, ASATriangle, SASTriangle, and SSSTriangle evaluate
to Triangle via DownValues, so they'll never show up in Graphics(3D)
by themselves.
*)
iparser[l_Legended] := iparser@First@l
iparser[g:(_Graphics|_Graphics3D)]:= iparser @ First @ g
iparser[{}]:= Sequence[]
iparser[l_List] :=
Internal`InheritedBlock[{state},
Print["List"];
iparser /@ l
]
iparser[Style[a_, b__]]:=
Internal`InheritedBlock[{state,unknownfcn},
(* augment unknown function to work with strings *)
unknownfcn[str_String]:= (state = {state, str}; ##&[]);
Print["Style"];
iparser /@ {b};
iparser @ a
]
iparser[GraphicsGroup[a_List]] :=
(Print["GraphicsGroup - List"]; iparser @ a)
iparser[GraphicsGroup[a_]]:=
(Print["GraphicsGroup - NoList"]; iparser @ {a})
iparser[g_GraphicsComplex]:=
(Print["GraphicsComplex - Normalizing."]; iparser @ Normal @ g);
iparser[Directive[a___]] :=
(Print["Directive: ", Directive[a]]; iparser /@ Flatten[{a}])
iparser[m:directive] :=
(Print["directive: ", m]; state = {state, m}; ##&[])
iparser[p:primitive] :=
(
Print["primitive: ", p, "; state: ", state];
(* Prevents flattening later *)
primList[Flatten[state], p]
)
iparser[a_] := (Print["unknown: ", a]; unknownfcn[a])
End[]; (* parser` *)
This returns a list of the form
{{{directives__}, primitive_} .. }
So, it can not be immediately used again in a Graphics
object, but that can be sidestepped if need be. Applying parser
to the example from the previous question
parser@Graphics[{Blue, {EdgeForm[{Red, Thick}], Disk[]}, Disk[{1,0}]}]
returns
{
{{RGBColor[0, 0, 1], EdgeForm[{RGBColor[1, 0, 0], Thickness[Large]}]}, Disk[{0, 0}]},
{{RGBColor[0, 0, 1]}, Disk[{1, 0}]}
}
as I described.
Plot[{Cos[x], Sin[x]}, {x, 0, 4 Pi}][[1]] /. l_List /; Length[l] > 5 :> Short[l]
$\endgroup$(plot // First) /. List[(_?NumericQ) ..] :> Sequence[]
used there - reducing quality... $\endgroup$