Overview
Comment: | Merge the "diamond" enhancement to trunk. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
bc3bd914a386c504de0ab4862c0460d1 |
User & Date: | drh 2024-02-08 18:15:24 |
References
2024-02-08
| ||
19:26 | • Edit reply: Flow charting difficulties (artifact: 0ab51e1b13 user: wyoung) | |
19:23 | • Edit: Flow charting difficulties (artifact: fee048c0d1 user: wyoung) | |
Context
2024-02-08
| ||
18:28 | Clarified the intro paragraph to the userman doc. (check-in: fd3c2254d4 user: wyoung tags: trunk) | |
18:15 | Merge the "diamond" enhancement to trunk. (check-in: bc3bd914a3 user: drh tags: trunk) | |
18:12 | Added "diamond" example in the differences doc (Closed-Leaf check-in: 07423e4e2a user: wyoung tags: diamond) | |
16:47 | Grammar fix in the userman (check-in: 1bbfc50806 user: wyoung tags: trunk) | |
Changes
Added doc/diamondobj.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # Diamond objects A diamond acts much like a [box](./boxobj.md) except that its corners are rotated around the center point such that they become the shape’s four primary cardinal points: ~~~~ pikchr indent D: diamond "Cardinal" "Points" dot ".n" above at D.n dot " .e" ljust at D.e dot ".s" below at D.s dot ".w " rjust at D.w ~~~~ Indeed, before Pikchr [got this primitive](/info/36751abee2), the workaround was to draw an invisible box to hold the text, then draw lines between its cardinal points: ~~~~ pikchr indent box width 150% invis "“Diamond”" "Label" line from last.w to last.n to last.e to last.s close ~~~~ This does work, and it has the advantage of being compatible with the original PIC and with GNU `dpic`, but it also has a number of weaknesses, one of which is evident in comparing the examples above: the labels aren’t as well-centered when manually drawing the diamond. Another is the need for that 150% fudge factor to the invisible box’s width, without which the labels would be truncated by the dimensions Pikchr calculates for the invisible bounding box: ~~~~ pikchr indent box invis "“Diamond”" "Label" line from last.w to last.n to last.e to last.s close ~~~~ A third advantage falls out of this fact: the “`fit`” attribute works as expected for Pikchr diamonds. It cannot with the manual PIC-compatible workaround due to the lack of a properly-calculated bounding box, one taking into account the rotated cardinal points: ~~~~ pikchr indent text "Unfitted:" diamond "D" text "Properly fitted:" diamond "D" fit text "Badly fitted:" box invis "D" fit line from last.w to last.n to last.e to last.s close ~~~~ There’s a fourth, more subtle advantage to having this primtive built into the language: the location of the ordinal points is now well-defined: ~~~~ pikchr indent D: diamond "Ordinal" "Points" dot " .ne" ljust above at D.ne dot " .se" ljust below at D.se dot ".sw " rjust below at D.sw dot ".nw " rjust above at D.nw ~~~~ To replicate that with the PIC-compatible hack above, you’d have to do the geometry to work out where those points land along the lines. It’s better to leave that bit of tedious math to the Pikchr renderer. Unlike a box, you cannot currently round the corners on a diamond. You can, however, programmatically override the default height and width by redefining the `diamondht` and `diamondwid` variables. Here we show two different ways of making the diamond 25% larger: ~~~~ pikchr indent D: diamond thick "Diamond" "Dimensions" width 125% height 125% X1: line thin color gray left 70% from 4mm left of (D.w,D.n) X2: line same from 4mm left of (D.w,D.s) text "height" small at 1/2 way between X1 and X2 line thin color gray from previous text.n up until even with X1 -> line thin color gray from previous text.s down until even with X2 -> X3: line thin color gray down 50% from 2mm below (D.w,D.s) X4: line same from 2mm below (D.e,D.s) text "width" small at 1/2 way between X3 and X4 line thin color gray from previous text.w left until even with X3 -> line thin color gray from previous text.e right until even with X4 -> diamondht = diamondht * 1.25 diamondwid = diamondwid * 1.25 diamond thick "Diamond" "Dimensions" at 1.5in right of D ~~~~ |
Changes to doc/differences.md.
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | ## New Object Types Pikchr supports several new object types that were unavailable in PIC. ~~~ pikchr indent oval "oval" move cylinder "cylinder" move file "file" move dot " dot" ljust ~~~ | > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | ## New Object Types Pikchr supports several new object types that were unavailable in PIC. ~~~ pikchr indent oval "oval" move diamond "diamond" move cylinder "cylinder" move file "file" move dot " dot" ljust ~~~ |
︙ | ︙ | |||
169 170 171 172 173 174 175 | ## The "`chop`" attribute works differently The "`chop`" attribute is completely redesigned. It takes no argument and can only appear once. If "`chop`" is specified on a line (or arrow or spline) then end-points of the line that would have landed on the center of a box-like object (box, | | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | ## The "`chop`" attribute works differently The "`chop`" attribute is completely redesigned. It takes no argument and can only appear once. If "`chop`" is specified on a line (or arrow or spline) then end-points of the line that would have landed on the center of a box-like object (box, circle, cylinder, diamond, ellipse, file, or oval) are shortened to land exactly on the border of that object. ~~~ pikchr indent file "A" cylinder "B" at 5cm heading 125 from A arrow <-> from A to B chop "from A to B chop" aligned above ~~~ |
︙ | ︙ |
Changes to doc/grammar.md.
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 | ## *object-class*: * **arc** * **arrow** * **box** [▶info](./boxobj.md) * **circle** [▶info](./circleobj.md) * **cylinder** [▶info](./cylinderobj.md) * **dot** * **ellipse** [▶info](./ellipseobj.md) * **file** [▶info](./fileobj.md) * **line** * **move** * **oval** [▶info](./ovalobj.md) * **spline** | > | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | ## *object-class*: * **arc** * **arrow** * **box** [▶info](./boxobj.md) * **circle** [▶info](./circleobj.md) * **cylinder** [▶info](./cylinderobj.md) * **diamond** [▶info](./diamondobj.md) * **dot** * **ellipse** [▶info](./ellipseobj.md) * **file** [▶info](./fileobj.md) * **line** * **move** * **oval** [▶info](./ovalobj.md) * **spline** |
︙ | ︙ |
Changes to doc/locattr.md.
1 2 3 | # location-attribute A *location-attribute* is an attribute used to assign a location to | | | 1 2 3 4 5 6 7 8 9 10 11 | # location-attribute A *location-attribute* is an attribute used to assign a location to a block object (box, circle, cylinder, diamond, dot, ellipse, file, oval, or text). If a *location-attribute* appears on a line object (arc, arrow, line, move, or spline) an error is issued and processing stops. There are three forms: * **at** *position* * **with** *edgename* **at** *position* |
︙ | ︙ |
Changes to doc/pathattr.md.
1 2 3 4 5 | # path-attribute A *path-attribute* is used to provide the origin and direction of a line object, that being an arc, arrow, line, move, or spline. It is an error to use a *path-attribute* on a block object, that being a box, circle, | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # path-attribute A *path-attribute* is used to provide the origin and direction of a line object, that being an arc, arrow, line, move, or spline. It is an error to use a *path-attribute* on a block object, that being a box, circle, cylinder, diamond, dot, ellipse, file, oval, or text. There are seven forms: * **from** *position* * **then**? **to** *position* * **then**? **go**? *direction* *distance*? * **then**? **go**? *direction* **until**? **even with** *place* |
︙ | ︙ |
Changes to pikchr.c.
︙ | ︙ | |||
3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 | { "charwid", 0.08 }, { "circlerad", 0.25 }, { "color", 0.0 }, { "cylht", 0.5 }, { "cylrad", 0.075 }, { "cylwid", 0.75 }, { "dashwid", 0.05 }, { "dotrad", 0.015 }, { "ellipseht", 0.5 }, { "ellipsewid", 0.75 }, { "fileht", 0.75 }, { "filerad", 0.15 }, { "filewid", 0.5 }, { "fill", -1.0 }, | > > | 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 | { "charwid", 0.08 }, { "circlerad", 0.25 }, { "color", 0.0 }, { "cylht", 0.5 }, { "cylrad", 0.075 }, { "cylwid", 0.75 }, { "dashwid", 0.05 }, { "diamondht", 0.75 }, { "diamondwid", 1.0 }, { "dotrad", 0.015 }, { "ellipseht", 0.5 }, { "ellipsewid", 0.75 }, { "fileht", 0.75 }, { "filerad", 0.15 }, { "filewid", 0.5 }, { "fill", -1.0 }, |
︙ | ︙ | |||
3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 | pik_append_dis(p," r=\"", r, "\""); pik_append_style(p,pObj,2); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "ellipse" class */ static void ellipseInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "ellipsewid",10,0); pObj->h = pik_value(p, "ellipseht",9,0); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 | pik_append_dis(p," r=\"", r, "\""); pik_append_style(p,pObj,2); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "diamond" class */ static void diamondInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "diamondwid",10,0); pObj->h = pik_value(p, "diamondht",9,0); } /* Return offset from the center of the box to the compass point ** given by parameter cp */ static PPoint diamondOffset(Pik *p, PObj *pObj, int cp){ PPoint pt = cZeroPoint; PNum w2 = 0.5*pObj->w; PNum w4 = 0.25*pObj->w; PNum h2 = 0.5*pObj->h; PNum h4 = 0.25*pObj->h; switch( cp ){ case CP_C: break; case CP_N: pt.x = 0.0; pt.y = h2; break; case CP_NE: pt.x = w4; pt.y = h4; break; case CP_E: pt.x = w2; pt.y = 0.0; break; case CP_SE: pt.x = w4; pt.y = -h4; break; case CP_S: pt.x = 0.0; pt.y = -h2; break; case CP_SW: pt.x = -w4; pt.y = -h4; break; case CP_W: pt.x = -w2; pt.y = 0.0; break; case CP_NW: pt.x = -w4; pt.y = h4; break; default: assert(0); } UNUSED_PARAMETER(p); return pt; } static void diamondFit(Pik *p, PObj *pObj, PNum w, PNum h){ if( pObj->w>0 && pObj->h>0 ){ PNum x = pObj->w*h/pObj->h + w; PNum y = pObj->h*x/pObj->w; pObj->w = x; pObj->h = y; } UNUSED_PARAMETER(p); } static void diamondRender(Pik *p, PObj *pObj){ PNum w2 = 0.5*pObj->w; PNum h2 = 0.5*pObj->h; PPoint pt = pObj->ptAt; if( pObj->sw>=0.0 ){ pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y); pik_append_xy(p,"L", pt.x,pt.y-h2); pik_append_xy(p,"L", pt.x+w2,pt.y); pik_append_xy(p,"L", pt.x,pt.y+h2); pik_append(p,"Z\" ",-1); pik_append_style(p,pObj,3); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "ellipse" class */ static void ellipseInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "ellipsewid",10,0); pObj->h = pik_value(p, "ellipseht",9,0); } |
︙ | ︙ | |||
4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 | /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ cylinderOffset, /* xFit */ cylinderFit, /* xRender */ cylinderRender }, { /* name */ "dot", /* isline */ 0, /* eJust */ 0, /* xInit */ dotInit, /* xNumProp */ dotNumProp, /* xCheck */ dotCheck, /* xChop */ circleChop, | > > > > > > > > > > > | 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 | /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ cylinderOffset, /* xFit */ cylinderFit, /* xRender */ cylinderRender }, { /* name */ "diamond", /* isline */ 0, /* eJust */ 0, /* xInit */ diamondInit, /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ diamondOffset, /* xFit */ diamondFit, /* xRender */ diamondRender }, { /* name */ "dot", /* isline */ 0, /* eJust */ 0, /* xInit */ dotInit, /* xNumProp */ dotNumProp, /* xCheck */ dotCheck, /* xChop */ circleChop, |
︙ | ︙ | |||
8141 8142 8143 8144 8145 8146 8147 | return TCL_OK; } #endif /* PIKCHR_TCL */ | | | 8206 8207 8208 8209 8210 8211 8212 8213 | return TCL_OK; } #endif /* PIKCHR_TCL */ #line 8238 "pikchr.c" |
Changes to pikchr.y.
︙ | ︙ | |||
968 969 970 971 972 973 974 975 976 977 978 979 980 981 | { "charwid", 0.08 }, { "circlerad", 0.25 }, { "color", 0.0 }, { "cylht", 0.5 }, { "cylrad", 0.075 }, { "cylwid", 0.75 }, { "dashwid", 0.05 }, { "dotrad", 0.015 }, { "ellipseht", 0.5 }, { "ellipsewid", 0.75 }, { "fileht", 0.75 }, { "filerad", 0.15 }, { "filewid", 0.5 }, { "fill", -1.0 }, | > > | 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 | { "charwid", 0.08 }, { "circlerad", 0.25 }, { "color", 0.0 }, { "cylht", 0.5 }, { "cylrad", 0.075 }, { "cylwid", 0.75 }, { "dashwid", 0.05 }, { "diamondht", 0.75 }, { "diamondwid", 1.0 }, { "dotrad", 0.015 }, { "ellipseht", 0.5 }, { "ellipsewid", 0.75 }, { "fileht", 0.75 }, { "filerad", 0.15 }, { "filewid", 0.5 }, { "fill", -1.0 }, |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | pik_append_dis(p," r=\"", r, "\""); pik_append_style(p,pObj,2); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "ellipse" class */ static void ellipseInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "ellipsewid",10,0); pObj->h = pik_value(p, "ellipseht",9,0); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 | pik_append_dis(p," r=\"", r, "\""); pik_append_style(p,pObj,2); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "diamond" class */ static void diamondInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "diamondwid",10,0); pObj->h = pik_value(p, "diamondht",9,0); } /* Return offset from the center of the box to the compass point ** given by parameter cp */ static PPoint diamondOffset(Pik *p, PObj *pObj, int cp){ PPoint pt = cZeroPoint; PNum w2 = 0.5*pObj->w; PNum w4 = 0.25*pObj->w; PNum h2 = 0.5*pObj->h; PNum h4 = 0.25*pObj->h; switch( cp ){ case CP_C: break; case CP_N: pt.x = 0.0; pt.y = h2; break; case CP_NE: pt.x = w4; pt.y = h4; break; case CP_E: pt.x = w2; pt.y = 0.0; break; case CP_SE: pt.x = w4; pt.y = -h4; break; case CP_S: pt.x = 0.0; pt.y = -h2; break; case CP_SW: pt.x = -w4; pt.y = -h4; break; case CP_W: pt.x = -w2; pt.y = 0.0; break; case CP_NW: pt.x = -w4; pt.y = h4; break; default: assert(0); } UNUSED_PARAMETER(p); return pt; } static void diamondFit(Pik *p, PObj *pObj, PNum w, PNum h){ if( pObj->w>0 && pObj->h>0 ){ PNum x = pObj->w*h/pObj->h + w; PNum y = pObj->h*x/pObj->w; pObj->w = x; pObj->h = y; } UNUSED_PARAMETER(p); } static void diamondRender(Pik *p, PObj *pObj){ PNum w2 = 0.5*pObj->w; PNum h2 = 0.5*pObj->h; PPoint pt = pObj->ptAt; if( pObj->sw>=0.0 ){ pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y); pik_append_xy(p,"L", pt.x,pt.y-h2); pik_append_xy(p,"L", pt.x+w2,pt.y); pik_append_xy(p,"L", pt.x,pt.y+h2); pik_append(p,"Z\" ",-1); pik_append_style(p,pObj,3); pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } /* Methods for the "ellipse" class */ static void ellipseInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "ellipsewid",10,0); pObj->h = pik_value(p, "ellipseht",9,0); } |
︙ | ︙ | |||
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 | /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ cylinderOffset, /* xFit */ cylinderFit, /* xRender */ cylinderRender }, { /* name */ "dot", /* isline */ 0, /* eJust */ 0, /* xInit */ dotInit, /* xNumProp */ dotNumProp, /* xCheck */ dotCheck, /* xChop */ circleChop, | > > > > > > > > > > > | 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 | /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ cylinderOffset, /* xFit */ cylinderFit, /* xRender */ cylinderRender }, { /* name */ "diamond", /* isline */ 0, /* eJust */ 0, /* xInit */ diamondInit, /* xNumProp */ 0, /* xCheck */ 0, /* xChop */ boxChop, /* xOffset */ diamondOffset, /* xFit */ diamondFit, /* xRender */ diamondRender }, { /* name */ "dot", /* isline */ 0, /* eJust */ 0, /* xInit */ dotInit, /* xNumProp */ dotNumProp, /* xCheck */ dotCheck, /* xChop */ circleChop, |
︙ | ︙ |
Added tests/autochop10.pikchr.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | C: diamond "diamond" line from C to 3cm heading 00 from C chop; line from C to 3cm heading 10 from C chop; line from C to 3cm heading 20 from C chop; line from C to 3cm heading 30 from C chop; line from C to 3cm heading 40 from C chop; line from C to 3cm heading 50 from C chop; line from C to 3cm heading 60 from C chop; line from C to 3cm heading 70 from C chop; line from C to 3cm heading 80 from C chop; line from C to 3cm heading 90 from C chop; line from C to 3cm heading 100 from C chop; line from C to 3cm heading 110 from C chop; line from C to 3cm heading 120 from C chop; line from C to 3cm heading 130 from C chop; line from C to 3cm heading 140 from C chop; line from C to 3cm heading 150 from C chop; line from C to 3cm heading 160 from C chop; line from C to 3cm heading 170 from C chop; line from C to 3cm heading 180 from C chop; line from C to 3cm heading 190 from C chop; line from C to 3cm heading 200 from C chop; line from C to 3cm heading 210 from C chop; line from C to 3cm heading 220 from C chop; line from C to 3cm heading 230 from C chop; line from C to 3cm heading 240 from C chop; line from C to 3cm heading 250 from C chop; line from C to 3cm heading 260 from C chop; line from C to 3cm heading 270 from C chop; line from C to 3cm heading 280 from C chop; line from C to 3cm heading 290 from C chop; line from C to 3cm heading 300 from C chop; line from C to 3cm heading 310 from C chop; line from C to 3cm heading 320 from C chop; line from C to 3cm heading 330 from C chop; line from C to 3cm heading 340 from C chop; line from C to 3cm heading 350 from C chop; |
Added tests/diamond01.pikchr.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | D1: diamond "First Diamond" arrow D2: diamond "Above" above "Below" below arrow D3: diamond "Fitted" fit arrow from D2.s down 1cm down D4: diamond "Long string above" above "Below1" below fit right arrow D5: diamond width 300% "thin" fit arrow from D3.e right 2cm right D6: diamond height 300% "tall" above "diamond" below fit |
Changes to tests/test78.pikchr.
1 2 3 4 5 6 7 8 | down text "Zero Thickness Objects" box "Box" fill lightblue thickness 0 fit circle "Circle" fill yellow thickness 0 fit file "File" fill lightgreen thickness 0 fit oval "Oval 1" fill pink thickness 0 fit oval "Oval 2" fill lightgrey width 1.1cm height 2cm thickness 0 cylinder "Cylinder" fill orange fit thickness 0 | > | 1 2 3 4 5 6 7 8 9 | down text "Zero Thickness Objects" box "Box" fill lightblue thickness 0 fit circle "Circle" fill yellow thickness 0 fit file "File" fill lightgreen thickness 0 fit oval "Oval 1" fill pink thickness 0 fit oval "Oval 2" fill lightgrey width 1.1cm height 2cm thickness 0 cylinder "Cylinder" fill orange fit thickness 0 diamond "Diamond" fill lightblue fit thickness 0 |