]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/TextStroke.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / utils / TextStroke.java
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/TextStroke.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/TextStroke.java
new file mode 100644 (file)
index 0000000..69e0042
--- /dev/null
@@ -0,0 +1,172 @@
+/*\r
+Copyright 2006 Jerry Huxtable\r
+\r
+Licensed under the Apache License, Version 2.0 (the "License");\r
+you may not use this file except in compliance with the License.\r
+You may obtain a copy of the License at\r
+\r
+   http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+Unless required by applicable law or agreed to in writing, software\r
+distributed under the License is distributed on an "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+See the License for the specific language governing permissions and\r
+limitations under the License.\r
+ */\r
+\r
+package org.simantics.scenegraph.utils;\r
+\r
+import java.awt.Font;\r
+import java.awt.Shape;\r
+import java.awt.Stroke;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.font.GlyphVector;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.FlatteningPathIterator;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.PathIterator;\r
+import java.awt.geom.Point2D;\r
+\r
+/**\r
+ * Taken from http://www.jhlabs.com/java/java2d/strokes/\r
+ */\r
+public class TextStroke implements Stroke {\r
+    private final String text;\r
+    private final Font font;\r
+    private boolean stretchToFit = false;\r
+    private boolean repeat = false;\r
+    private final AffineTransform t = new AffineTransform();\r
+\r
+    private static final float FLATNESS = 1;\r
+\r
+    public TextStroke( String text, Font font ) {\r
+        this( text, font, true, false );\r
+    }\r
+\r
+    public TextStroke( String text, Font font, boolean stretchToFit, boolean repeat ) {\r
+        this.text = text;\r
+        this.font = font;\r
+        this.stretchToFit = stretchToFit;\r
+        this.repeat = repeat;\r
+    }\r
+\r
+    @Override\r
+    public Shape createStrokedShape( Shape shape ) {\r
+        FontRenderContext frc = new FontRenderContext(null, true, true);\r
+        GlyphVector glyphVector = font.createGlyphVector(frc, text);\r
+\r
+        GeneralPath result = new GeneralPath();\r
+        PathIterator it = new FlatteningPathIterator( shape.getPathIterator( null ), FLATNESS );\r
+        float points[] = new float[6];\r
+        float moveX = 0, moveY = 0;\r
+        float lastX = 0, lastY = 0;\r
+        float thisX = 0, thisY = 0;\r
+        int type = 0;\r
+        @SuppressWarnings("unused")\r
+               boolean first = false;\r
+        float next = 0;\r
+        int currentChar = 0;\r
+        int length = glyphVector.getNumGlyphs();\r
+\r
+        if ( length == 0 )\r
+            return result;\r
+\r
+        float factor = stretchToFit ? measurePathLength( shape )/(float)glyphVector.getLogicalBounds().getWidth() : 1.0f;\r
+        float nextAdvance = 0;\r
+\r
+        while ( currentChar < length && !it.isDone() ) {\r
+            type = it.currentSegment( points );\r
+            switch( type ){\r
+                case PathIterator.SEG_MOVETO:\r
+                    moveX = lastX = points[0];\r
+                    moveY = lastY = points[1];\r
+                    result.moveTo( moveX, moveY );\r
+                    first = true;\r
+                    nextAdvance = glyphVector.getGlyphMetrics( currentChar ).getAdvance() * 0.5f;\r
+                    next = nextAdvance;\r
+                    break;\r
+\r
+                case PathIterator.SEG_CLOSE:\r
+                    points[0] = moveX;\r
+                    points[1] = moveY;\r
+                    // Fall into....\r
+\r
+                case PathIterator.SEG_LINETO:\r
+                    thisX = points[0];\r
+                    thisY = points[1];\r
+                    float dx = thisX-lastX;\r
+                    float dy = thisY-lastY;\r
+                    float distance = (float)Math.sqrt( dx*dx + dy*dy );\r
+                    if ( distance >= next ) {\r
+                        float r = 1.0f/distance;\r
+                        float angle = (float)Math.atan2( dy, dx );\r
+                        while ( currentChar < length && distance >= next ) {\r
+                            Shape glyph = glyphVector.getGlyphOutline( currentChar );\r
+                            Point2D p = glyphVector.getGlyphPosition(currentChar);\r
+                            float px = (float)p.getX();\r
+                            float py = (float)p.getY();\r
+                            float x = lastX + next*dx*r;\r
+                            float y = lastY + next*dy*r;\r
+                            float advance = nextAdvance;\r
+                            nextAdvance = currentChar < length-1 ? glyphVector.getGlyphMetrics(currentChar+1).getAdvance() * 0.5f : 0;\r
+                            t.setToTranslation( x, y );\r
+                            t.rotate( angle );\r
+                            t.translate( -px-advance, -py );\r
+                            result.append( t.createTransformedShape( glyph ), false );\r
+                            next += (advance+nextAdvance) * factor;\r
+                            currentChar++;\r
+                            if ( repeat )\r
+                                currentChar %= length;\r
+                        }\r
+                    }\r
+                    next -= distance;\r
+                    first = false;\r
+                    lastX = thisX;\r
+                    lastY = thisY;\r
+                    break;\r
+            }\r
+            it.next();\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+    public float measurePathLength( Shape shape ) {\r
+        PathIterator it = new FlatteningPathIterator( shape.getPathIterator( null ), FLATNESS );\r
+        float points[] = new float[6];\r
+        float moveX = 0, moveY = 0;\r
+        float lastX = 0, lastY = 0;\r
+        float thisX = 0, thisY = 0;\r
+        int type = 0;\r
+        float total = 0;\r
+\r
+        while ( !it.isDone() ) {\r
+            type = it.currentSegment( points );\r
+            switch( type ){\r
+                case PathIterator.SEG_MOVETO:\r
+                    moveX = lastX = points[0];\r
+                    moveY = lastY = points[1];\r
+                    break;\r
+\r
+                case PathIterator.SEG_CLOSE:\r
+                    points[0] = moveX;\r
+                    points[1] = moveY;\r
+                    // Fall into....\r
+\r
+                case PathIterator.SEG_LINETO:\r
+                    thisX = points[0];\r
+                    thisY = points[1];\r
+                    float dx = thisX-lastX;\r
+                    float dy = thisY-lastY;\r
+                    total += (float)Math.sqrt( dx*dx + dy*dy );\r
+                    lastX = thisX;\r
+                    lastY = thisY;\r
+                    break;\r
+            }\r
+            it.next();\r
+        }\r
+\r
+        return total;\r
+    }\r
+\r
+}
\ No newline at end of file