Attempt Shading + Bezier Bounds (hopefully) correct
authorSam Moore <[email protected]>
Thu, 14 Aug 2014 20:20:37 +0000 (04:20 +0800)
committerSam Moore <[email protected]>
Thu, 14 Aug 2014 20:20:37 +0000 (04:20 +0800)
Turns out I can't do high school calculus despite 4 years of Physics study.

The shading algorithm I envisioned has several rather hilarious
things wrong with it...

Although that 'j' does look damn good if you set the zoom *just* right...

src/bezier.cpp
src/bezier.h
src/document.cpp
src/objectrenderer.cpp
src/objectrenderer.h
src/screen.cpp
src/svg-tests/cubicbeziers.svg [new file with mode: 0644]
src/svg-tests/shape_pathonly.svg [new file with mode: 0644]

index a30a20a..da65336 100644 (file)
@@ -59,8 +59,8 @@ static pair<Real, Real> BezierTurningPoints(const Real & p0, const Real & p1, co
        {
                return pair<Real,Real>(0, 1);
        }
        {
                return pair<Real,Real>(0, 1);
        }
-       Real a = (p1- p0 - 2*(p2-p1) + p3-p2);
-       Real b = (p1-p0 - (p2-p1))*(p1-p0);
+       Real a = (3*(p1-p2) + p3 - p0);
+       Real b = 2*(p2 - 2*p1 + p0);
        Real c = (p1-p0);
        if (a == 0)
        {
        Real c = (p1-p0);
        if (a == 0)
        {
@@ -74,6 +74,7 @@ static pair<Real, Real> BezierTurningPoints(const Real & p0, const Real & p1, co
        Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c));
        if (b*b - 4*a*c < 0)
        {
        Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c));
        if (b*b - 4*a*c < 0)
        {
+               Debug("No real roots");
                return pair<Real, Real>(0,1);
        }
        pair<Real, Real> tsols = SolveQuadratic(a, b, c);
                return pair<Real, Real>(0,1);
        }
        pair<Real, Real> tsols = SolveQuadratic(a, b, c);
