root/OpenSceneGraph/trunk/examples/osgtext3D/osgtext3D.cpp @ 11679

Revision 11679, 12.1 kB (checked in by robert, 4 years ago)

Added computeIntersectionPoint and computeBisectorNormal functions

Line 
1/* OpenSceneGraph example, osgtext.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/ArgumentParser>
20#include <osg/Geode>
21#include <osg/Geometry>
22#include <osg/PositionAttitudeTransform>
23#include <osgText/Font3D>
24#include <osgDB/WriteFile>
25#include <osgGA/StateSetManipulator>
26#include <osgUtil/Tessellator>
27#include <osgViewer/Viewer>
28#include <osgViewer/ViewerEventHandlers>
29#include <osg/io_utils>
30
31extern int main_orig(int, char**);
32extern int main_test(int, char**);
33
34osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
35{
36    float ba_x = b.x()-a.x();
37    float ba_y = b.y()-a.y();
38
39    float dc_x = d.x()-c.x();
40    float dc_y = d.y()-c.y();
41
42    float denominator = (dc_x * ba_y - dc_y * ba_x);
43    if (denominator==0.0)
44    {
45        // line segments must be parallel.
46        return (b+c)*0.5;
47    }
48
49    float t = ((a.x()-c.x())*ba_y + (a.y()-c.y())*ba_x) / denominator;
50
51    return c + (d-c)*t;
52}
53
54osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
55{
56    osg::Vec2 ab(a.x()-b.x(), a.y()-b.y());
57    osg::Vec2 dc(d.x()-c.x(), d.y()-c.y());
58    float length_ab = ab.normalize();
59    float length_dc = dc.normalize();
60    float denominator = (ab.x()-dc.x());
61    if (denominator==0.0)
62    {
63        // ab and cd parallel
64        return osg::Vec3(ab.y(), -ab.x(), 0.0f);
65    }
66    float r = (dc.x()-ab.y())/ denominator;
67    float ny = 1.0f / sqrtf(r*r + 1.0f);
68    float nx = r * ny;
69
70    return osg::Vec3(nx,ny,0.0f);
71}
72
73class Boundary
74{
75    typedef std::vector<unsigned int>   Points;
76    typedef std::vector<float>          Distances;
77    typedef std::vector<osg::Vec3>      Bisectors;
78
79    struct Segment : public osg::Referenced
80    {
81        unsigned int            _p1;
82        unsigned int            _p2;
83        Segment*                _left;
84        osg::ref_ptr<Segment>   _right;
85        float                   _distance;
86    };
87
88    osg::ref_ptr<Segment>  _head;
89
90    osg::ref_ptr<osg::Vec3Array> _vertices;
91    Bisectors                   _bisectors;
92    Points                      _boundary;
93    Distances                   _distances;
94};
95
96
97float computeAngle(osg::Vec3& v1, osg::Vec3& v2, osg::Vec3& v3)
98{
99    osg::Vec3 v12(v1-v2);
100    osg::Vec3 v32(v3-v2);
101    v12.normalize();
102    v32.normalize();
103    float dot = v12*v32;
104    float angle = acosf(dot);
105    return angle;
106}
107
108void computeBoundaryAngles(osg::Vec3Array& vertices, unsigned int start, unsigned int count)
109{
110    OSG_NOTICE<<"computeBoundaryAngles("<<vertices.size()<<", "<<start<<", "<<count<<")"<<std::endl;
111    if (vertices[start+count-1]==vertices[start])
112    {
113        OSG_NOTICE<<"is a line loop"<<std::endl;
114    }
115    else
116    {
117        OSG_NOTICE<<"is not line loop, ("<<vertices[start+count-1]<<"), ("<<vertices[start]<<")"<<std::endl;
118        return;
119    }
120
121    computeAngle(vertices[start+count-2],vertices[start],vertices[start+1]);
122    for(unsigned int i=start+1; i<start+count-1; ++i)
123    {
124        computeAngle(vertices[i-1],vertices[i],vertices[i+1]);
125    }
126    computeAngle(vertices[start+count-2],vertices[start],vertices[start+1]);
127}
128
129void computeBoundaryAngles(osg::Geometry* geometry)
130{
131    OSG_NOTICE<<"computeBoundaryAngles("<<geometry<<")"<<std::endl;
132    osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
133    osg::Geometry::PrimitiveSetList& primitives = geometry->getPrimitiveSetList();
134    for(osg::Geometry::PrimitiveSetList::iterator itr = primitives.begin();
135        itr != primitives.end();
136        ++itr)
137    {
138        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
139        if (drawArray && drawArray->getMode()==GL_POLYGON)
140        {
141            computeBoundaryAngles(*vertices, drawArray->getFirst(), drawArray->getCount());
142        }
143    }
144}
145
146osg::Vec3 computeNewVertexPosition(osg::Vec3& v1, osg::Vec3& v2, osg::Vec3& v3)
147{
148    double angle = computeAngle(v1,v2,v3);
149    osg::Vec3 v21(v2-v1);
150    osg::Vec3 v32(v3-v2);
151    float length_21 = v21.normalize();
152    float length_32 = v32.normalize();
153
154    float t = 5.0;
155    if (length_21==0.0)
156    {
157        OSG_NOTICE<<"length_21=="<<length_21<<", length_32="<<length_32<<std::endl;
158        osg::Vec3 bisector = v32 ^ osg::Vec3(0.0f,0.0f,1.0f);
159        bisector.normalize();
160        osg::Vec3 new_vertex = v2 + bisector * t;
161        return new_vertex;
162    }
163    else if (length_32==0.0)
164    {
165        OSG_NOTICE<<"length_21=="<<length_21<<", length_32="<<length_32<<std::endl;
166        osg::Vec3 bisector = v21 ^ osg::Vec3(0.0f,0.0f,1.0f);
167        bisector.normalize();
168        osg::Vec3 new_vertex = v2 + bisector * t;
169        return new_vertex;
170    }
171
172    osg::Vec3 cross = v21^v32;
173    osg::Vec3 bisector(v32-v21);
174
175
176    OSG_NOTICE<<"v1="<<v1<<", v2="<<v2<<", v3="<<v3<<", dot_angle="<<osg::RadiansToDegrees(angle)<<std::endl;
177    OSG_NOTICE<<"     computeIntersectionPoint() point "<<computeIntersectionPoint(v1,v2,v2,v3)<<std::endl;
178    OSG_NOTICE<<"     computeBisectorNormal() normal "<<computeBisectorNormal(v1,v2,v2,v3)<<std::endl;
179   
180    if (bisector.length()<0.5)
181    {
182        // angle wider than 90 degrees so use side vectors as guide for angle to project along.
183        osg::Vec3 s21 = v21 ^ osg::Vec3(0.0f,0.0f,1.0f);
184        s21.normalize();
185
186        osg::Vec3 s32 = v32 ^ osg::Vec3(0.0f,0.0f,1.0f);
187        s32.normalize();
188
189        osg::Vec3 bisector(s21+s32);
190        bisector.normalize();
191
192        OSG_NOTICE<<"     bisector normal "<<computeBisectorNormal(v1,v2,v2,v3)<<std::endl;
193
194        float l = t / sin(angle*0.5);
195
196        osg::Vec3 new_vertex = v2 + bisector * l;
197        new_vertex.z() += 0.5f;
198
199        return new_vertex;
200    }
201    else
202    {
203        float l = t / sin(angle*0.5);
204
205        bisector.normalize();
206        if (cross.z()>0.0) bisector = -bisector;
207
208        OSG_NOTICE<<"     bisector normal "<<computeBisectorNormal(v1,v2,v2,v3)<<std::endl;
209
210        osg::Vec3 new_vertex = v2 + bisector * l;
211        new_vertex.z() += 0.5f;
212        return new_vertex;
213    }
214}
215
216osg::DrawArrays* computeBevelEdge(osg::Vec3Array& orig_vertices, unsigned int start, unsigned int count, osg::Vec3Array& new_vertices)
217{
218    OSG_NOTICE<<"computeBoundaryAngles("<<orig_vertices.size()<<", "<<start<<", "<<count<<")"<<std::endl;
219    if (orig_vertices[start+count-1]==orig_vertices[start])
220    {
221        OSG_NOTICE<<"is a line loop"<<std::endl;
222    }
223    else
224    {
225        OSG_NOTICE<<"is not line loop, ("<<orig_vertices[start+count-1]<<"), ("<<orig_vertices[start]<<")"<<std::endl;
226        return new osg::DrawArrays(GL_POLYGON, start, count);
227    }
228
229    new_vertices[start] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
230    for(unsigned int i=start+1; i<start+count-1; ++i)
231    {
232        new_vertices[i] = computeNewVertexPosition(orig_vertices[i-1],orig_vertices[i],orig_vertices[i+1]);
233    }
234    new_vertices[start+count-1] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
235
236    return new osg::DrawArrays(GL_POLYGON, start, count);
237}
238
239void removeLoops(osg::Vec3Array& orig_vertices, unsigned int start, unsigned int count)
240{
241}
242
243osg::Geometry* computeBevelEdge(osg::Geometry* orig_geometry)
244{
245    OSG_NOTICE<<"computeBoundaryAngles("<<orig_geometry<<")"<<std::endl;
246    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(orig_geometry->getVertexArray());
247    osg::Geometry::PrimitiveSetList& orig_primitives = orig_geometry->getPrimitiveSetList();
248
249    osg::Geometry* new_geometry = new osg::Geometry;
250    osg::Vec3Array* new_vertices = new osg::Vec3Array(*orig_vertices);
251    osg::Geometry::PrimitiveSetList& new_primitives = new_geometry->getPrimitiveSetList();
252    new_geometry->setVertexArray(new_vertices);
253    osg::Vec4Array* new_colours = new osg::Vec4Array;
254    new_colours->push_back(osg::Vec4(1.0,0.0,0.0,1.0));
255    new_geometry->setColorArray(new_colours);
256    new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
257
258    for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
259        itr != orig_primitives.end();
260        ++itr)
261    {
262        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
263        if (drawArray && drawArray->getMode()==GL_POLYGON)
264        {
265            osg::DrawArrays* new_drawArray = computeBevelEdge(*orig_vertices, drawArray->getFirst(), drawArray->getCount(), *new_vertices);
266            removeLoops(*new_vertices, new_drawArray->getFirst(), new_drawArray->getCount());
267            new_primitives.push_back(new_drawArray);
268        }
269    }
270    return new_geometry;
271}
272
273int main(int argc, char** argv)
274{
275    osg::ArgumentParser arguments(&argc, argv);
276
277    if (arguments.read("--test"))
278    {
279        return main_test(argc,argv);
280    }
281    else if (arguments.read("--original") || arguments.read("--orig"))
282    {
283        return main_orig(argc,argv);
284    }
285
286    std::string fontFile("arial.ttf");
287    while(arguments.read("-f",fontFile)) {}
288
289    std::string word("This is a simple test");
290    while(arguments.read("-w",word)) {}
291
292    osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
293    if (!font) return 1;
294    OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
295
296
297    bool useTessellator = false;
298    while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
299
300    osg::ref_ptr<osg::Group> group = new osg::Group;
301    osg::Vec3 position;
302
303    for(unsigned int i=0; i<word.size(); ++i)
304    {
305        osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
306        if (!glyph) return 1;
307
308        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
309        transform->setPosition(position);
310        transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
311
312        position.x() += glyph->getHorizontalWidth();
313
314        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
315
316        osg::Vec3Array* vertices = glyph->getRawVertexArray();
317        osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList();
318
319        osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
320        geometry->setVertexArray(vertices);
321        geometry->setPrimitiveSetList(primitives);
322        osg::Vec4Array* colours = new osg::Vec4Array;
323        colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
324        geometry->setColorArray(colours);
325        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
326
327        computeBoundaryAngles(geometry);
328
329        osg::Geometry* bevel = computeBevelEdge(geometry);
330        geode->addDrawable(bevel);
331
332        if (useTessellator)
333        {
334            osgUtil::Tessellator ts;
335            ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
336            ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
337            ts.retessellatePolygons(*geometry);
338
339            ts.retessellatePolygons(*bevel);
340
341        }
342
343        geode->addDrawable(geometry.get());
344
345        transform->addChild(geode.get());
346
347        group->addChild(transform.get());
348    }
349
350    std::string filename;
351    if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
352
353    osgViewer::Viewer viewer(arguments);
354    viewer.setSceneData(group.get());
355    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
356    return viewer.run();
357}
Note: See TracBrowser for help on using the browser.