index 722ed57..f3df458 100644 (file)
@@ -11,8 +11,8 @@ namespace IPDF
        
        inline std::pair<Real,Real> SolveQuadratic(const Real & a, const Real & b, const Real & c)
        {
        
        inline std::pair<Real,Real> SolveQuadratic(const Real & a, const Real & b, const Real & c)
        {
-               Real x0((b + Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
-               Real x1((b - Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
+               Real x0((-b + Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
+               Real x1((-b - Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
                return std::pair<Real,Real>(x0,x1);
        }
 
                return std::pair<Real,Real>(x0,x1);
        }
 
index 4cf6c40..16cb8f9 100644 (file)
@@ -389,7 +389,7 @@ static void TransformXYPair(Real & x, Real & y, const SVGMatrix & transform)
 
 void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
 {
 
 void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
 {
-       Debug("Parsing transform %s", s.c_str());
+       //Debug("Parsing transform %s", s.c_str());
        string token;
        string command;
        unsigned i = 0;
        string token;
        string command;
        unsigned i = 0;
@@ -404,7 +404,7 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
                        else
                                return;
                }
                        else
                                return;
                }
-               Debug("Token is \"%s\"", command.c_str());
+               //Debug("Token is \"%s\"", command.c_str());
        
                SVGMatrix delta = {1,0,0,0,1,0};
        
        
                SVGMatrix delta = {1,0,0,0,1,0};
        
@@ -443,8 +443,8 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
                        Warn("Unrecognised transform \"%s\", using identity", command.c_str());
                }
        
                        Warn("Unrecognised transform \"%s\", using identity", command.c_str());
                }
        
-               Debug("Old transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f);
-               Debug("Delta transform is {%f,%f,%f,%f,%f,%f}", delta.a, delta.b, delta.c, delta.d,delta.e,delta.f);
+               //Debug("Old transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f);
+               //Debug("Delta transform is {%f,%f,%f,%f,%f,%f}", delta.a, delta.b, delta.c, delta.d,delta.e,delta.f);
        
                SVGMatrix old(transform);
                transform.a = old.a * delta.a + old.c * delta.b;
        
                SVGMatrix old(transform);
                transform.a = old.a * delta.a + old.c * delta.b;
@@ -455,13 +455,13 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
                transform.d = old.b * delta.c + old.d * delta.d;
                transform.f = old.b * delta.e + old.d * delta.f + old.f;
        
                transform.d = old.b * delta.c + old.d * delta.d;
                transform.f = old.b * delta.e + old.d * delta.f + old.f;
        
-               Debug("New transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f);
+               //Debug("New transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f);
        }
 }
 
 void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
 {
        }
 }
 
 void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
 {
-       Debug("Parse node <%s>", root.name());
+       //Debug("Parse node <%s>", root.name());
 
                
        for (pugi::xml_node child = root.first_child(); child; child = child.next_sibling())
 
                
        for (pugi::xml_node child = root.first_child(); child; child = child.next_sibling())
@@ -818,7 +818,8 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
        int num_instructions = stbtt_GetGlyphShape(font, glyph_index, &instructions);
 
        Real current_x(0), current_y(0);
        int num_instructions = stbtt_GetGlyphShape(font, glyph_index, &instructions);
 
        Real current_x(0), current_y(0);
-
+       unsigned start_index = m_count;
+       unsigned end_index = m_count;
        for (int i = 0; i < num_instructions; ++i)
        {
                // TTF uses 16-bit signed ints for coordinates:
        for (int i = 0; i < num_instructions; ++i)
        {
                // TTF uses 16-bit signed ints for coordinates:
@@ -831,7 +832,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
                Real old_x(current_x), old_y(current_y);
                current_x = inst_x;
                current_y = inst_y;
                Real old_x(current_x), old_y(current_y);
                current_x = inst_x;
                current_y = inst_y;
-               //unsigned bezier_index;
+               
                switch(instructions[i].type)
                {
                // Move To
                switch(instructions[i].type)
                {
                // Move To
@@ -839,8 +840,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
                        break;
                // Line To
                case STBTT_vline:
                        break;
                // Line To
                case STBTT_vline:
-                       AddBezier(Bezier(old_x + x, old_y + y, old_x + x, old_y + y, current_x + x, current_y + y, current_x + x, current_y + y));
-                       //Add(BEZIER,Rect(0,0,1,1),bezier_index);
+                       end_index = AddBezier(Bezier(old_x + x, old_y + y, old_x + x, old_y + y, current_x + x, current_y + y, current_x + x, current_y + y));
                        break;
                // Quadratic Bezier To:
                case STBTT_vcurve:
                        break;
                // Quadratic Bezier To:
                case STBTT_vcurve:
@@ -848,11 +848,16 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
                        // - Endpoints are the same.
                        // - cubic1 = quad0+(2/3)*(quad1-quad0)
                        // - cubic2 = quad2+(2/3)*(quad1-quad2)
                        // - Endpoints are the same.
                        // - cubic1 = quad0+(2/3)*(quad1-quad0)
                        // - cubic2 = quad2+(2/3)*(quad1-quad2)
-                       AddBezier(Bezier(old_x + x, old_y + y, old_x + Real(2)*(inst_cx-old_x)/Real(3) + x, old_y + Real(2)*(inst_cy-old_y)/Real(3) + y,
+                       end_index = AddBezier(Bezier(old_x + x, old_y + y, old_x + Real(2)*(inst_cx-old_x)/Real(3) + x, old_y + Real(2)*(inst_cy-old_y)/Real(3) + y,
                                                current_x + Real(2)*(inst_cx-current_x)/Real(3) + x, current_y + Real(2)*(inst_cy-current_y)/Real(3) + y, current_x + x, current_y + y));
                        break;
                }
        }
                                                current_x + Real(2)*(inst_cx-current_x)/Real(3) + x, current_y + Real(2)*(inst_cy-current_y)/Real(3) + y, current_x + x, current_y + y));
                        break;
                }
        }
+       
+       if (start_index < m_count && end_index < m_count)
+       {
+               AddGroup(start_index, end_index);
+       }
 
        stbtt_FreeShape(font, instructions);
 }
 
        stbtt_FreeShape(font, instructions);
 }
index 7a0f8cd..ed4db41 100644 (file)
@@ -227,11 +227,12 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view,
                Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target));
                //Debug("%s -> %s via %s", objects.beziers[objects.data_indices[m_indexes[i]]].Str().c_str(), control.Str().c_str(), bounds.Str().c_str());
                // Draw a rectangle around the bezier for debugging the bounds rectangle calculations
                Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target));
                //Debug("%s -> %s via %s", objects.beziers[objects.data_indices[m_indexes[i]]].Str().c_str(), control.Str().c_str(), bounds.Str().c_str());
                // Draw a rectangle around the bezier for debugging the bounds rectangle calculations
+               /*
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, Colour(1,0,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, Colour(1,0,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, Colour(1,0,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, Colour(1,0,0,1));
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
-       
+               */
                // Draw lines between the control points for debugging
                //ObjectRenderer::RenderLineOnCPU((int64_t)control.x0, (int64_t)control.y0, (int64_t)control.x1, (int64_t)control.y1,target);
                //ObjectRenderer::RenderLineOnCPU((int64_t)control.x1, (int64_t)control.y1, (int64_t)control.x2, (int64_t)control.y2,target);
                // Draw lines between the control points for debugging
                //ObjectRenderer::RenderLineOnCPU((int64_t)control.x0, (int64_t)control.y0, (int64_t)control.x1, (int64_t)control.y1,target);
                //ObjectRenderer::RenderLineOnCPU((int64_t)control.x1, (int64_t)control.y1, (int64_t)control.x2, (int64_t)control.y2,target);
@@ -341,15 +342,52 @@ void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, c
                if (m_indexes[i] < first_obj_id) continue;
                if (m_indexes[i] >= last_obj_id) continue;
                
                if (m_indexes[i] < first_obj_id) continue;
                if (m_indexes[i] >= last_obj_id) continue;
                
+               
                Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
                PixelBounds pix_bounds(bounds);
        
 
                Colour c(0.5,0.5,1,1);
                Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
                PixelBounds pix_bounds(bounds);
        
 
                Colour c(0.5,0.5,1,1);
+               // make the bounds just a little bit bigger
+               pix_bounds.x--;
+               pix_bounds.w++;
+               pix_bounds.y--;
+               pix_bounds.h++;
+               /*
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, c);
                ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
+               */
+               // Attempt to shade the region
+               // Assumes the outline has been drawn first...
+               for (int64_t y = max((int64_t)0, pix_bounds.y); y <= min(pix_bounds.y+pix_bounds.h, target.h-1); ++y)
+               {
+                       bool inside = false;
+                       bool online = false;
+                       for (int64_t x = max((int64_t)0, pix_bounds.x); x <= min(pix_bounds.x+pix_bounds.w, target.w-1); ++x)
+                       {
+                               int64_t index = (x+target.w*y)*4;
+                               if (target.pixels[index+0] == 0 && target.pixels[index+1] == 0 && target.pixels[index+2] == 0 && target.pixels[index+3] == 255)
+                               {
+                                       online = true;
+                                       continue;
+                               }
+                               else if (online)
+                               {
+                                       inside = !inside;
+                                       online = false;
+                               }
+                               
+                               if (inside)
+                               {
+                                       target.pixels[index+0] = c.r*255;
+                                       target.pixels[index+1] = c.g*255;
+                                       target.pixels[index+2] = c.b*255;
+                                       target.pixels[index+3] = c.a*255;
+                               }
+                       }
+               }
                
        
        }       
                
        
        }       
index e3872b0..70339e7 100644 (file)
@@ -136,6 +136,8 @@ namespace IPDF
                        GroupRenderer() : ObjectRenderer(GROUP, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
                        virtual ~GroupRenderer() {}
                        virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
                        GroupRenderer() : ObjectRenderer(GROUP, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
                        virtual ~GroupRenderer() {}
                        virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
+                       // do nothing on GPU
+                       virtual void RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) {}
        };
        
 }
        };
        
 }
index 27675d5..f075684 100644 (file)
@@ -18,7 +18,9 @@ static void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum
 {
        // Don't print out gl Errors we generated.
        if (source == GL_DEBUG_SOURCE_APPLICATION) return;
 {
        // Don't print out gl Errors we generated.
        if (source == GL_DEBUG_SOURCE_APPLICATION) return;
-       Error("OpenGL Error (%d): %s", id, msg);
+       //Error("OpenGL Error (%d): %s", id, msg);
+       // Spams this message on fglrx, disabling for now because it's damn annoying.
+       // ERROR: opengl_debug_callback (screen.cpp:21) - OpenGL Error (1011): glObjectLabel failed because (depending on the operation) a referenced binding point is empty; a referenced name is not the name of an object; or the given name is otherwise not valid to this operation (GL_INVALID_VALUE)
 }
 
 
 }
 
 
diff --git a/src/svg-tests/cubicbeziers.svg b/src/svg-tests/cubicbeziers.svg
new file mode 100644 (file)
index 0000000..9597357
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="580.2168"
+   height="628.40479"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="cubicbeziers.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.979899"
+     inkscape:cx="238.97518"
+     inkscape:cy="593.69099"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1366"
+     inkscape:window-height="692"
+     inkscape:window-x="1280"
+     inkscape:window-y="280"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-25.625,-34.073881)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 140,180.93361 C 12.857141,-46.209249 357.71463,165.18237 25.714285,112.36218"
+       id="path2985"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 380.35613,179.82644 c -137.24439,-190.777369 508.57143,-69.28571 70,2.14286"
+       id="path2985-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 140.72388,285.19636 C 1.0445869,95.551229 109.42999,427.06216 181.42946,261.07525"
+       id="path2985-1-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 347.85731,304.91858 C 431.42173,164.77092 446.8731,426.58132 536.04516,266.65533"
+       id="path2985-1-6-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 107.93659,486.26514 C 191.50101,346.11748 69.571636,281.64861 166.82491,472.24555"
+       id="path2985-1-6-2-5"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 425.12449,419.71135 c 83.56442,-140.14766 190.93968,60.04344 -50.20815,55.68094"
+       id="path2985-1-6-2-5-5"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 84.401896,615.05664 C 238.677,694.11208 24.823746,388.21676 226.12273,658.61575"
+       id="path2985-1-6-2-5-5-5"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 367.54579,602.1648 C 175.33857,815.57053 683.74439,370.27416 508.25647,614.40918"
+       id="path2985-1-6-2-5-5-5-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/src/svg-tests/shape_pathonly.svg b/src/svg-tests/shape_pathonly.svg
new file mode 100644 (file)
index 0000000..0306a61
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- These lines are comments to assist human readability -->
+<svg id="svg_example"
+xmlns="http://www.w3.org/2000/svg"
+version="1.1"
+width="104"
+height="186">
+<!-- The curved region -->
+<path id="curvedshape"
+d = "m 57,185 c 0,0 57,-13 32,-43 -25,-30 -53,2 -25,
+-30 28,-32 52,17 28,-32 -24,-50 -16,44 -35,12
+-19,-32 13,-64 13,-64 0,0 40,-50 -0,-14 -40,36
+-94,68 -59,109 35,41 45,62 45,62 z"
+style = "fill:#ff0000; fill-opacity:0.75;
+stroke:#000000;"/>
+</svg>

UCC git Repository :: git.ucc.asn.au