/src/libmwaw/src/lib/Canvas5Graph.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <array> |
35 | | #include <cmath> |
36 | | #include <iomanip> |
37 | | #include <iostream> |
38 | | #include <limits> |
39 | | #include <map> |
40 | | #include <set> |
41 | | #include <sstream> |
42 | | #include <stack> |
43 | | |
44 | | #include <librevenge/librevenge.h> |
45 | | |
46 | | #include "MWAWFont.hxx" |
47 | | #include "MWAWFontConverter.hxx" |
48 | | #include "MWAWGraphicListener.hxx" |
49 | | #include "MWAWGraphicShape.hxx" |
50 | | #include "MWAWGraphicStyle.hxx" |
51 | | #include "MWAWListener.hxx" |
52 | | #include "MWAWParagraph.hxx" |
53 | | #include "MWAWParser.hxx" |
54 | | #include "MWAWPictBitmap.hxx" |
55 | | #include "MWAWPictMac.hxx" |
56 | | #include "MWAWPosition.hxx" |
57 | | #include "MWAWSubDocument.hxx" |
58 | | |
59 | | #include "Canvas5Parser.hxx" |
60 | | |
61 | | #include "Canvas5Graph.hxx" |
62 | | #include "Canvas5Image.hxx" |
63 | | #include "Canvas5Structure.hxx" |
64 | | #include "Canvas5StyleManager.hxx" |
65 | | |
66 | | #include "libmwaw_internal.hxx" |
67 | | |
68 | | /** Internal: the structures of a Canvas5Graph */ |
69 | | namespace Canvas5GraphInternal |
70 | | { |
71 | | //! Internal: the section data |
72 | | struct SectionData { |
73 | | //! constructor |
74 | | SectionData() |
75 | 0 | : m_numColumns(1) |
76 | 0 | , m_bdBox() |
77 | 0 | { |
78 | 0 | } |
79 | | //! the number of columns |
80 | | int m_numColumns; |
81 | | //! the bounding box |
82 | | MWAWBox2f m_bdBox; |
83 | | }; |
84 | | |
85 | | //! Internal: the shape data |
86 | | struct ShapeData { |
87 | | //! constructor |
88 | | ShapeData() |
89 | 0 | : m_inMainZone(true) |
90 | 0 | , m_type(0) |
91 | 0 | , m_stream() |
92 | 0 | , m_streamReverted(false) |
93 | 0 | , m_entry() |
94 | 0 | , m_vertices() |
95 | 0 | , m_children() |
96 | 0 | , m_macoId() |
97 | | |
98 | 0 | , m_grid(1,1) |
99 | 0 | , m_ngonType(4) |
100 | | |
101 | 0 | , m_gdeType(0) |
102 | 0 | , m_sections() |
103 | 0 | { |
104 | 0 | for (auto &l : m_local) l=0; |
105 | 0 | for (auto &i : m_ids) i=0; |
106 | 0 | for (auto &s : m_shapeIds) s=0; |
107 | 0 | for (auto &s : m_specials) s=0; |
108 | 0 | for (auto &e : m_cweb) e=MWAWEntry(); |
109 | 0 | for (auto &d : m_doubleValues) d=0; |
110 | 0 | } |
111 | | //! returns the data stream |
112 | | Canvas5Structure::Stream &getStream() const |
113 | 0 | { |
114 | 0 | if (!m_stream || !m_stream->input()) { |
115 | 0 | MWAW_DEBUG_MSG(("Canvas5GraphInternal::ShapeData::getStream: no input stream\n")); |
116 | 0 | throw libmwaw::ParseException(); |
117 | 0 | } |
118 | 0 | m_stream->input()->setReadInverted(m_streamReverted); |
119 | 0 | return *m_stream; |
120 | 0 | } |
121 | | //! operator<< |
122 | | friend std::ostream &operator<<(std::ostream &o, ShapeData const &s) |
123 | 0 | { |
124 | 0 | for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_local)); ++i) { |
125 | 0 | if (s.m_local[i]) o << "l" << i << "=" << s.m_local[i] << ","; |
126 | 0 | } |
127 | 0 | for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_ids)); ++i) { |
128 | 0 | if (!s.m_ids[i]) continue; |
129 | 0 | char const *wh[]= {"TL", "Mat", "Str"}; |
130 | 0 | o << wh[i] << s.m_ids[i] << ","; |
131 | 0 | } |
132 | 0 | for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_shapeIds)); ++i) { |
133 | 0 | if (!s.m_shapeIds[i]) continue; |
134 | 0 | char const *wh[]= {"child", "parent", "shape1", "shape2"}; |
135 | 0 | o << wh[i] << "=S" << s.m_shapeIds[i] << ","; |
136 | 0 | } |
137 | 0 | return o; |
138 | 0 | } |
139 | | //! a flag to know if the shape is in the main zone or in Vkfl |
140 | | bool m_inMainZone; |
141 | | //! the shape type |
142 | | unsigned m_type; |
143 | | //! the data stream |
144 | | std::shared_ptr<Canvas5Structure::Stream> m_stream; |
145 | | //! a flag to know the stream endian |
146 | | bool m_streamReverted; |
147 | | //! the shape data entry |
148 | | MWAWEntry m_entry; |
149 | | //! the local variable |
150 | | int m_local[2]; |
151 | | //! the text link, matrix, name id |
152 | | unsigned m_ids[3]; |
153 | | //! the shape ids |
154 | | unsigned m_shapeIds[4]; |
155 | | |
156 | | //! the shape vertices: line, ... |
157 | | std::vector<MWAWVec2f> m_vertices; |
158 | | //! the childs: group |
159 | | std::vector<unsigned> m_children; |
160 | | //! the macro Id: MACO |
161 | | std::vector<unsigned> m_macoId; |
162 | | |
163 | | // special |
164 | | |
165 | | //! the grid subdivision |
166 | | MWAWVec2i m_grid; |
167 | | //! some special values |
168 | | int m_specials[4]; |
169 | | //! the buttons image entries |
170 | | MWAWEntry m_cweb[3]; |
171 | | //! the n-polygon type: NGON |
172 | | int m_ngonType; |
173 | | //! the #Gde type |
174 | | int m_gdeType; |
175 | | //! the sections: #Gde |
176 | | std::vector<SectionData> m_sections; |
177 | | //! the arc angles or rect oval size: v9 |
178 | | double m_doubleValues[4]; |
179 | | }; |
180 | | |
181 | | //! Internal: the shape of a Canvas5Graph |
182 | | struct Shape { |
183 | | //! constructor |
184 | | Shape() |
185 | 0 | : m_type(-1) |
186 | 0 | , m_id(0) |
187 | 0 | , m_initialBox() |
188 | 0 | , m_bdbox() |
189 | | , m_pos() |
190 | 0 | , m_sent(false) |
191 | 0 | { |
192 | 0 | for (auto &f : m_flags) f=0; |
193 | 0 | for (auto &v : m_values) v=0; |
194 | 0 | } |
195 | | |
196 | | //! returns the type name |
197 | | std::string getTypeName() const |
198 | 0 | { |
199 | 0 | static std::map<int, std::string> const s_typeName= { |
200 | 0 | {2,"text"}, |
201 | 0 | {3,"line"}, |
202 | 0 | {4,"rect"}, |
203 | 0 | {5,"rectOval"}, |
204 | 0 | {6,"oval"}, |
205 | 0 | {7,"arc"}, |
206 | 0 | {9,"polyline"}, |
207 | 0 | {10,"spline"}, |
208 | 0 | {52,"special"}, |
209 | 0 | {99,"group"}, |
210 | 0 | {100,"none"} |
211 | 0 | }; |
212 | 0 | auto const &it=s_typeName.find(m_type); |
213 | 0 | if (it!=s_typeName.end()) |
214 | 0 | return it->second; |
215 | 0 | std::stringstream s; |
216 | 0 | s << "Type" << m_type << "A"; |
217 | 0 | return s.str(); |
218 | 0 | } |
219 | | |
220 | | //! operator<< |
221 | | friend std::ostream &operator<<(std::ostream &o, Shape const &s) |
222 | 0 | { |
223 | 0 | o << s.getTypeName() << ","; |
224 | 0 | o << s.m_bdbox << ","; |
225 | 0 | if (s.m_bdbox!=s.m_initialBox) |
226 | 0 | o << "bdbox[orig]=" << s.m_initialBox << ","; |
227 | 0 | if (s.m_type!=100 && s.m_pos>=0) |
228 | 0 | o << "data=" << std::hex << s.m_pos << std::dec << ","; |
229 | 0 | if (s.m_flags[0]) { |
230 | 0 | if (s.m_flags[0]&1) o << "locked,"; |
231 | 0 | if (s.m_flags[0]&4) o << "noPrint,"; |
232 | 0 | if (s.m_flags[0]&0x200) o << "spread[trap],"; |
233 | 0 | if (s.m_flags[0]&0x400) o << "overPrint,"; |
234 | 0 | if (s.m_flags[0]&0x800) o << "trap[choke],"; |
235 | 0 | int val=(s.m_flags[0]&0xf1fa); |
236 | 0 | if (val) |
237 | 0 | o << "fl=" << std::hex << val << std::dec << ","; |
238 | 0 | } |
239 | 0 | if (s.m_flags[1]) { |
240 | 0 | if (s.m_flags[1]&1) o << "parent,"; |
241 | 0 | if (s.m_flags[1]&2) o << "shape1,"; |
242 | 0 | if (s.m_flags[1]&4) o << "shape2,"; |
243 | 0 | if (s.m_flags[1]&8) o << "rot,"; |
244 | 0 | int val=(s.m_flags[1]&0xfff9); |
245 | 0 | if (val) |
246 | 0 | o << "fl1=" << std::hex << val << std::dec << ","; |
247 | 0 | } |
248 | 0 | if (s.m_flags[2]) { |
249 | 0 | if ((s.m_flags[2]&0x1)==0) o << "no[size],"; |
250 | 0 | if (s.m_flags[2]&0x4) o << "txtPlc[id],"; |
251 | 0 | if (s.m_flags[2]&0x10) o << "mat,"; |
252 | 0 | if (s.m_flags[2]&0x20) o << "type,"; |
253 | 0 | if (s.m_flags[2]&0x80) o << "shape[id],"; |
254 | 0 | if (s.m_flags[2]&0x200) o << "loc1,"; |
255 | 0 | if (s.m_flags[2]&0x400) o << "loc2,"; |
256 | 0 | if (s.m_flags[2]&0x800) o << "name,"; |
257 | 0 | int val=(s.m_flags[2]&0xf1ca); |
258 | 0 | if (val) |
259 | 0 | o << "fl2=" << std::hex << val << std::dec << ","; |
260 | 0 | } |
261 | 0 | for (int i=0; i<int(MWAW_N_ELEMENTS(s.m_values)); ++i) { |
262 | 0 | int val=s.m_values[i]; |
263 | 0 | if (val==0) continue; |
264 | 0 | char const *wh[]= {nullptr, "col[surf]=Co", "col[line]=Co", "stroke=St"}; |
265 | 0 | if (wh[i]) |
266 | 0 | o << wh[i] << val << ","; |
267 | 0 | else |
268 | 0 | o << "f" << i << "=" << val << ","; |
269 | 0 | } |
270 | 0 | return o; |
271 | 0 | } |
272 | | //! the shape type |
273 | | int m_type; |
274 | | //! the shape id |
275 | | int m_id; |
276 | | //! the original box |
277 | | MWAWBox2f m_initialBox; |
278 | | //! the bounding box |
279 | | MWAWBox2f m_bdbox; |
280 | | //! the beginning position |
281 | | long m_pos; |
282 | | //! some unknown value |
283 | | int m_values[4]; |
284 | | //! some unknown flag |
285 | | int m_flags[3]; |
286 | | //! a flag to know if the shape is already send |
287 | | mutable bool m_sent; |
288 | | }; |
289 | | |
290 | | //! Internal[low level]: a pseudo class to store the data corresponding to a shape |
291 | | struct PseudoShape { |
292 | | //! constructor |
293 | | PseudoShape() |
294 | 0 | : m_shape() |
295 | 0 | , m_data() |
296 | 0 | { |
297 | 0 | } |
298 | | |
299 | | //! the shape |
300 | | Shape m_shape; |
301 | | //! the data shape |
302 | | ShapeData m_data; |
303 | | }; |
304 | | |
305 | | //////////////////////////////////////// |
306 | | //! Internal: the state of a Canvas5Graph |
307 | | struct State { |
308 | | //! constructor |
309 | | State() |
310 | 6.32k | : m_dataStream() |
311 | 6.32k | , m_dataStreamReverted(false) |
312 | | |
313 | 6.32k | , m_shapeZones() |
314 | 6.32k | , m_idToShapeMap() |
315 | 6.32k | , m_posToShapeDataMap() |
316 | 6.32k | , m_idToMatrices() |
317 | | |
318 | 6.32k | , m_sendIdSet() |
319 | 6.32k | , m_sendAGIFIdSet() |
320 | 6.32k | , m_sendMACOIdSet() |
321 | 6.32k | { |
322 | 6.32k | } |
323 | | |
324 | | //! the data shape stream |
325 | | std::shared_ptr<Canvas5Structure::Stream> m_dataStream; |
326 | | //! a flag to retrieved the data shape entry |
327 | | bool m_dataStreamReverted; |
328 | | |
329 | | //! the shape data zones |
330 | | std::vector<MWAWEntry> m_shapeZones; |
331 | | //! the map id to shape |
332 | | std::map<int, Shape> m_idToShapeMap; |
333 | | //! the map id to shape data |
334 | | std::map<long, ShapeData> m_posToShapeDataMap; |
335 | | //! the map id to matrices |
336 | | std::map<int, std::array<std::array<double, 9>, 2> > m_idToMatrices; |
337 | | |
338 | | //! the list of current send shape id (used to avoid loop) |
339 | | std::set<int> m_sendIdSet; |
340 | | //! the list of current send GIF id (used to avoid loop) |
341 | | std::set<int> m_sendAGIFIdSet; |
342 | | //! the list of current send macro id (used to avoid loop) |
343 | | std::set<std::vector<unsigned> > m_sendMACOIdSet; |
344 | | }; |
345 | | |
346 | | //////////////////////////////////////// |
347 | | //! Internal: the subdocument of a Canvas5Graph |
348 | | class SubDocument final : public MWAWSubDocument |
349 | | { |
350 | | public: |
351 | | //! constructor from a zoneId |
352 | | SubDocument(Canvas5Graph &parser, MWAWInputStreamPtr const &input, Shape const &shape, ShapeData const &data) |
353 | 0 | : MWAWSubDocument(parser.m_mainParser, input, MWAWEntry()) |
354 | 0 | , m_graphParser(parser) |
355 | 0 | , m_shape(&shape) |
356 | 0 | , m_data(&data) |
357 | 0 | , m_measure() |
358 | 0 | , m_font() |
359 | 0 | { |
360 | 0 | } |
361 | | //! constructor from string |
362 | | SubDocument(Canvas5Graph &parser, MWAWInputStreamPtr const &input, librevenge::RVNGString const &measure, MWAWFont const &font) |
363 | 0 | : MWAWSubDocument(parser.m_mainParser, input, MWAWEntry()) |
364 | 0 | , m_graphParser(parser) |
365 | 0 | , m_shape(nullptr) |
366 | 0 | , m_data(nullptr) |
367 | 0 | , m_measure(measure) |
368 | 0 | , m_font(font) |
369 | 0 | { |
370 | 0 | } |
371 | | |
372 | | //! destructor |
373 | 0 | ~SubDocument() final {} |
374 | | |
375 | | //! operator!= |
376 | | bool operator!=(MWAWSubDocument const &doc) const final |
377 | 0 | { |
378 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
379 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
380 | 0 | if (!sDoc) return true; |
381 | 0 | if (&m_graphParser != &sDoc->m_graphParser) return true; |
382 | 0 | if (m_shape != sDoc->m_shape) return true; |
383 | 0 | if (m_data != sDoc->m_data) return true; |
384 | 0 | if (m_measure != sDoc->m_measure) return true; |
385 | 0 | return false; |
386 | 0 | } |
387 | | |
388 | | //! the parser function |
389 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final; |
390 | | |
391 | | protected: |
392 | | //! the graph parser |
393 | | Canvas5Graph &m_graphParser; |
394 | | //! the shape |
395 | | Shape const *m_shape; |
396 | | //! the shape data |
397 | | ShapeData const *m_data; |
398 | | //! the measure |
399 | | librevenge::RVNGString m_measure; |
400 | | //! the font |
401 | | MWAWFont m_font; |
402 | | private: |
403 | | SubDocument(SubDocument const &orig) = delete; |
404 | | SubDocument &operator=(SubDocument const &orig) = delete; |
405 | | }; |
406 | | |
407 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/) |
408 | 0 | { |
409 | 0 | if (!listener || !listener->canWriteText()) { |
410 | 0 | MWAW_DEBUG_MSG(("Canvas5GraphInternal::SubDocument::parse: no listener\n")); |
411 | 0 | return; |
412 | 0 | } |
413 | 0 | if (!m_shape || !m_data) { |
414 | 0 | if (m_measure.empty()) { |
415 | 0 | MWAW_DEBUG_MSG(("Canvas5GraphInternal::SubDocument::parse: can not find the measure\n")); |
416 | 0 | return; |
417 | 0 | } |
418 | 0 | listener->setFont(m_font); |
419 | 0 | MWAWParagraph para; |
420 | 0 | para.m_justify = MWAWParagraph::JustificationCenter; |
421 | 0 | listener->setParagraph(para); |
422 | 0 | listener->insertUnicodeString(m_measure); |
423 | 0 | return; |
424 | 0 | } |
425 | 0 | long pos = m_input ? m_input->tell() : 0; |
426 | 0 | m_graphParser.sendText(listener, *m_shape, *m_data); |
427 | 0 | if (m_input) m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
428 | 0 | } |
429 | | |
430 | | } |
431 | | |
432 | | //////////////////////////////////////////////////////////// |
433 | | // constructor/destructor, ... |
434 | | //////////////////////////////////////////////////////////// |
435 | | Canvas5Graph::Canvas5Graph(Canvas5Parser &parser) |
436 | 6.32k | : m_parserState(parser.getParserState()) |
437 | 6.32k | , m_state(new Canvas5GraphInternal::State) |
438 | 6.32k | , m_mainParser(&parser) |
439 | 6.32k | , m_imageParser(parser.m_imageParser) |
440 | 6.32k | , m_styleManager(parser.m_styleManager) |
441 | 6.32k | { |
442 | 6.32k | } |
443 | | |
444 | | Canvas5Graph::~Canvas5Graph() |
445 | 6.32k | { |
446 | 6.32k | } |
447 | | |
448 | | int Canvas5Graph::version() const |
449 | 0 | { |
450 | 0 | return m_parserState->m_version; |
451 | 0 | } |
452 | | |
453 | | //////////////////////////////////////////////////////////// |
454 | | // |
455 | | // Intermediate level |
456 | | // |
457 | | //////////////////////////////////////////////////////////// |
458 | | |
459 | | bool Canvas5Graph::readMatrices(std::shared_ptr<Canvas5Structure::Stream> stream) |
460 | 0 | { |
461 | 0 | if (!stream) { |
462 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: no stream\n")); |
463 | 0 | return false; |
464 | 0 | } |
465 | 0 | auto input=stream->input(); |
466 | 0 | long pos=input->tell(); |
467 | 0 | if (!input->checkPosition(pos+4)) { |
468 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: the zone is too short\n")); |
469 | 0 | return false; |
470 | 0 | } |
471 | 0 | libmwaw::DebugFile &ascFile = stream->ascii(); |
472 | 0 | pos=input->tell(); |
473 | 0 | libmwaw::DebugStream f; |
474 | 0 | f << "Entries(Matrix):"; |
475 | 0 | if (version()>=9) { |
476 | 0 | ascFile.addPos(pos); |
477 | 0 | ascFile.addNote(f.str().c_str()); |
478 | 0 | return m_mainParser->readArray9(stream, "Matrix", |
479 | 0 | [this](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) { |
480 | 0 | auto lInput=lStream->input(); |
481 | 0 | libmwaw::DebugFile &asciiFile = lStream->ascii(); |
482 | 0 | libmwaw::DebugStream lF; |
483 | 0 | lF << "Mat" << item.m_id << ","; |
484 | 0 | if (item.m_length!=144) { |
485 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: a matrix is too short\n")); |
486 | 0 | lF << "###"; |
487 | 0 | asciiFile.addPos(item.m_pos); |
488 | 0 | asciiFile.addNote(lF.str().c_str()); |
489 | 0 | } |
490 | 0 | lInput->seek(-4, librevenge::RVNG_SEEK_CUR); |
491 | 0 | std::array<std::array<double, 9>, 2> matrices; |
492 | 0 | for (size_t st=0; st<2; ++st) { |
493 | 0 | lF << "mat" << st << "=["; |
494 | 0 | auto &matrix = matrices[st]; |
495 | 0 | for (auto &d : matrix) { |
496 | 0 | d=m_mainParser->readDouble(*lStream, 8); |
497 | 0 | lF << d << ","; |
498 | 0 | } |
499 | 0 | lF << "],"; |
500 | 0 | } |
501 | 0 | m_state->m_idToMatrices[item.m_id]=matrices; |
502 | 0 | asciiFile.addPos(item.m_pos); |
503 | 0 | asciiFile.addNote(lF.str().c_str()); |
504 | 0 | }); |
505 | 0 | } |
506 | 0 | int val=int(input->readLong(4)); |
507 | 0 | if (val!=-1) |
508 | 0 | f << "f0=" << val << ","; |
509 | 0 | ascFile.addPos(pos); |
510 | 0 | ascFile.addNote(f.str().c_str()); |
511 | 0 | if (!m_mainParser->readUsed(*stream, "Matrix")) // size=144 |
512 | 0 | return false; |
513 | 0 | return m_mainParser->readExtendedHeader(stream, 0x48, "Matrix", |
514 | 0 | [this](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) { |
515 | 0 | auto lInput=lStream->input(); |
516 | 0 | libmwaw::DebugFile &asciiFile = lStream->ascii(); |
517 | 0 | libmwaw::DebugStream lF; |
518 | 0 | lF << "Mat" << item.m_id << ","; |
519 | 0 | std::array<std::array<double, 9>, 2> matrices; |
520 | 0 | for (size_t st=0; st<2; ++st) { |
521 | 0 | lF << "mat" << st << "=["; |
522 | 0 | auto &matrix = matrices[st]; |
523 | 0 | for (auto &d : matrix) { |
524 | 0 | d=double(lInput->readLong(4))/65536.; |
525 | 0 | lF << d << ","; |
526 | 0 | } |
527 | 0 | lF << "],"; |
528 | 0 | } |
529 | 0 | m_state->m_idToMatrices[item.m_id]=matrices; |
530 | 0 | asciiFile.addPos(item.m_pos); |
531 | 0 | asciiFile.addNote(lF.str().c_str()); |
532 | 0 | }); |
533 | 0 | } |
534 | | |
535 | | //////////////////////////////////////////////////////////// |
536 | | // shapes |
537 | | //////////////////////////////////////////////////////////// |
538 | | |
539 | | bool Canvas5Graph::findShapeDataZones(std::shared_ptr<Canvas5Structure::Stream> stream) |
540 | 0 | { |
541 | 0 | if (!stream || !stream->input()) |
542 | 0 | return false; |
543 | 0 | m_state->m_dataStream=stream; |
544 | 0 | auto input=stream->input(); |
545 | 0 | m_state->m_dataStreamReverted=input->readInverted(); |
546 | 0 | auto &ascFile=stream->ascii(); |
547 | 0 | long pos=input->tell(); |
548 | 0 | int len=int(input->readULong(4)); |
549 | 0 | if ((len%20)!=0 || (long)((unsigned long)pos+4+(unsigned)len)<pos+4 || !input->checkPosition(pos+4+len)) { |
550 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::findShapeDataZones: can not find zone 1\n")); |
551 | 0 | return false; |
552 | 0 | } |
553 | 0 | ascFile.addPos(pos); |
554 | 0 | ascFile.addNote("Entries(DataShap):"); |
555 | |
|
556 | 0 | libmwaw::DebugStream f; |
557 | 0 | int N=len/20; |
558 | 0 | for (int i=0; i<N; ++i) { |
559 | 0 | pos=input->tell(); |
560 | 0 | f.str(""); |
561 | 0 | f << "DataShap-" << i << ":"; |
562 | 0 | f << "id=" << input->readULong(4) << ","; |
563 | 0 | f << "f0=" << input->readULong(4) << ","; // small number |
564 | 0 | f << "sz=" << input->readULong(4) << ","; |
565 | 0 | for (int j=0; j<4; ++j) { // 0 |
566 | 0 | int val=int(input->readLong(2)); |
567 | 0 | if (val) |
568 | 0 | f << "f" << j+1 << "=" << val << ","; |
569 | 0 | } |
570 | 0 | ascFile.addPos(pos); |
571 | 0 | ascFile.addNote(f.str().c_str()); |
572 | 0 | input->seek(pos+20, librevenge::RVNG_SEEK_SET); |
573 | 0 | } |
574 | |
|
575 | 0 | for (int i=0; i<N; ++i) { |
576 | 0 | pos=input->tell(); |
577 | 0 | f.str(""); |
578 | 0 | f << "DataShap-A" << i << ":"; |
579 | 0 | long zLen=long(input->readULong(4)); |
580 | 0 | if ((long)((unsigned long)pos+4+(unsigned long)zLen)<pos+4 || !input->checkPosition(pos+4+zLen)) { |
581 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::findShapeDataZones: can not find a zone 1 length\n")); |
582 | 0 | f << "###"; |
583 | 0 | ascFile.addPos(pos); |
584 | 0 | ascFile.addNote(f.str().c_str()); |
585 | 0 | return false; |
586 | 0 | } |
587 | 0 | MWAWEntry entry; |
588 | 0 | entry.setBegin(pos+4); |
589 | 0 | entry.setLength(zLen); |
590 | 0 | m_state->m_shapeZones.push_back(entry); |
591 | 0 | ascFile.addPos(pos); |
592 | 0 | ascFile.addNote(f.str().c_str()); |
593 | 0 | input->seek(pos+4+zLen, librevenge::RVNG_SEEK_SET); |
594 | 0 | } |
595 | 0 | return true; |
596 | 0 | } |
597 | | |
598 | | bool Canvas5Graph::readShapes(Canvas5Structure::Stream &stream, int numShapes) |
599 | 0 | { |
600 | 0 | auto input=stream.input(); |
601 | 0 | long pos=input->tell(); |
602 | 0 | if (!input->checkPosition(pos+4)) { |
603 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: can not find the input\n")); |
604 | 0 | return false; |
605 | 0 | } |
606 | 0 | long len=long(input->readULong(4)); |
607 | 0 | long endPos=pos+4+len; |
608 | 0 | int const vers=version(); |
609 | 0 | int const dataSize=vers<9 ? 60 : 96; |
610 | 0 | if (endPos<pos+4 || len<dataSize*numShapes || !input->checkPosition(endPos)) { |
611 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: can not determine the zone length\n")); |
612 | 0 | return false; |
613 | 0 | } |
614 | | |
615 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
616 | 0 | libmwaw::DebugStream f; |
617 | 0 | f << "Entries(Shape):"; |
618 | 0 | ascFile.addPos(pos); |
619 | 0 | ascFile.addNote(f.str().c_str()); |
620 | 0 | bool reverted=input->readInverted(); |
621 | 0 | for (int i=0; i<numShapes; ++i) { |
622 | 0 | pos=input->tell(); |
623 | 0 | if (i<1) { |
624 | 0 | ascFile.addPos(pos); |
625 | 0 | ascFile.addNote("_"); |
626 | 0 | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
627 | 0 | continue; |
628 | 0 | } |
629 | 0 | Canvas5GraphInternal::Shape shape; |
630 | 0 | f.str(""); |
631 | 0 | f << "Shape-S" << i << ":"; |
632 | 0 | float fDim[4]; |
633 | 0 | for (auto &d : fDim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8)); |
634 | 0 | if (vers<9) |
635 | 0 | shape.m_initialBox=MWAWBox2f(MWAWVec2f(fDim[1], fDim[0]),MWAWVec2f(fDim[3], fDim[2])); |
636 | 0 | else |
637 | 0 | shape.m_initialBox=MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]),MWAWVec2f(fDim[2], fDim[3])); |
638 | 0 | for (auto &d : fDim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8)); |
639 | 0 | if (vers<9) |
640 | 0 | shape.m_bdbox=MWAWBox2f(MWAWVec2f(fDim[1], fDim[0]),MWAWVec2f(fDim[3], fDim[2])); |
641 | 0 | else |
642 | 0 | shape.m_bdbox=MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]),MWAWVec2f(fDim[2], fDim[3])); |
643 | 0 | unsigned block=unsigned(input->readULong(2)); |
644 | 0 | shape.m_pos=int((block<<16)|input->readULong(2)); |
645 | 0 | if (shape.m_pos==int(0xFFFFFFFF)) shape.m_pos=-1; |
646 | 0 | shape.m_type=int(input->readULong(1)); |
647 | 0 | if (shape.m_type==100) { // none |
648 | 0 | ascFile.addPos(pos); |
649 | 0 | ascFile.addNote("_"); |
650 | 0 | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
651 | 0 | continue; |
652 | 0 | } |
653 | 0 | f << "id=" << std::hex << input->readULong(4) << std::dec << ","; |
654 | 0 | shape.m_values[0]=int(input->readULong(1)); |
655 | 0 | for (int j=0; j<3; ++j) |
656 | 0 | shape.m_flags[j]=int(input->readULong(2)); |
657 | 0 | if (reverted) std::swap(shape.m_flags[1],shape.m_flags[2]); |
658 | 0 | if (shape.m_flags[1]&0x60) { |
659 | 0 | f << "##fl,"; |
660 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: find some unknown flags\n")); |
661 | 0 | } |
662 | 0 | for (int j=0; j<3; ++j) // small number, maybe parent id, child id, ??? |
663 | 0 | shape.m_values[j+1]=int(input->readLong(4)); |
664 | 0 | f << shape << ","; |
665 | 0 | shape.m_id=i; |
666 | 0 | m_state->m_idToShapeMap[i]=shape; |
667 | 0 | ascFile.addPos(pos); |
668 | 0 | ascFile.addNote(f.str().c_str()); |
669 | 0 | input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET); |
670 | 0 | } |
671 | 0 | if (input->tell()<endPos) |
672 | 0 | ascFile.skipZone(input->tell(), endPos-1); |
673 | 0 | if (&stream!=m_state->m_dataStream.get()) { |
674 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: oops, the shape data stream seems bad\n")); |
675 | 0 | } |
676 | 0 | else { |
677 | 0 | for (auto const &it : m_state->m_idToShapeMap) { |
678 | 0 | if (it.second.m_pos>=0) |
679 | 0 | readShapeData(it.first, it.second); |
680 | 0 | } |
681 | 0 | } |
682 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
683 | 0 | return true; |
684 | 0 | } |
685 | | |
686 | | bool Canvas5Graph::readShapeData(int id, Canvas5GraphInternal::Shape const &shape) |
687 | 0 | { |
688 | 0 | auto &stream=m_state->m_dataStream; |
689 | 0 | if (shape.m_pos < 0 || !stream) { |
690 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: shape id=%d has not a valid position\n", id)); |
691 | 0 | return false; |
692 | 0 | } |
693 | 0 | if ((shape.m_flags[1]&0x419f)==0 && (shape.m_flags[2]&0xfff)==0 && shape.m_type>=4 && shape.m_type<=7) |
694 | 0 | return true; // sometimes m_pos is set even if there is no data |
695 | 0 | size_t bl=size_t(shape.m_pos>>16); |
696 | 0 | long pos=shape.m_pos&0xffff; |
697 | 0 | if (bl>=m_state->m_shapeZones.size() || pos+4 > m_state->m_shapeZones[bl].length()) { |
698 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the block corresponding to shape id=%d\n", id)); |
699 | 0 | return false; |
700 | 0 | } |
701 | | |
702 | 0 | if (m_state->m_posToShapeDataMap.find(shape.m_pos)!=m_state->m_posToShapeDataMap.end()) |
703 | 0 | return true; |
704 | 0 | auto const &entry=m_state->m_shapeZones[bl]; |
705 | 0 | auto input=stream->input(); |
706 | 0 | int const vers=version(); |
707 | 0 | libmwaw::DebugFile &ascFile = stream->ascii(); |
708 | 0 | libmwaw::DebugStream f; |
709 | 0 | f << "DataShap-S" << id << ":"; |
710 | |
|
711 | 0 | input->seek(entry.begin()+pos, librevenge::RVNG_SEEK_SET); |
712 | 0 | pos=input->tell(); |
713 | 0 | int val=int(input->readULong(4)); |
714 | 0 | if (val!=id) f << "dup2=" << val << ","; |
715 | 0 | f << shape.getTypeName() << ","; |
716 | |
|
717 | 0 | m_state->m_posToShapeDataMap[shape.m_pos]=Canvas5GraphInternal::ShapeData(); |
718 | 0 | Canvas5GraphInternal::ShapeData &data=m_state->m_posToShapeDataMap.find(shape.m_pos)->second; |
719 | 0 | long len=(shape.m_flags[2]&0x1) ? long(input->readULong(4)) : 0; |
720 | 0 | if (shape.m_flags[2]&0x2) f << "f2=" << long(input->readULong(4)) << ","; // find id=1??? |
721 | 0 | if (shape.m_flags[2]&0x4) data.m_ids[0]=unsigned(input->readULong(4)); |
722 | 0 | if (shape.m_flags[2]&0x8) f << "f8=" << long(input->readULong(4)) << ","; // never seen this one |
723 | 0 | if (shape.m_flags[2]&0x10) data.m_ids[1]=unsigned(input->readULong(4)); |
724 | 0 | if (shape.m_flags[2]&0x20) data.m_type = unsigned(input->readULong(4)); |
725 | 0 | if (shape.m_flags[2]&0x40) f << "f40=" << long(input->readULong(4)) << ","; // never seen this one |
726 | 0 | if (shape.m_flags[2]&0x80) data.m_shapeIds[0]=unsigned(input->readULong(4)); // checkme: replaced? |
727 | 0 | if (shape.m_flags[2]&0x100) f << "f100=" << long(input->readULong(4)) << ","; // never seen this one |
728 | 0 | if (shape.m_flags[2]&0x200) data.m_local[0]=int(input->readULong(4)); // text: id?, rectOval: roundX, arc angl1 |
729 | 0 | if (shape.m_flags[2]&0x400) data.m_local[1]=int(input->readULong(4)); // roundY, angl2 |
730 | 0 | if (shape.m_flags[2]&0x800) data.m_ids[2]=unsigned(input->readULong(4)); |
731 | 0 | if (shape.m_flags[1]&0x1) data.m_shapeIds[1]=unsigned(input->readULong(4)); |
732 | 0 | if (shape.m_flags[1]&0x2) data.m_shapeIds[2]=unsigned(input->readULong(4)); // child? |
733 | 0 | if (shape.m_flags[1]&0x4) data.m_shapeIds[3]=unsigned(input->readULong(4)); // often simillar to shape1 ? |
734 | 0 | if (shape.m_flags[1]&0x8) f << "g8=" << long(input->readULong(4)) << ","; // rotation? |
735 | 0 | if (shape.m_flags[1]&0x10) f << "g10=" << long(input->readULong(4)) << ","; // ? |
736 | | // checkme: we need probably also test for f1&0x20 and f1&0x40 |
737 | 0 | if (shape.m_flags[1]&0x80) f << "g80=" << long(input->readULong(4)) << ","; // ? |
738 | 0 | if (shape.m_flags[1]&0x100) f << "link[id]=" << long(input->readULong(4)) << ","; // checkme: appear in v6 with id=3200 |
739 | 0 | if (shape.m_flags[1]&0x4000) f << "Xobd" << long(input->readULong(4)) << ","; // appear in v6, related to object data base |
740 | |
|
741 | 0 | if (data.m_type) f << "type=" << Canvas5Structure::getString(data.m_type) << ","; |
742 | 0 | f << data; |
743 | |
|
744 | 0 | long actPos=input->tell(); |
745 | 0 | long endPos=actPos+len; |
746 | 0 | if (endPos<actPos || endPos>entry.end()) { |
747 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: oops, bad length for shape id=%d\n", id)); |
748 | 0 | f << "###"; |
749 | 0 | ascFile.addPos(pos); |
750 | 0 | ascFile.addNote(f.str().c_str()); |
751 | 0 | return false; |
752 | 0 | } |
753 | | |
754 | 0 | if (len && shape.m_type!=2) |
755 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
756 | |
|
757 | 0 | input->pushLimit(entry.end()); |
758 | |
|
759 | 0 | data.m_stream=stream; |
760 | 0 | data.m_streamReverted=input->readInverted(); |
761 | 0 | data.m_entry.setBegin(input->tell()); |
762 | 0 | data.m_entry.setLength(len); |
763 | |
|
764 | 0 | switch (shape.m_type) { |
765 | 0 | case 2: // with type="TXT " or "TxtU" |
766 | | // will be parsed by sendText |
767 | 0 | break; |
768 | 0 | case 3: { |
769 | 0 | if (len<(vers<9 ? 16 : 32)) { |
770 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a line\n")); |
771 | 0 | f << "###"; |
772 | 0 | break; |
773 | 0 | } |
774 | 0 | f << "pts=["; |
775 | 0 | for (int i=0; i<2; ++i) { |
776 | 0 | float fDim[2]; |
777 | 0 | for (auto &d : fDim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
778 | 0 | if (vers>=9) |
779 | 0 | data.m_vertices.push_back(MWAWVec2f(fDim[0], fDim[1])); |
780 | 0 | else |
781 | 0 | data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0])); |
782 | 0 | f << data.m_vertices.back() << ","; |
783 | 0 | } |
784 | 0 | f << "];"; |
785 | 0 | break; |
786 | 0 | } |
787 | 0 | case 4: // rect |
788 | 0 | case 5: // rectOval |
789 | 0 | case 6: // oval |
790 | 0 | case 7: // arc |
791 | 0 | if (vers>=9 && (shape.m_type==5 || shape.m_type==7) && len==16) { |
792 | 0 | f << (shape.m_type==5 ? "round" : "angle") << "="; |
793 | 0 | for (int i=0; i<2; ++i) { |
794 | 0 | data.m_doubleValues[i]=m_mainParser->readDouble(*stream, 8); |
795 | 0 | f << data.m_doubleValues[i] << (i==0 ? "x" : ","); |
796 | 0 | } |
797 | 0 | break; |
798 | 0 | } |
799 | 0 | if (len) { |
800 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: find unexpected length\n")); |
801 | 0 | f << "###"; |
802 | 0 | break; |
803 | 0 | } |
804 | 0 | if (shape.m_type==5) |
805 | 0 | f << "round=" << float(data.m_local[0])/65536.f << "x" << float(data.m_local[1])/65536.f << ","; |
806 | 0 | else if (shape.m_type==7) |
807 | 0 | f << "angle=" << float(data.m_local[0])/65536.f << "->" << float(data.m_local[1])/65536.f << ","; |
808 | 0 | break; |
809 | 0 | case 9: // polyline |
810 | 0 | case 10: { // spline |
811 | 0 | if (len<8) { |
812 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a polyline/spline\n")); |
813 | 0 | f << "###"; |
814 | 0 | break; |
815 | 0 | } |
816 | 0 | if (vers<9) |
817 | 0 | input->seek(4, librevenge::RVNG_SEEK_CUR); |
818 | 0 | int N=m_mainParser->readInteger(*stream, vers<9 ? 4 : 8); |
819 | 0 | f << "N=" << N << ","; |
820 | 0 | if (vers>=9) |
821 | 0 | input->seek(8, librevenge::RVNG_SEEK_CUR); |
822 | 0 | int const fieldSize=vers<9 ? 4 : 8; |
823 | 0 | if (4+fieldSize+2*fieldSize*N<4+fieldSize || (len-4-fieldSize)/(2*fieldSize)<N || 4+fieldSize+2*fieldSize*N>len) { |
824 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData[polyline/spline]: can not read N\n")); |
825 | 0 | f << "###"; |
826 | 0 | break; |
827 | 0 | } |
828 | 0 | f << "pts=["; |
829 | 0 | for (int i=0; i<N; ++i) { |
830 | 0 | float fDim[2]; |
831 | 0 | for (auto &d : fDim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
832 | 0 | if (vers<9) |
833 | 0 | data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0])); |
834 | 0 | else |
835 | 0 | data.m_vertices.push_back(MWAWVec2f(fDim[0], fDim[1])); |
836 | 0 | f << data.m_vertices.back() << ","; |
837 | 0 | } |
838 | 0 | f << "],"; |
839 | 0 | break; |
840 | 0 | } |
841 | 0 | case 52: { // special |
842 | 0 | std::string extra; |
843 | 0 | if (!readSpecialData(stream, len, data, extra)) |
844 | 0 | f << "###"; |
845 | 0 | f << extra; |
846 | 0 | break; |
847 | 0 | } |
848 | 0 | case 20: // master elements ? |
849 | 0 | case 99: { // group |
850 | 0 | if (len<4) { |
851 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a group\n")); |
852 | 0 | f << "###"; |
853 | 0 | break; |
854 | 0 | } |
855 | 0 | int N=int(input->readULong(4)); |
856 | 0 | f << "N=" << N << ","; |
857 | 0 | if (4+4*N<4 || 4+4*N>len) { |
858 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData[group]: can not read N\n")); |
859 | 0 | f << "###"; |
860 | 0 | break; |
861 | 0 | } |
862 | 0 | f << "id=["; |
863 | 0 | for (int i=0; i<N; ++i) { |
864 | 0 | data.m_children.push_back(unsigned(input->readULong(4))); |
865 | 0 | f << "S" << data.m_children.back() << ","; |
866 | 0 | } |
867 | 0 | f << "],"; |
868 | 0 | break; |
869 | 0 | } |
870 | 0 | default: |
871 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected type\n")); |
872 | 0 | f << "###"; |
873 | 0 | break; |
874 | 0 | } |
875 | 0 | ascFile.addPos(pos); |
876 | 0 | ascFile.addNote(f.str().c_str()); |
877 | |
|
878 | 0 | if (len && input->tell()!=endPos) |
879 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
880 | 0 | input->popLimit(); |
881 | |
|
882 | 0 | return true; |
883 | 0 | } |
884 | | |
885 | | std::shared_ptr<Canvas5GraphInternal::PseudoShape> Canvas5Graph::readSpecialData(std::shared_ptr<Canvas5Structure::Stream> stream, long len, unsigned type, MWAWBox2f const &box, std::string &extra) |
886 | 0 | { |
887 | 0 | if (!stream) |
888 | 0 | return nullptr; |
889 | 0 | auto input=stream->input(); |
890 | |
|
891 | 0 | auto res=std::make_shared<Canvas5GraphInternal::PseudoShape>(); |
892 | 0 | Canvas5GraphInternal::ShapeData &data=res->m_data; |
893 | 0 | data.m_inMainZone=false; |
894 | 0 | data.m_type=type; |
895 | |
|
896 | 0 | data.m_stream=stream; |
897 | 0 | data.m_streamReverted=input->readInverted(); |
898 | 0 | data.m_entry.setBegin(input->tell()); |
899 | 0 | data.m_entry.setLength(len); |
900 | 0 | if (!readSpecialData(stream, len, data, extra)) |
901 | 0 | return nullptr; |
902 | 0 | auto &shape=res->m_shape; |
903 | 0 | shape.m_type=52; |
904 | 0 | shape.m_initialBox=shape.m_bdbox=box; |
905 | 0 | return res; |
906 | 0 | } |
907 | | |
908 | | bool Canvas5Graph::readSpecialData(std::shared_ptr<Canvas5Structure::Stream> stream, long len, Canvas5GraphInternal::ShapeData &data, std::string &extra) |
909 | 0 | { |
910 | 0 | if (!stream) |
911 | 0 | return false; |
912 | 0 | auto input=stream->input(); |
913 | 0 | int const vers=version(); |
914 | 0 | libmwaw::DebugStream f; |
915 | 0 | int val; |
916 | 0 | switch (data.m_type) { |
917 | 0 | case 0x43756265: // Cube |
918 | 0 | if (len<(vers<9 ? 64 : 128)) { |
919 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the cube points\n")); |
920 | 0 | return false; |
921 | 0 | } |
922 | 0 | for (int i=0; i<8; ++i) { // front face, back face |
923 | 0 | float pts[2]; |
924 | 0 | for (auto &c : pts) c=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
925 | 0 | if (vers>=9) |
926 | 0 | std::swap(pts[0],pts[1]); |
927 | 0 | data.m_vertices.push_back(MWAWVec2f(pts[1],pts[0])); |
928 | 0 | f << data.m_vertices.back() << ","; |
929 | 0 | } |
930 | 0 | break; |
931 | 0 | case 0x43765465: // CvTe, will be read when we create the shape |
932 | 0 | case 0x44494d4e: // DIMN, will be read when we create the shape |
933 | 0 | break; |
934 | 0 | case 0x4e474f4e: { // NGON |
935 | 0 | if (len<(vers<9 ? 56 : 72)) { |
936 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the NGON data\n")); |
937 | 0 | return false; |
938 | 0 | } |
939 | 0 | val=int(input->readULong(2)); |
940 | 0 | if (val&0x100) |
941 | 0 | f << "smooth,"; |
942 | 0 | val&=0xfeff; |
943 | 0 | if (val) |
944 | 0 | f << "fl=" << std::hex << val << std::hex << ","; |
945 | 0 | if (vers<9) { |
946 | 0 | for (int i=0; i<5; ++i) { |
947 | 0 | val=int(input->readULong(2)); |
948 | 0 | int const expected[]= {1,0x255, 0x6ae0, 0x2440, 0x1404 }; |
949 | 0 | if (val!=expected[i]) f << "f" << i << "=" << val << ","; |
950 | 0 | } |
951 | 0 | for (int i=0; i<5; ++i) { |
952 | 0 | val=int(input->readULong(4)); |
953 | 0 | int const expected[]= {0x22e5140, 0x2232300, 0x2556af0, 0x23718c2, 0xec634 }; |
954 | 0 | if (val!=expected[i]) f << "f" << i+6 << "=" << val << ","; |
955 | 0 | } |
956 | 0 | } |
957 | 0 | else { |
958 | 0 | for (int i=0; i<7; ++i) { |
959 | 0 | val=int(input->readULong(2)); |
960 | 0 | int const expected[]= {0x3884, 0xbfff, 0xdc80,0,0x20, 0xa000, 0xb430}; |
961 | 0 | if (val!=expected[i]) f << "f" << i << "=" << val << ","; |
962 | 0 | } |
963 | 0 | for (int i=0; i<8; ++i) { |
964 | 0 | val=int(input->readULong(2)); |
965 | 0 | if (val) f << "f" << i+8 << "=" << val << ","; |
966 | 0 | } |
967 | 0 | } |
968 | 0 | data.m_doubleValues[0]=m_mainParser->readDouble(*stream,vers<9 ? 4 : 8); |
969 | 0 | f << "rad[min]=" << data.m_doubleValues[1] << ","; |
970 | 0 | f << "angles=["; |
971 | 0 | for (int i=0; i<2; ++i) { // 2 angles: pt0, min |
972 | 0 | data.m_doubleValues[i+1]=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8); |
973 | 0 | f << data.m_doubleValues[i+1] << ","; |
974 | 0 | } |
975 | 0 | f << "],"; |
976 | 0 | data.m_ngonType=int(input->readULong(4)); |
977 | 0 | if (data.m_ngonType!=4) f << "type=" << data.m_ngonType << ","; |
978 | 0 | data.m_specials[0]=int(input->readLong(2)); |
979 | 0 | f << "N=" << data.m_specials[0] << ","; |
980 | 0 | for (int i=0; i<(vers<9 ? 3 : 5); ++i) { |
981 | 0 | val=int(input->readULong(2)); |
982 | 0 | int const expected[]= {vers<9 ? 0x207 : 0x3830, 0, 0, 0, 0}; |
983 | 0 | if (val!=expected[i]) f << "g" << i << "=" << val << ","; |
984 | 0 | } |
985 | 0 | break; |
986 | 0 | } |
987 | 0 | case 0x65666665: // effe: will be read by sendEffect |
988 | 0 | case 0x45787472: // Extr: will be read by sendExtrude |
989 | 0 | break; |
990 | 0 | case 0x4772644d: { // GrdL |
991 | 0 | if (len<4) { |
992 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a grid\n")); |
993 | 0 | return false; |
994 | 0 | } |
995 | 0 | int subdiv[2]; |
996 | 0 | for (auto &d : subdiv) d=int(input->readULong(2)); |
997 | 0 | data.m_grid=MWAWVec2i(subdiv[0], subdiv[1]); |
998 | 0 | f << "grid=" << data.m_grid << ","; |
999 | 0 | break; |
1000 | 0 | } |
1001 | 0 | case 0x43436972: // CCir |
1002 | 0 | case 0x53504952: { // SPIR |
1003 | 0 | if (len<4) { |
1004 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a ccircle/spiral\n")); |
1005 | 0 | return false; |
1006 | 0 | } |
1007 | 0 | for (int i=0; i<2; ++i) data.m_specials[i]=int(input->readLong(2)); |
1008 | 0 | f << "N=" << data.m_specials[0] << ","; |
1009 | 0 | if (data.m_specials[1]) f << "space[between]=" << data.m_specials[1] << ","; // 0: equidistant (only used by CCir) |
1010 | 0 | break; |
1011 | 0 | } |
1012 | 0 | case 0x4d41434f: { // MACO: object from macros, never sent ? |
1013 | 0 | if (len<(vers<9 ? 92 : 128)) { |
1014 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[MACO]: unexpected size\n")); |
1015 | 0 | return false; |
1016 | 0 | } |
1017 | 0 | val=int(input->readLong(4)); |
1018 | 0 | if (val!=2) |
1019 | 0 | f << "f0=" << val << ","; |
1020 | 0 | if (vers>=9) |
1021 | 0 | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1022 | 0 | float dim[4]; |
1023 | 0 | for (auto &d : dim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
1024 | 0 | if (vers<9) |
1025 | 0 | f << "box=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])) << ","; |
1026 | 0 | else |
1027 | 0 | f << "box=" << MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3])) << ","; |
1028 | 0 | for (int i=0; i<(vers<9 ? 13 : 17); ++i) { // f5=0|1 |
1029 | 0 | val=int(input->readLong(4)); |
1030 | 0 | if (val) |
1031 | 0 | f << "f" << i+1 << "=" << val << ","; |
1032 | 0 | } |
1033 | |
|
1034 | 0 | std::string sMaco; |
1035 | 0 | m_imageParser->readMacroIndent(*stream, data.m_macoId, sMaco); |
1036 | 0 | f << "id=[" << sMaco << "],"; |
1037 | 0 | break; |
1038 | 0 | } |
1039 | 0 | case 0x4f4c6e6b : { // OLnk |
1040 | 0 | if (len<56) { |
1041 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a link\n")); |
1042 | 0 | return false; |
1043 | 0 | } |
1044 | 0 | f << "pts=["; |
1045 | 0 | for (int i=0; i<4; ++i) { |
1046 | 0 | float fDim[2]; |
1047 | 0 | for (auto &d : fDim) d=float(input->readLong(4))/65536.f; |
1048 | 0 | data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0])); |
1049 | 0 | f << data.m_vertices.back() << ","; |
1050 | 0 | } |
1051 | 0 | f << "],"; |
1052 | 0 | for (int i=0; i<3; ++i) { // f0=small number, f1=0|5 |
1053 | 0 | val=int(input->readLong(4)); |
1054 | 0 | if (val) |
1055 | 0 | f << "f" << i << "=" << val << ","; |
1056 | 0 | } |
1057 | 0 | val=int(input->readLong(2)); // find 4,5,7 |
1058 | 0 | if (val) f << "f3=" << val << ","; |
1059 | 0 | break; |
1060 | 0 | } |
1061 | 0 | case 0x706f626a: // pobj |
1062 | 0 | if (len<8) { |
1063 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a pobj\n")); |
1064 | 0 | return false; |
1065 | 0 | } |
1066 | 0 | for (int i=0; i<2; ++i) |
1067 | 0 | data.m_specials[i]=int(input->readULong(4)); |
1068 | 0 | if (data.m_specials[0]) |
1069 | 0 | f << "B" << data.m_specials[1] << ":" << data.m_specials[0] << ","; |
1070 | 0 | else |
1071 | 0 | f << "B" << data.m_specials[1] << ","; |
1072 | 0 | break; |
1073 | 0 | case 0x54585420: // TEXT, only in Vkfl, will be read when we create the shape |
1074 | 0 | if (data.m_inMainZone) { |
1075 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected text in main zone\n")); |
1076 | 0 | return false; |
1077 | 0 | } |
1078 | 0 | break; |
1079 | 0 | case 0x41474946: // AGIF: appear in v6 |
1080 | 0 | if (len<12) { |
1081 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a AGIF\n")); |
1082 | 0 | return false; |
1083 | 0 | } |
1084 | 0 | for (int i=0; i<3; ++i) |
1085 | 0 | data.m_specials[i]=int(input->readULong(4)); |
1086 | 0 | if (data.m_specials[0]!=1) |
1087 | 0 | f << "AG" << data.m_specials[1] << ":" << data.m_specials[0]; |
1088 | 0 | else |
1089 | 0 | f << "AG" << data.m_specials[1]; |
1090 | 0 | if (data.m_specials[2]!=1) |
1091 | 0 | f << "[" << data.m_specials[2] << "]"; |
1092 | 0 | f << ","; |
1093 | 0 | break; |
1094 | 0 | case 0x43574542: { // CWEB: a button with 3 potential shapes (and sound) |
1095 | | // checkme: find 8 times in two files, but with the same content... |
1096 | | // this zone is clearly related with RsrcWEBE (unparsed) |
1097 | 0 | if (len<40) { |
1098 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[CWEB]: unexpected size\n")); |
1099 | 0 | return false; |
1100 | 0 | } |
1101 | 0 | long pos=input->tell(); |
1102 | 0 | for (int i=0; i<2; ++i) { |
1103 | 0 | val=int(input->readLong(4)); |
1104 | 0 | int const expected[]= {0x1261998, 1}; |
1105 | 0 | if (val!=expected[i]) |
1106 | 0 | f << "f" << i << "=" << val << ","; |
1107 | 0 | } |
1108 | 0 | f << "lengths=["; |
1109 | 0 | std::vector<long> lengths; |
1110 | 0 | for (int i=0; i<8; ++i) { // 0-2: image, 3-5: sound, 6-7: unsure ??? |
1111 | 0 | long len1=long(input->readLong(4)); |
1112 | 0 | if (!len1 && i>=5) break; |
1113 | 0 | lengths.push_back(len1); |
1114 | 0 | f << std::hex << len1 << std::dec << ","; |
1115 | 0 | } |
1116 | 0 | f << "],"; |
1117 | 0 | input->seek(pos+40, librevenge::RVNG_SEEK_SET); |
1118 | |
|
1119 | 0 | libmwaw::DebugFile &ascFile = stream->ascii(); |
1120 | 0 | long endPos=pos+len; |
1121 | 0 | for (size_t i=0; i<6; ++i) { |
1122 | 0 | if (i>=lengths.size()) |
1123 | 0 | break; |
1124 | 0 | long l=lengths[i]; |
1125 | 0 | if (l==0) continue; |
1126 | 0 | pos=input->tell(); |
1127 | 0 | if (l < 0 || (long)((unsigned long)pos+(unsigned long)l)<pos || pos+l>endPos) { |
1128 | 0 | extra=f.str(); |
1129 | 0 | ascFile.addPos(input->tell()); |
1130 | 0 | ascFile.addNote("DataShap[CWEB]:###"); |
1131 | 0 | return false; |
1132 | 0 | } |
1133 | 0 | if (i<3) { // image |
1134 | 0 | data.m_cweb[i].setBegin(pos); |
1135 | 0 | data.m_cweb[i].setLength(l); |
1136 | 0 | } |
1137 | 0 | else { |
1138 | | // look like a basic snd file: see https://en.wikipedia.org/wiki/Au_file_format |
1139 | 0 | ascFile.addPos(pos); |
1140 | 0 | ascFile.addNote("DataShap[CWEB,snd]:##"); |
1141 | 0 | } |
1142 | 0 | input->seek(pos+l, librevenge::RVNG_SEEK_SET); |
1143 | 0 | } |
1144 | 0 | if (input->tell()!=endPos) { |
1145 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[CWEB]: find extra data\n")); |
1146 | 0 | ascFile.addPos(input->tell()); |
1147 | 0 | ascFile.addNote("DataShap:special,CWEB:###"); |
1148 | 0 | } |
1149 | 0 | break; |
1150 | 0 | } |
1151 | 0 | case 0x516b546d: // QkTm: appear in v6 |
1152 | 0 | if (len!=4) { |
1153 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a QkTm\n")); |
1154 | 0 | return false; |
1155 | 0 | } |
1156 | 0 | data.m_specials[0]=int(input->readULong(4)); |
1157 | 0 | f << "QK" << data.m_specials[0] << ","; |
1158 | 0 | break; |
1159 | 0 | case 0x23476465: { // #Gde: text with column and section, appear in v6 |
1160 | 0 | if (len<28) { |
1161 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: unexpected size\n")); |
1162 | 0 | return false; |
1163 | 0 | } |
1164 | 0 | auto fl=input->readULong(4); |
1165 | 0 | if (fl!=0x1771) f << "fl=" << std::hex << fl << std::dec << ","; |
1166 | 0 | data.m_gdeType=int(input->readULong(4)); |
1167 | 0 | if (data.m_gdeType<=0 || data.m_gdeType>=4 || (data.m_gdeType==1 && len!=(vers<9 ? 52: 60))) { |
1168 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: unexpected type0\n")); |
1169 | 0 | f << "###type0=" << data.m_gdeType << "," << len << ","; |
1170 | 0 | extra=f.str(); |
1171 | 0 | return false; |
1172 | 0 | } |
1173 | 0 | char const *wh[]= {"type1","type2","section/column"}; |
1174 | 0 | f << wh[data.m_gdeType-1] << ","; |
1175 | 0 | switch (data.m_gdeType) { |
1176 | 0 | case 0: { |
1177 | 0 | float dims[2]; |
1178 | 0 | for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 4)); |
1179 | 0 | f << "dim=" << MWAWVec2f(dims[0], dims[1]) << ","; // 36x36 or 50x50 |
1180 | 0 | for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 4)); |
1181 | 0 | f << "unk=" << MWAWVec2f(dims[0], dims[1]) << ","; // 0.25x0.25.. |
1182 | 0 | f << "unk1=" << std::hex << input->readULong(4) << std::dec << ","; |
1183 | 0 | break; |
1184 | 0 | } |
1185 | 0 | case 1: { |
1186 | 0 | for (int i=0; i<3; ++i) { // f0=0|1, f1=f2=0|1 |
1187 | 0 | val=int(input->readULong(4)); |
1188 | 0 | int const expected[]= {0, 1, 1}; |
1189 | 0 | if (val!=expected[i]) f << "f" << i << "=" << val << ","; |
1190 | 0 | } |
1191 | 0 | if (vers>=9) |
1192 | 0 | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1193 | |
|
1194 | 0 | float dims[2]; |
1195 | 0 | for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
1196 | 0 | f << "dim=" << MWAWVec2f(dims[1], dims[0]) << ","; // 36x36 or 50x50 |
1197 | 0 | if (vers<9) |
1198 | 0 | f << "unk0=" << std::hex << input->readULong(4) << std::dec << ","; |
1199 | 0 | for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 8)); |
1200 | 0 | f << "unk=" << MWAWVec2f(dims[0], dims[1]) << ","; // 0.25, 0.25 or 1x1 except when unkn0=0 |
1201 | 0 | f << "unk1=" << std::hex << input->readULong(4) << std::dec << ","; |
1202 | 0 | break; |
1203 | 0 | } |
1204 | 0 | case 2: { |
1205 | 0 | val=int(input->readULong(4)); // 0|1 |
1206 | 0 | if (val) f << "f0=" << val << ","; |
1207 | 0 | int N=int(input->readULong(4)); |
1208 | 0 | f << "N=" << N << ","; |
1209 | 0 | unsigned const headerSz=vers<9 ? 28 : 36; |
1210 | 0 | unsigned const dataSz=vers<9 ? 8 : 16; |
1211 | 0 | if (N<0 || int((len-headerSz)/dataSz)<N || len!=long(dataSz*unsigned(N)+headerSz)) { |
1212 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N value\n")); |
1213 | 0 | f << "###"; |
1214 | 0 | extra=f.str(); |
1215 | 0 | return false; |
1216 | 0 | } |
1217 | 0 | f << "unk=["; |
1218 | 0 | for (int i=0; i<N; ++i) { |
1219 | 0 | val=int(input->readLong(4)); // 1|2 |
1220 | 0 | if (vers>=9) |
1221 | 0 | input->seek(4, librevenge::RVNG_SEEK_CUR); |
1222 | 0 | f << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ":" << val << ","; |
1223 | 0 | } |
1224 | 0 | f << "],"; |
1225 | 0 | f << "unk1=["; |
1226 | 0 | for (int i=0; i<(vers<9 ? 3 : 5); ++i) |
1227 | 0 | f << float(input->readLong(4))/65536 << ","; |
1228 | 0 | f << "],"; |
1229 | 0 | break; |
1230 | 0 | } |
1231 | 0 | case 3: |
1232 | 0 | default: { |
1233 | 0 | int N=int(input->readLong(4)); |
1234 | 0 | f << "N=" << N << ","; |
1235 | 0 | int const dataSz=vers<9 ? 100 : 120; |
1236 | 0 | if (N<0 || (len-28)/dataSz<N) { |
1237 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N value\n")); |
1238 | 0 | f << "###"; |
1239 | 0 | extra=f.str(); |
1240 | 0 | return false; |
1241 | 0 | } |
1242 | 0 | libmwaw::DebugStream f2; |
1243 | 0 | libmwaw::DebugFile &ascFile = stream->ascii(); |
1244 | 0 | for (int i=0; i<N; ++i) { |
1245 | 0 | long pos=input->tell(); |
1246 | 0 | f2.str(""); |
1247 | 0 | f2 << "DataShap[#Gde-S" << i << ":]"; |
1248 | 0 | Canvas5GraphInternal::SectionData section; |
1249 | 0 | for (int j=0; j<4; ++j) { |
1250 | 0 | val=int(input->readLong(4)); |
1251 | 0 | if (val) |
1252 | 0 | f2 << "f" << j << "=" << val << ","; |
1253 | 0 | } |
1254 | 0 | float dim[4]; |
1255 | 0 | for (auto &d : dim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)); |
1256 | 0 | if (vers<9) |
1257 | 0 | section.m_bdBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])); |
1258 | 0 | else |
1259 | 0 | section.m_bdBox=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3])); |
1260 | 0 | f2 << "box=" << section.m_bdBox << ","; |
1261 | 0 | if (vers>=9) { |
1262 | 0 | f2 << "unkn=" << m_mainParser->readDouble(*stream, 8) << ","; // 2 |
1263 | 0 | val=int(input->readLong(4)); |
1264 | 0 | if (val) |
1265 | 0 | f2 << "f2=" << val << ","; |
1266 | 0 | } |
1267 | 0 | long actPos=input->tell(); |
1268 | 0 | std::string name; |
1269 | 0 | for (int j=0; j<28; ++j) { // checkme what is the bigger length |
1270 | 0 | char c=char(input->readULong(1)); |
1271 | 0 | if (!c) |
1272 | 0 | break; |
1273 | 0 | name+=c; |
1274 | 0 | } |
1275 | 0 | f2 << name << ","; |
1276 | 0 | input->seek(actPos+28, librevenge::RVNG_SEEK_SET); |
1277 | 0 | for (int j=0; j<(vers<9 ? 7 : 6); ++j) { // f11=0|1 |
1278 | 0 | val=int(input->readLong(4)); |
1279 | 0 | if (val==(j<3 ? 1 : 0)) continue; |
1280 | 0 | if (j==0) |
1281 | 0 | f2 << "writing[mode]=" << val << ","; // 2: means first rigth columns then toward left |
1282 | 0 | else |
1283 | 0 | f2 << "f" << j+5 << "=" << val << ","; |
1284 | 0 | } |
1285 | 0 | if (vers<9) { |
1286 | 0 | val=int(input->readLong(4)); |
1287 | 0 | if (val!=0x20000) |
1288 | 0 | f2 << "g0=" << float(val)/65536; |
1289 | 0 | } |
1290 | 0 | section.m_numColumns=int(input->readLong(4)); |
1291 | 0 | f2 << "num[columns]=" << section.m_numColumns << ","; |
1292 | 0 | f2 << "id=" << input->readLong(4) << ","; |
1293 | 0 | data.m_sections.push_back(section); |
1294 | |
|
1295 | 0 | ascFile.addPos(pos); |
1296 | 0 | ascFile.addNote(f2.str().c_str()); |
1297 | 0 | input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET); |
1298 | 0 | } |
1299 | |
|
1300 | 0 | long pos=input->tell(); |
1301 | 0 | f2.str(""); |
1302 | 0 | f2 << "DataShap[#Gde-columns]:"; |
1303 | 0 | if (vers<9) { |
1304 | 0 | float dim[2]; |
1305 | 0 | for (auto &d : dim) d=float(input->readLong(4))/65536; |
1306 | 0 | f2 << "orig=" << MWAWVec2f(dim[1],dim[0]) << ","; |
1307 | 0 | } |
1308 | 0 | else |
1309 | 0 | input->seek(8, librevenge::RVNG_SEEK_CUR); |
1310 | 0 | int N0=int(input->readLong(4)); |
1311 | 0 | f2 << "num[columns]=" << N0 << ","; |
1312 | 0 | int const data1Sz=vers<9 ? 8 : 16; |
1313 | 0 | if (N0<0 || 28+dataSz*N+data1Sz*N0<len || (len-dataSz*N-28)/data1Sz<N0) { |
1314 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N0 value\n")); |
1315 | 0 | f2 << "###"; |
1316 | 0 | ascFile.addPos(pos); |
1317 | 0 | ascFile.addNote(f2.str().c_str()); |
1318 | 0 | extra=f.str(); |
1319 | 0 | return false; |
1320 | 0 | } |
1321 | 0 | f2 << "pos=["; |
1322 | 0 | for (int i=0; i<=2*N0; ++i) |
1323 | 0 | f2 << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ","; |
1324 | 0 | f2 << "],"; |
1325 | 0 | ascFile.addPos(pos); |
1326 | 0 | ascFile.addNote(f2.str().c_str()); |
1327 | 0 | break; |
1328 | 0 | } |
1329 | 0 | } |
1330 | 0 | break; |
1331 | 0 | } |
1332 | 0 | case 0x416e4766: // AnGf: appear in v7, will be parsed when we send data |
1333 | 0 | break; |
1334 | 0 | case 0x70636567: // pceg: appear in v7 |
1335 | 0 | if (len<8) { |
1336 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a pceg\n")); |
1337 | 0 | return false; |
1338 | 0 | } |
1339 | 0 | val=int(input->readULong(4)); |
1340 | 0 | if (val!=0x3251999) |
1341 | 0 | f << "f0=" << std::hex << val << std::dec << ","; |
1342 | 0 | data.m_specials[1]=int(input->readULong(4)); |
1343 | 0 | f << "PC" << data.m_specials[1] << ","; |
1344 | 0 | break; |
1345 | 0 | case 0x54656368: // Tech: appear in v7, will be parsed when we send data |
1346 | 0 | break; |
1347 | | |
1348 | 0 | case 0x72656750: // regP: registration mark, appear in v8 |
1349 | 0 | if (len<16) { |
1350 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a regP\n")); |
1351 | 0 | return false; |
1352 | 0 | } |
1353 | 0 | for (int i=0; i<4; ++i) { |
1354 | 0 | val=int(input->readLong(4)); |
1355 | 0 | int const expected[]= {0x7df, 0x700, 1, 1}; |
1356 | 0 | if (val!=expected[i]) |
1357 | 0 | f << "f" << i << "=" << val << ","; |
1358 | 0 | } |
1359 | 0 | break; |
1360 | 0 | default: |
1361 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected special %s\n", Canvas5Structure::getString(data.m_type).c_str())); |
1362 | 0 | return false; |
1363 | 0 | } |
1364 | 0 | extra=f.str(); |
1365 | 0 | return true; |
1366 | 0 | } |
1367 | | |
1368 | | //////////////////////////////////////////////////////////// |
1369 | | |
1370 | | bool Canvas5Graph::readDeR3(std::shared_ptr<Canvas5Structure::Stream> stream, Canvas5StyleManager::StyleList &styles) |
1371 | 0 | { |
1372 | 0 | if (!stream || !stream->input()) |
1373 | 0 | return false; |
1374 | 0 | auto input=stream->input(); |
1375 | 0 | long pos=input->tell(); |
1376 | 0 | int const vers=version(); |
1377 | 0 | int const headerSize=vers<9 ? 124 : 160; |
1378 | 0 | if (!input->checkPosition(pos+headerSize)) { |
1379 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: the zone is too short 1\n")); |
1380 | 0 | return false; |
1381 | 0 | } |
1382 | 0 | libmwaw::DebugFile &ascFile = stream->ascii(); |
1383 | 0 | libmwaw::DebugStream f; |
1384 | 0 | int val; |
1385 | 0 | f << "Entries(DeR3):"; |
1386 | 0 | for (int i=0; i<2; ++i) { |
1387 | 0 | val=int(input->readLong(2)); |
1388 | 0 | if (val!=(i==0 ? 2 : 0)) |
1389 | 0 | f << "f" << i << "=" << val << ","; |
1390 | 0 | } |
1391 | 0 | unsigned name=unsigned(input->readULong(4)); |
1392 | 0 | if (name!=0x44655233) { // "DeR3" |
1393 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: unexcepted header\n")); |
1394 | 0 | return false; |
1395 | 0 | } |
1396 | 0 | int nLines=0; |
1397 | 0 | for (int i=0; i<4; ++i) { |
1398 | 0 | val=int(input->readULong(2)); |
1399 | 0 | if (val==0) continue; |
1400 | 0 | if (i==2) { |
1401 | 0 | nLines=val; |
1402 | 0 | f << "n[lines]=" << val << ","; |
1403 | 0 | } |
1404 | 0 | else |
1405 | 0 | f << "f" << i+2 << "=" << val << ","; |
1406 | 0 | } |
1407 | 0 | unsigned long lengths[7], totalLength=0; |
1408 | 0 | f << "len=["; |
1409 | 0 | for (auto &l : lengths) { |
1410 | 0 | l=input->readULong(4); |
1411 | 0 | if (totalLength+l<totalLength) { |
1412 | 0 | f << "###"; |
1413 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad lengths\n")); |
1414 | 0 | ascFile.addPos(pos); |
1415 | 0 | ascFile.addNote(f.str().c_str()); |
1416 | 0 | return false; |
1417 | 0 | } |
1418 | 0 | totalLength+=l; |
1419 | 0 | if (l) |
1420 | 0 | f << l << ","; |
1421 | 0 | else |
1422 | 0 | f << "_,"; |
1423 | 0 | if (long(l)<0) { |
1424 | 0 | f << "###"; |
1425 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: a length is bad\n")); |
1426 | 0 | ascFile.addPos(pos); |
1427 | 0 | ascFile.addNote(f.str().c_str()); |
1428 | 0 | return false; |
1429 | 0 | } |
1430 | 0 | } |
1431 | 0 | f << "],"; |
1432 | 0 | for (int i=0; i<(vers<9 ? 2 : 6); ++i) { // g0=0|12 |
1433 | 0 | val=int(input->readLong(2)); |
1434 | 0 | if (val) f << "g" << i << "=" << val << ","; |
1435 | 0 | } |
1436 | 0 | for (int i=0; i<2; ++i) { // dim0~=1 or dim2=0-100 |
1437 | 0 | double dVal=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8); |
1438 | 0 | if (dVal<1 || dVal>1) |
1439 | 0 | f << "dim" << i << "=" << dVal << ","; |
1440 | 0 | } |
1441 | 0 | int nIntervs=int(input->readLong(4)); |
1442 | 0 | if (nIntervs) f << "n[interv]=" << nIntervs << ","; |
1443 | 0 | if (nIntervs<0 || (int(lengths[3])<nIntervs*12)) { |
1444 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad number of tabulations\n")); |
1445 | 0 | f << "###"; |
1446 | 0 | nIntervs=0; |
1447 | 0 | } |
1448 | 0 | val=int(input->readLong(4)); |
1449 | 0 | if (val!=10) f << "g2=" << val << ","; |
1450 | 0 | for (int i=0; i<30; ++i) { // g2=1-6, g3=-1, g28=0-466 |
1451 | 0 | val=int(input->readLong(2)); |
1452 | 0 | if (val) f << "g" << i+3 << "=" << val << ","; |
1453 | 0 | } |
1454 | 0 | int const widthSize=vers<9 ? 4 : 8; |
1455 | 0 | int const tabSize=vers<9 ? 12 : 24; |
1456 | 0 | if (pos+headerSize+long(totalLength)<pos+headerSize || !input->checkPosition(pos+headerSize+long(totalLength)) || |
1457 | 0 | int(lengths[0])<4*(nLines+1) || int(lengths[1])<2*(nLines+1) || int(lengths[2])<widthSize*nLines || |
1458 | 0 | (lengths[3]%12)!=0 || (int(lengths[4])%tabSize)!=0) { |
1459 | 0 | f << "###"; |
1460 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad lengths\n")); |
1461 | 0 | ascFile.addPos(pos); |
1462 | 0 | ascFile.addNote(f.str().c_str()); |
1463 | 0 | return false; |
1464 | 0 | } |
1465 | 0 | ascFile.addPos(pos); |
1466 | 0 | ascFile.addNote(f.str().c_str()); |
1467 | 0 | input->seek(pos+headerSize, librevenge::RVNG_SEEK_SET); |
1468 | |
|
1469 | 0 | if (lengths[0]) { |
1470 | 0 | pos=input->tell(); |
1471 | 0 | f.str(""); |
1472 | 0 | f << "DeR3-line:numChar=["; |
1473 | 0 | for (int i=0; i<=nLines; ++i) f << input->readULong(4) << ","; |
1474 | 0 | f << "],"; |
1475 | 0 | ascFile.addPos(pos); |
1476 | 0 | ascFile.addNote(f.str().c_str()); |
1477 | 0 | input->seek(pos+long(lengths[0]), librevenge::RVNG_SEEK_SET); |
1478 | 0 | } |
1479 | |
|
1480 | 0 | if (lengths[1]) { |
1481 | 0 | pos=input->tell(); |
1482 | 0 | f.str(""); |
1483 | 0 | f << "DeR3-flags:fl=["; |
1484 | 0 | for (int i=0; i<=nLines; ++i) f << std::hex << input->readULong(2) << std::dec << ","; |
1485 | 0 | f << "],"; |
1486 | 0 | ascFile.addPos(pos); |
1487 | 0 | ascFile.addNote(f.str().c_str()); |
1488 | 0 | input->seek(pos+long(lengths[1]), librevenge::RVNG_SEEK_SET); |
1489 | 0 | } |
1490 | |
|
1491 | 0 | if (lengths[2]) { |
1492 | 0 | pos=input->tell(); |
1493 | 0 | f.str(""); |
1494 | 0 | f << "DeR3-widths:w=["; |
1495 | 0 | for (int i=0; i<nLines; ++i) f << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ","; |
1496 | 0 | f << "],"; |
1497 | 0 | ascFile.addPos(pos); |
1498 | 0 | ascFile.addNote(f.str().c_str()); |
1499 | 0 | input->seek(pos+long(lengths[2]), librevenge::RVNG_SEEK_SET); |
1500 | 0 | } |
1501 | |
|
1502 | 0 | long endPos=input->tell()+long(lengths[3]); |
1503 | 0 | for (int i=0; i<int(lengths[3]/12); ++i) { |
1504 | 0 | if (i>=nIntervs) |
1505 | 0 | break; |
1506 | 0 | pos=input->tell(); |
1507 | 0 | f.str(""); |
1508 | 0 | f << "DeR3-int" << i << ":"; |
1509 | 0 | f << "len=" << float(input->readLong(4))/65536.f << ","; |
1510 | 0 | f << "type=" << input->readLong(2) << ","; |
1511 | 0 | val=int(input->readLong(2)); |
1512 | 0 | if (val) f << "f1=" << val << ","; |
1513 | 0 | f << "pos=" << float(input->readLong(4))/65536.f << ","; |
1514 | 0 | ascFile.addPos(pos); |
1515 | 0 | ascFile.addNote(f.str().c_str()); |
1516 | 0 | input->seek(pos+12, librevenge::RVNG_SEEK_SET); |
1517 | 0 | } |
1518 | 0 | if (input->tell()!=endPos) { |
1519 | 0 | ascFile.addPos(input->tell()); |
1520 | 0 | ascFile.addNote("_"); |
1521 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1522 | 0 | } |
1523 | |
|
1524 | 0 | for (int i=0; i<int(lengths[4])/tabSize; ++i) { |
1525 | 0 | pos=input->tell(); |
1526 | 0 | f.str(""); |
1527 | 0 | f << "DeR3-tab" << i << ":"; |
1528 | 0 | f << "pos=" << m_mainParser->readDouble(*stream, vers<9 ? 4: 8) << ","; |
1529 | 0 | f << "type=" << input->readLong(2) << ","; |
1530 | 0 | for (int j=0; j<(vers<9 ? 3 : 7); ++j) { |
1531 | 0 | val=int(input->readLong(2)); |
1532 | 0 | if (val) f << "f" << j << "=" << val << ","; |
1533 | 0 | } |
1534 | 0 | ascFile.addPos(pos); |
1535 | 0 | ascFile.addNote(f.str().c_str()); |
1536 | 0 | input->seek(pos+tabSize, librevenge::RVNG_SEEK_SET); |
1537 | 0 | } |
1538 | |
|
1539 | 0 | if (lengths[5]) { |
1540 | 0 | pos=input->tell(); |
1541 | 0 | f.str(""); |
1542 | 0 | f<< "DeR3-A"; |
1543 | 0 | ascFile.addPos(pos); |
1544 | 0 | ascFile.addNote(f.str().c_str()); |
1545 | 0 | input->seek(pos+long(lengths[5]), librevenge::RVNG_SEEK_SET); |
1546 | 0 | } |
1547 | |
|
1548 | 0 | if (!lengths[6]) return true; |
1549 | | |
1550 | 0 | pos=input->tell(); |
1551 | 0 | endPos=pos+long(lengths[6]); |
1552 | 0 | f.str(""); |
1553 | 0 | f<< "Entries(ParaStyl),DeR3-style:"; |
1554 | |
|
1555 | 0 | int N[2]; |
1556 | 0 | f << "N=["; |
1557 | 0 | for (auto &n : N) { |
1558 | 0 | n=int(input->readULong(4)); |
1559 | 0 | f << n << ","; |
1560 | 0 | } |
1561 | 0 | f << "],"; |
1562 | 0 | f << "len=" << input->readULong(4) << ","; |
1563 | 0 | f << "max[tabs,sz]=" << int(input->readULong(4)) << ","; |
1564 | 0 | int styleSize=vers<9 ? 128 : 224; |
1565 | 0 | if (lengths[6]<40 || N[0]<0 || N[1]<0 || int(lengths[6]-40)/styleSize<N[0] || |
1566 | 0 | long(N[0])*styleSize+40<40 || long(N[0])*styleSize+40>long(lengths[6])) { |
1567 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: bad N\n")); |
1568 | 0 | f << "###"; |
1569 | 0 | ascFile.addPos(pos); |
1570 | 0 | ascFile.addNote(f.str().c_str()); |
1571 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1572 | 0 | return true; |
1573 | 0 | } |
1574 | 0 | ascFile.addPos(pos); |
1575 | 0 | ascFile.addNote(f.str().c_str()); |
1576 | |
|
1577 | 0 | input->seek(pos+(vers<9 ? 28 : 32), librevenge::RVNG_SEEK_SET); |
1578 | 0 | styles.m_paragraphs.resize(size_t(N[0])); |
1579 | 0 | for (int i=0; i<N[0]; ++i) { |
1580 | 0 | pos=input->tell(); |
1581 | 0 | f.str(""); |
1582 | 0 | f<< "ParaStyl-E" << i+1 << ":"; |
1583 | 0 | ascFile.addPos(pos); |
1584 | 0 | ascFile.addNote(f.str().c_str()); |
1585 | 0 | m_styleManager->readParaStyle(stream, i+1, &styles); |
1586 | 0 | input->seek(pos+styleSize, librevenge::RVNG_SEEK_SET); |
1587 | 0 | } |
1588 | |
|
1589 | 0 | for (int t=0; t<N[1]; ++t) { |
1590 | 0 | pos=input->tell(); |
1591 | 0 | f.str(""); |
1592 | 0 | f << "DeR3-Tab" << t+1 << ":"; |
1593 | 0 | val=int(input->readULong(4)); |
1594 | 0 | if (val!=1) |
1595 | 0 | f << "used=" << val << ","; |
1596 | 0 | int len=int(input->readULong(4)); |
1597 | 0 | if (len<0 || pos+16+len > endPos) { |
1598 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: bad tab size\n")); |
1599 | 0 | f << "###"; |
1600 | 0 | ascFile.addPos(pos); |
1601 | 0 | ascFile.addNote(f.str().c_str()); |
1602 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1603 | 0 | return true; |
1604 | 0 | } |
1605 | 0 | for (int i=0; i<4; ++i) { // 0 |
1606 | 0 | val=int(input->readLong(2)); |
1607 | 0 | if (val) f << "f" << i << "=" << val << ","; |
1608 | 0 | } |
1609 | 0 | double dVal=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8); |
1610 | 0 | if (dVal<36 || dVal>36) |
1611 | 0 | f << "dim?=" << dVal << ","; |
1612 | 0 | int n=int(input->readULong(2)); |
1613 | 0 | if (n) f << "N=" << n << ","; |
1614 | 0 | if (n<0 || len < (vers<9 ? 0 : 24) + tabSize*n) { |
1615 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: the num of tab seems bad\n")); |
1616 | 0 | f << "###"; |
1617 | 0 | n=0; |
1618 | 0 | } |
1619 | 0 | for (int i=0; i<(vers<9 ? 3 : 7); ++i) { // 0 |
1620 | 0 | val=int(input->readLong(2)); |
1621 | 0 | if (val) f << "f" << i+4 << "=" << val << ","; |
1622 | 0 | } |
1623 | 0 | f << "tabs=["; |
1624 | 0 | std::vector<MWAWTabStop> tabs; |
1625 | 0 | tabs.resize(size_t(n)); |
1626 | 0 | for (size_t i=0; i<size_t(n); ++i) { |
1627 | 0 | MWAWTabStop &tab=tabs[i]; |
1628 | 0 | tab.m_position=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)/72; |
1629 | 0 | int type=int(input->readULong(2)); |
1630 | 0 | switch (type) { |
1631 | 0 | case 0: // left |
1632 | 0 | break; |
1633 | 0 | case 1: |
1634 | 0 | tab.m_alignment=MWAWTabStop::CENTER; |
1635 | 0 | break; |
1636 | 0 | case 2: |
1637 | 0 | tab.m_alignment=MWAWTabStop::RIGHT; |
1638 | 0 | break; |
1639 | 0 | case 3: |
1640 | 0 | tab.m_alignment=MWAWTabStop::DECIMAL; |
1641 | 0 | tab.m_decimalCharacter=','; |
1642 | 0 | break; |
1643 | 0 | case 4: |
1644 | 0 | tab.m_alignment=MWAWTabStop::DECIMAL; |
1645 | 0 | tab.m_decimalCharacter='\''; |
1646 | 0 | break; |
1647 | 0 | default: |
1648 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: unknown tab type\n")); |
1649 | 0 | f << "###type=" << val << ","; |
1650 | 0 | break; |
1651 | 0 | } |
1652 | 0 | f << tab; |
1653 | 0 | for (int j=0; j<(vers<9 ? 3 : 7); ++j) { // v9: f2 is probably related to leader char but 0x30 mean 'a' ? |
1654 | 0 | val=int(input->readLong(2)); |
1655 | 0 | if (val) f << ":f" << j << "=" << val << ","; |
1656 | 0 | } |
1657 | 0 | f << ","; |
1658 | 0 | } |
1659 | 0 | f << "],"; |
1660 | 0 | if (!tabs.empty()) { |
1661 | 0 | for (auto ¶Id : styles.m_paragraphs) { |
1662 | 0 | if (paraId.second==t+1) |
1663 | 0 | paraId.first.m_tabs=tabs; |
1664 | 0 | } |
1665 | 0 | } |
1666 | 0 | ascFile.addPos(pos); |
1667 | 0 | ascFile.addNote(f.str().c_str()); |
1668 | 0 | input->seek(pos+16+len, librevenge::RVNG_SEEK_SET); |
1669 | 0 | } |
1670 | | |
1671 | 0 | pos=input->tell(); |
1672 | 0 | if (pos!=endPos) { // checkme: list of 0 |
1673 | 0 | ascFile.addPos(pos); |
1674 | 0 | ascFile.addNote("_"); |
1675 | 0 | } |
1676 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1677 | 0 | return true; |
1678 | 0 | } |
1679 | | |
1680 | | //////////////////////////////////////////////////////////// |
1681 | | // |
1682 | | // Low level |
1683 | | // |
1684 | | //////////////////////////////////////////////////////////// |
1685 | | |
1686 | | //////////////////////////////////////////////////////////// |
1687 | | // send data to the listener |
1688 | | //////////////////////////////////////////////////////////// |
1689 | | bool Canvas5Graph::sendShape(int sId) |
1690 | 0 | { |
1691 | 0 | return sendShape(sId, LocalState()); |
1692 | 0 | } |
1693 | | |
1694 | | bool Canvas5Graph::sendShape(int sId, Canvas5Graph::LocalState const &local) |
1695 | 0 | { |
1696 | 0 | auto const &it = m_state->m_idToShapeMap.find(sId); |
1697 | 0 | if (it==m_state->m_idToShapeMap.end()) { |
1698 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendShape: can not find the shape %d\n", sId)); |
1699 | 0 | return false; |
1700 | 0 | } |
1701 | 0 | if (m_state->m_sendIdSet.find(sId)!=m_state->m_sendIdSet.end()) { |
1702 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendShape: loop detected for shape %d\n", sId)); |
1703 | 0 | return false; |
1704 | 0 | } |
1705 | 0 | m_state->m_sendIdSet.insert(sId); |
1706 | 0 | bool res=send(it->second, local); |
1707 | 0 | m_state->m_sendIdSet.erase(sId); |
1708 | 0 | return res; |
1709 | 0 | } |
1710 | | |
1711 | | void Canvas5Graph::send(MWAWListenerPtr listener, MWAWGraphicShape const &shape, MWAWTransformation const &transform, |
1712 | | MWAWGraphicStyle const &style) |
1713 | 0 | { |
1714 | 0 | if (!listener) |
1715 | 0 | return; |
1716 | 0 | MWAWGraphicShape fShape=shape; |
1717 | 0 | if (!transform.isIdentity()) |
1718 | 0 | fShape=fShape.transform(transform); |
1719 | 0 | auto shapeBox=fShape.getBdBox(); |
1720 | 0 | MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
1721 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
1722 | 0 | listener->insertShape(pos, fShape, style); |
1723 | 0 | } |
1724 | | |
1725 | | void Canvas5Graph::send(MWAWListenerPtr listener, librevenge::RVNGString const &text, MWAWVec2f const ¢er, |
1726 | | MWAWTransformation const &transform, MWAWFont const &font, bool addFrame) |
1727 | 0 | { |
1728 | 0 | if (!listener || text.empty()) |
1729 | 0 | return; |
1730 | | |
1731 | 0 | MWAWPosition measurePos(center-MWAWVec2f(30,6), MWAWVec2f(60,12), librevenge::RVNG_POINT); |
1732 | 0 | measurePos.m_anchorTo = MWAWPosition::Page; |
1733 | 0 | std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, MWAWInputStreamPtr(), text, font)); |
1734 | |
|
1735 | 0 | MWAWGraphicStyle measureStyle; |
1736 | 0 | measureStyle.m_lineWidth=addFrame ? 1 : 0; |
1737 | 0 | measureStyle.setSurfaceColor(MWAWColor::white()); |
1738 | |
|
1739 | 0 | MWAWTransformation transf; |
1740 | 0 | float rotation=0; |
1741 | 0 | MWAWVec2f shearing; |
1742 | 0 | if (!transform.isIdentity() && transform.decompose(rotation,shearing,transf,center)) { |
1743 | 0 | auto shapeBox=transf*MWAWBox2f(center-MWAWVec2f(30,6),center+MWAWVec2f(30,6)); |
1744 | 0 | measurePos.setOrigin(shapeBox[0]); |
1745 | 0 | measurePos.setSize(shapeBox[1]-shapeBox[0]); |
1746 | 0 | measureStyle.m_rotate=-rotation; |
1747 | 0 | } |
1748 | 0 | listener->insertTextBox(measurePos, doc, measureStyle); |
1749 | 0 | } |
1750 | | |
1751 | | bool Canvas5Graph::send(Canvas5GraphInternal::Shape const &shape, Canvas5Graph::LocalState const &lTransform) |
1752 | 0 | { |
1753 | 0 | auto listener=m_parserState->m_graphicListener; |
1754 | 0 | if (!listener) { |
1755 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: can not find the listener\n")); |
1756 | 0 | return false; |
1757 | 0 | } |
1758 | 0 | int const vers=version(); |
1759 | 0 | auto const &shapeIt=m_state->m_posToShapeDataMap.find(shape.m_pos); |
1760 | 0 | bool hasShapeId=shapeIt!=m_state->m_posToShapeDataMap.end(); |
1761 | 0 | MWAWPosition pos(shape.m_initialBox[0], shape.m_initialBox.size(), librevenge::RVNG_POINT); |
1762 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
1763 | 0 | LocalState local(pos, lTransform.m_style); |
1764 | 0 | local.m_transform=lTransform.m_transform; |
1765 | 0 | if (hasShapeId && shapeIt->second.m_ids[1]) { |
1766 | 0 | auto const &matIt=m_state->m_idToMatrices.find(int(shapeIt->second.m_ids[1])); |
1767 | 0 | if (matIt==m_state->m_idToMatrices.end()) { |
1768 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: can not find the matrix %d\n", int(shapeIt->second.m_ids[1]))); |
1769 | 0 | } |
1770 | 0 | else |
1771 | 0 | local.multiplyMatrix(matIt->second[0]); |
1772 | 0 | } |
1773 | 0 | if (shape.m_values[1]) |
1774 | 0 | m_styleManager->updateSurfaceColor(shape.m_values[1], local.m_style); |
1775 | 0 | if (shape.m_values[2]) |
1776 | 0 | m_styleManager->updateLineColor(shape.m_values[2], local.m_style); |
1777 | 0 | int numLines=1; |
1778 | 0 | if (shape.m_values[3]) |
1779 | 0 | m_styleManager->updateLineStyle(shape.m_values[3], local.m_style, numLines); |
1780 | 0 | MWAWGraphicShape finalShape; |
1781 | 0 | switch (shape.m_type) { |
1782 | 0 | case 2: { |
1783 | 0 | if (!hasShapeId || !shapeIt->second.m_stream) { |
1784 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[text]: can not find the text zone\n")); |
1785 | 0 | return false; |
1786 | 0 | } |
1787 | 0 | local.m_style.m_lineWidth=0; |
1788 | 0 | std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, shapeIt->second.getStream().input(), shape, shapeIt->second)); |
1789 | 0 | MWAWTransformation transf; |
1790 | 0 | float rotation=0; |
1791 | 0 | MWAWVec2f shearing; |
1792 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) { |
1793 | 0 | MWAWBox2f box=transf*shape.m_initialBox; |
1794 | 0 | pos.setOrigin(box[0]); |
1795 | 0 | pos.setSize(box[1]-box[0]); |
1796 | 0 | MWAWGraphicStyle style(local.m_style); |
1797 | 0 | style.m_rotate=-rotation; |
1798 | 0 | listener->insertTextBox(pos, doc, style); |
1799 | 0 | } |
1800 | 0 | else |
1801 | 0 | listener->insertTextBox(pos, doc, local.m_style); |
1802 | 0 | return true; |
1803 | 0 | } |
1804 | 0 | case 3: { |
1805 | 0 | auto const &data=shapeIt->second; |
1806 | 0 | if (data.m_vertices.size()==2) |
1807 | 0 | finalShape=MWAWGraphicShape::line(data.m_vertices[0], data.m_vertices[1]); |
1808 | 0 | else |
1809 | 0 | finalShape=MWAWGraphicShape::line(shape.m_initialBox[0], shape.m_initialBox[1]); |
1810 | 0 | break; |
1811 | 0 | } |
1812 | 0 | case 4: |
1813 | 0 | finalShape=MWAWGraphicShape::rectangle(shape.m_initialBox); |
1814 | 0 | break; |
1815 | 0 | case 5: |
1816 | 0 | if (!hasShapeId) { |
1817 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[rectOval]: can not find the oval size\n")); |
1818 | 0 | return false; |
1819 | 0 | } |
1820 | 0 | if (vers<9) |
1821 | 0 | finalShape=MWAWGraphicShape::rectangle |
1822 | 0 | (shape.m_initialBox, 1/65536.f*MWAWVec2f(float(shapeIt->second.m_local[0])/2,float(shapeIt->second.m_local[1])/2)); |
1823 | 0 | else |
1824 | 0 | finalShape=MWAWGraphicShape::rectangle |
1825 | 0 | (shape.m_initialBox, MWAWVec2f(float(shapeIt->second.m_doubleValues[0])/2,float(shapeIt->second.m_doubleValues[1])/2)); |
1826 | 0 | break; |
1827 | 0 | case 6: |
1828 | 0 | finalShape=MWAWGraphicShape::circle(shape.m_initialBox); |
1829 | 0 | break; |
1830 | 0 | case 7: { // arc |
1831 | 0 | if (!hasShapeId) { |
1832 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[arc]: can not find the angle\n")); |
1833 | 0 | return false; |
1834 | 0 | } |
1835 | 0 | auto const &data=shapeIt->second; |
1836 | 0 | float const angles[]= {vers<9 ? float(data.m_local[0])/65536 : float(180/M_PI *data.m_doubleValues[1]), |
1837 | 0 | vers<9 ? float(data.m_local[1])/65536 : float(180/ M_PI *data.m_doubleValues[0]) |
1838 | 0 | }; |
1839 | 0 | int angle[2] = { int(90-angles[0]-angles[1]), int(90-angles[1]) }; |
1840 | 0 | if (angles[0]<0) |
1841 | 0 | std::swap(angle[0],angle[1]); |
1842 | 0 | else if (angles[0]>=360) |
1843 | 0 | angle[0]-=359; |
1844 | 0 | if (angle[1]>360) { |
1845 | 0 | int numLoop=int(angle[1]/360)-1; |
1846 | 0 | angle[0]-=numLoop*360; |
1847 | 0 | angle[1]-=numLoop*360; |
1848 | 0 | while (angle[1] > 360) { |
1849 | 0 | angle[0]-=360; |
1850 | 0 | angle[1]-=360; |
1851 | 0 | } |
1852 | 0 | } |
1853 | 0 | if (angle[0] < -360) { |
1854 | 0 | int numLoop=int(angle[0]/360)+1; |
1855 | 0 | angle[0]-=numLoop*360; |
1856 | 0 | angle[1]-=numLoop*360; |
1857 | 0 | while (angle[0] < -360) { |
1858 | 0 | angle[0]+=360; |
1859 | 0 | angle[1]+=360; |
1860 | 0 | } |
1861 | 0 | } |
1862 | | // we must compute the real bd box |
1863 | 0 | float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 }; |
1864 | 0 | int limitAngle[2]; |
1865 | 0 | for (int i = 0; i < 2; ++i) |
1866 | 0 | limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90); |
1867 | 0 | for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) { |
1868 | 0 | float ang = (bord == limitAngle[0]) ? float(angle[0]) : |
1869 | 0 | (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord); |
1870 | 0 | ang *= float(M_PI/180.); |
1871 | 0 | float const actVal[2] = { std::cos(ang), -std::sin(ang)}; |
1872 | 0 | if (actVal[0] < minVal[0]) minVal[0] = actVal[0]; |
1873 | 0 | else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0]; |
1874 | 0 | if (actVal[1] < minVal[1]) minVal[1] = actVal[1]; |
1875 | 0 | else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1]; |
1876 | 0 | } |
1877 | 0 | MWAWBox2f circleBox=shape.m_initialBox; |
1878 | | // we have the shape box, we need to reconstruct the circle box |
1879 | 0 | if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) { |
1880 | 0 | float const scaling[2]= { (shape.m_initialBox[1][0]-shape.m_initialBox[0][0])/(maxVal[0]-minVal[0]), |
1881 | 0 | (shape.m_initialBox[1][1]-shape.m_initialBox[0][1])/(maxVal[1]-minVal[1]) |
1882 | 0 | }; |
1883 | 0 | float const constant[2]= { shape.m_initialBox[0][0]-minVal[0] *scaling[0], shape.m_initialBox[0][1]-minVal[1] *scaling[1]}; |
1884 | 0 | circleBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]), |
1885 | 0 | MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1])); |
1886 | 0 | } |
1887 | 0 | finalShape = MWAWGraphicShape::pie(shape.m_initialBox, circleBox, MWAWVec2f(float(angle[0]), float(angle[1]))); |
1888 | 0 | break; |
1889 | 0 | } |
1890 | 0 | case 9: { // polyline |
1891 | 0 | if (!hasShapeId || shapeIt->second.m_vertices.size()<2) { |
1892 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[spline]: can not find the point\n")); |
1893 | 0 | return false; |
1894 | 0 | } |
1895 | 0 | if (local.m_style.hasSurface()) |
1896 | 0 | finalShape=MWAWGraphicShape::polygon(shape.m_initialBox); |
1897 | 0 | else |
1898 | 0 | finalShape=MWAWGraphicShape::polyline(shape.m_initialBox); |
1899 | 0 | finalShape.m_vertices=shapeIt->second.m_vertices; |
1900 | 0 | break; |
1901 | 0 | } |
1902 | 0 | case 10: { // spline |
1903 | 0 | if (!hasShapeId || shapeIt->second.m_vertices.size()<2 || (shapeIt->second.m_vertices.size()%4)!=0) { |
1904 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[spline]: can not find the point\n")); |
1905 | 0 | return false; |
1906 | 0 | } |
1907 | 0 | finalShape=MWAWGraphicShape::path(shape.m_initialBox); |
1908 | 0 | std::vector<MWAWGraphicShape::PathData> &path=finalShape.m_path; |
1909 | 0 | path.push_back(MWAWGraphicShape::PathData('M', shapeIt->second.m_vertices[0])); |
1910 | 0 | for (size_t p=3; p < shapeIt->second.m_vertices.size(); p+=4) { |
1911 | 0 | if (p>=4 && shapeIt->second.m_vertices[p-4]!=shapeIt->second.m_vertices[p-3]) |
1912 | 0 | path.push_back(MWAWGraphicShape::PathData('M', shapeIt->second.m_vertices[p-3])); |
1913 | 0 | bool hasFirstC=shapeIt->second.m_vertices[p-3]!=shapeIt->second.m_vertices[p-2]; |
1914 | 0 | bool hasSecondC=shapeIt->second.m_vertices[p-1]!=shapeIt->second.m_vertices[p]; |
1915 | 0 | if (!hasFirstC && !hasSecondC) |
1916 | 0 | path.push_back(MWAWGraphicShape::PathData('L', shapeIt->second.m_vertices[p])); |
1917 | 0 | else |
1918 | 0 | path.push_back(MWAWGraphicShape::PathData('C', shapeIt->second.m_vertices[p], shapeIt->second.m_vertices[p-2], shapeIt->second.m_vertices[p-1])); |
1919 | 0 | } |
1920 | 0 | if (local.m_style.hasSurface()) |
1921 | 0 | path.push_back(MWAWGraphicShape::PathData('Z')); |
1922 | 0 | break; |
1923 | 0 | } |
1924 | 0 | case 52: |
1925 | 0 | if (!hasShapeId) { |
1926 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[special]: can not find the special data\n")); |
1927 | 0 | return false; |
1928 | 0 | } |
1929 | 0 | if (numLines!=1) { |
1930 | | // even if this is possible, using mutiple line on special give really weird results |
1931 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[special]: find a special with multi lines\n")); |
1932 | 0 | m_styleManager->updateLineStyle(shape.m_values[3], local.m_style, numLines, 0); |
1933 | 0 | } |
1934 | 0 | return sendSpecial(listener, shape, shapeIt->second, local); |
1935 | 0 | case 20: |
1936 | 0 | case 99: |
1937 | 0 | if (!hasShapeId) { |
1938 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[group]: can not find the child shape\n")); |
1939 | 0 | return false; |
1940 | 0 | } |
1941 | 0 | if (shapeIt->second.m_children.empty()) |
1942 | 0 | return true; |
1943 | 0 | if (shape.m_type==99) |
1944 | 0 | local.m_style=MWAWGraphicStyle::emptyStyle(); |
1945 | 0 | listener->openGroup(pos); |
1946 | 0 | for (auto cId : shapeIt->second.m_children) |
1947 | 0 | sendShape(int(cId), local); |
1948 | 0 | listener->closeGroup(); |
1949 | 0 | return true; |
1950 | 0 | default: |
1951 | 0 | static bool first=true; |
1952 | 0 | if (first) { |
1953 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: sorry, not implemented[%d]\n", shape.m_type)); |
1954 | 0 | first=false; |
1955 | 0 | } |
1956 | 0 | return false; |
1957 | 0 | } |
1958 | 0 | if (!local.m_transform.isIdentity()) { |
1959 | 0 | finalShape=finalShape.transform(local.m_transform); |
1960 | 0 | MWAWBox2f shapeBox=finalShape.getBdBox(); |
1961 | 0 | pos=MWAWPosition(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
1962 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
1963 | 0 | } |
1964 | 0 | if (shape.m_values[3]==0 || numLines==1) { |
1965 | 0 | listener->insertShape(pos, finalShape, local.m_style); |
1966 | 0 | return true; |
1967 | 0 | } |
1968 | 0 | listener->openGroup(pos); |
1969 | 0 | auto style=local.m_style; |
1970 | 0 | style.m_lineWidth=0; |
1971 | 0 | listener->insertShape(pos, finalShape, style); |
1972 | 0 | style=MWAWGraphicStyle::emptyStyle(); |
1973 | 0 | if (shape.m_values[2]) |
1974 | 0 | m_styleManager->updateLineColor(shape.m_values[2], style); |
1975 | 0 | auto path=finalShape.getPath(true); |
1976 | 0 | for (int l=0; l<numLines; ++l) { |
1977 | 0 | float offset; |
1978 | 0 | m_styleManager->updateLineStyle(shape.m_values[3], style, numLines, l, &offset); |
1979 | 0 | MWAWBox2f decalBox; |
1980 | 0 | auto decalPath=MWAWGraphicShape::offsetVertices(path, offset, decalBox); |
1981 | 0 | auto decalShape=MWAWGraphicShape::path(decalBox); |
1982 | 0 | decalShape.m_path=decalPath; |
1983 | 0 | pos=MWAWPosition(decalBox[0], decalBox.size(), librevenge::RVNG_POINT); |
1984 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
1985 | 0 | listener->insertShape(pos, decalShape, style); |
1986 | 0 | } |
1987 | 0 | listener->closeGroup(); |
1988 | 0 | return true; |
1989 | 0 | } |
1990 | | |
1991 | | bool Canvas5Graph::sendSpecial(MWAWListenerPtr listener, Canvas5GraphInternal::PseudoShape const &pseudoShape, LocalState const &local) |
1992 | 0 | { |
1993 | 0 | return sendSpecial(listener, pseudoShape.m_shape, pseudoShape.m_data, local); |
1994 | 0 | } |
1995 | | |
1996 | | bool Canvas5Graph::sendSpecial(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, Canvas5GraphInternal::ShapeData const &data, |
1997 | | Canvas5Graph::LocalState const &local) |
1998 | 0 | { |
1999 | 0 | if (!data.m_stream) |
2000 | 0 | return false; |
2001 | 0 | if (!listener) { |
2002 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: can not find the listener\n")); |
2003 | 0 | return false; |
2004 | 0 | } |
2005 | 0 | int const vers=version(); |
2006 | 0 | auto &stream=data.getStream(); |
2007 | 0 | MWAWGraphicShape fShape; |
2008 | 0 | auto const &box=shape.m_initialBox; |
2009 | 0 | switch (data.m_type) { |
2010 | 0 | case 0x43436972: { // CCir |
2011 | 0 | if (data.m_specials[0]<=0 || data.m_specials[0]>20) { |
2012 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of circles seems bad\n")); |
2013 | 0 | return false; |
2014 | 0 | } |
2015 | 0 | listener->openGroup(local.m_position); |
2016 | 0 | MWAWVec2f center=0.5f*(box[0]+box[1]); |
2017 | 0 | MWAWVec2f diag=0.5f*box.size(); |
2018 | 0 | for (int i=0; i<data.m_specials[0]; ++i) { |
2019 | 0 | MWAWVec2f newDiag; |
2020 | 0 | if (data.m_specials[1]<=0) |
2021 | 0 | newDiag=float(data.m_specials[0]-i)/float(data.m_specials[0])*diag; |
2022 | 0 | else { |
2023 | 0 | newDiag=diag-float(data.m_specials[1]*i)*MWAWVec2f(1,1); |
2024 | 0 | for (int c=0; c<2; ++c) { |
2025 | 0 | if (newDiag[c]<0) |
2026 | 0 | newDiag[c]=0; |
2027 | 0 | } |
2028 | 0 | } |
2029 | 0 | fShape=MWAWGraphicShape::circle(MWAWBox2f(center-newDiag, center+newDiag)); |
2030 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2031 | 0 | } |
2032 | 0 | listener->closeGroup(); |
2033 | 0 | break; |
2034 | 0 | } |
2035 | 0 | case 0x43756265: { // Cube |
2036 | 0 | if (data.m_vertices.size()!=8) { |
2037 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: can not find the cube vertices\n")); |
2038 | 0 | return false; |
2039 | 0 | } |
2040 | 0 | int const faces[]= { |
2041 | 0 | 0, 2, 6, 4, // X==0 |
2042 | 0 | 1, 3, 7, 5, // X==1 |
2043 | 0 | 0, 1, 5, 4, // Y==0 |
2044 | 0 | 2, 3, 7, 6, // Y==1 |
2045 | 0 | 0, 1, 3, 2, // Z==0 |
2046 | 0 | 4, 5, 7, 6, // Z==1 |
2047 | 0 | }; |
2048 | 0 | listener->openGroup(local.m_position); |
2049 | 0 | fShape.m_type=local.m_style.hasSurface() ? MWAWGraphicShape::Polygon : MWAWGraphicShape::Polyline; |
2050 | 0 | MWAWVec2f const dir=box[1]-box[0]; |
2051 | 0 | MWAWVec2f const dirs[]= {data.m_vertices[1]-data.m_vertices[0], |
2052 | 0 | data.m_vertices[2]-data.m_vertices[0], |
2053 | 0 | data.m_vertices[4]-data.m_vertices[0] |
2054 | 0 | }; |
2055 | 0 | int wh=(dirs[0][0]*dirs[2][1]-dirs[0][1]*dirs[2][0]>0) ? 0 : 1; |
2056 | 0 | wh+=(dirs[1][0]*dirs[2][1]-dirs[1][1]*dirs[2][0]>0) ? 0 : 2; |
2057 | 0 | if (dirs[0][0]*dirs[1][1]-dirs[0][1]*dirs[1][0]>0 && (wh==0 || wh==3)) wh=3-wh; |
2058 | |
|
2059 | 0 | for (int f=0; f<3; ++f) { |
2060 | 0 | size_t face; |
2061 | 0 | switch (f) { |
2062 | 0 | case 0: |
2063 | 0 | face=4; |
2064 | 0 | break; |
2065 | 0 | case 1: |
2066 | 0 | face = (wh==0 || wh==1) ? 2 : 3; |
2067 | 0 | break; |
2068 | 0 | default: |
2069 | 0 | face = (wh==0 || wh==2) ? 1 : 0; |
2070 | 0 | break; |
2071 | 0 | } |
2072 | | |
2073 | 0 | MWAWBox2f shapeBox; |
2074 | 0 | fShape.m_vertices.resize(4); |
2075 | 0 | for (size_t p=0; p<4; ++p) { |
2076 | 0 | MWAWVec2f const &pt=data.m_vertices[size_t(faces[4*face+p])]; |
2077 | 0 | fShape.m_vertices[p]=box[0]+MWAWVec2f(pt[0]*dir[0], pt[1]*dir[1]); |
2078 | 0 | } |
2079 | 0 | fShape.m_bdBox=shapeBox; |
2080 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2081 | 0 | } |
2082 | 0 | listener->closeGroup(); |
2083 | 0 | break; |
2084 | 0 | } |
2085 | 0 | case 0x43765465: // CvTe |
2086 | 0 | return sendCurveText(listener, shape, data, local); |
2087 | 0 | case 0x44494d4e: // DIMN |
2088 | 0 | if (vers<9) |
2089 | 0 | return sendDimension(listener, shape, data, local); |
2090 | 0 | return sendDimension9(listener, shape, data, local); |
2091 | 0 | case 0x65666665: // eff |
2092 | 0 | return sendEffect(listener, shape, data, local); |
2093 | 0 | case 0x45787472: // Extr: extrude |
2094 | 0 | return sendExtrude(listener, shape, data, local); |
2095 | 0 | case 0x4772644d: { // GrdL |
2096 | 0 | listener->openGroup(local.m_position); |
2097 | 0 | if (data.m_grid[0]<=0 || data.m_grid[1]<=0 || |
2098 | 0 | data.m_grid[0]>100 || data.m_grid[1]>100) { |
2099 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial[grid]: can not find the number of rows/columns\n")); |
2100 | 0 | return false; |
2101 | 0 | } |
2102 | 0 | MWAWVec2f dim((box[1][0]-box[0][0])/float(data.m_grid[0]), |
2103 | 0 | (box[1][1]-box[0][1])/float(data.m_grid[1])); |
2104 | 0 | for (int i=0; i<=data.m_grid[0]; ++i) { |
2105 | 0 | float X=box[0][0]+float(i)*dim[0]; |
2106 | 0 | fShape=MWAWGraphicShape::line(MWAWVec2f(X,box[0][1]), MWAWVec2f(X,box[1][1])); |
2107 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2108 | 0 | } |
2109 | 0 | for (int j=0; j<=data.m_grid[1]; ++j) { |
2110 | 0 | float Y=box[0][1]+float(j)*dim[1]; |
2111 | 0 | fShape=MWAWGraphicShape::line(MWAWVec2f(box[0][0],Y), MWAWVec2f(box[1][0],Y)); |
2112 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2113 | 0 | } |
2114 | 0 | listener->closeGroup(); |
2115 | 0 | break; |
2116 | 0 | } |
2117 | 0 | case 0x4e474f4e: { // NGON |
2118 | 0 | if (data.m_specials[0]<=2 || data.m_specials[0]>=50) { // find N=33 |
2119 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of ngon seems bad\n")); |
2120 | 0 | return false; |
2121 | 0 | } |
2122 | 0 | int type=data.m_ngonType; |
2123 | 0 | if (type<0 || type>5) { |
2124 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the ngon's seems bad, assume 4\n")); |
2125 | 0 | type=4; |
2126 | 0 | } |
2127 | 0 | bool needGroup=type!=0 && type!=3 && type!=4; |
2128 | 0 | if (needGroup) |
2129 | 0 | listener->openGroup(local.m_position); |
2130 | 0 | MWAWVec2f const center=0.5f*(box[0]+box[1]); |
2131 | 0 | MWAWVec2f const diag=0.5f*box.size(); |
2132 | 0 | double const angles[]= {M_PI/2-data.m_doubleValues[2], M_PI/2-M_PI/data.m_specials[0]}; |
2133 | 0 | double const step=-2*M_PI/data.m_specials[0]; |
2134 | 0 | float const rad=float(data.m_doubleValues[0]); |
2135 | 0 | if (type==0 || type==1 || type==5) { // border |
2136 | 0 | fShape=MWAWGraphicShape::polygon(box); |
2137 | 0 | for (int i=0; i<data.m_specials[0]; ++i) { |
2138 | 0 | float const angle1=float(angles[0]+i *step); |
2139 | 0 | fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1])); |
2140 | 0 | } |
2141 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2142 | 0 | } |
2143 | 0 | if (type==1 || type==4) { // outside star |
2144 | 0 | fShape=MWAWGraphicShape::polygon(box); |
2145 | 0 | for (int i=0; i<data.m_specials[0]; ++i) { |
2146 | 0 | float const angle1=float(angles[0]+i *step); |
2147 | 0 | fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1])); |
2148 | 0 | float const angle2=float(angles[1]+i *step); |
2149 | 0 | fShape.m_vertices.push_back(center+MWAWVec2f(rad *std::cos(angle2)*diag[0], -rad *std::sin(angle2)*diag[1])); |
2150 | 0 | } |
2151 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2152 | 0 | } |
2153 | 0 | if (type==3) { // inside star |
2154 | 0 | fShape=MWAWGraphicShape::polygon(box); |
2155 | 0 | int id=0; |
2156 | 0 | for (int i=0; i<data.m_specials[0]; ++i) { |
2157 | 0 | float const angle1=float(angles[0]+id *step); |
2158 | 0 | fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1])); |
2159 | 0 | id+=(data.m_specials[0]-1+i%2)/2; |
2160 | 0 | } |
2161 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2162 | 0 | } |
2163 | 0 | if (type==2 || type==5) { // list of segment: center->outside points |
2164 | 0 | for (int i=0; i<data.m_specials[0]; ++i) { |
2165 | 0 | float const angle1=float(angles[0]+i *step); |
2166 | 0 | fShape=MWAWGraphicShape::line(center, center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1])); |
2167 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2168 | 0 | } |
2169 | 0 | } |
2170 | 0 | if (needGroup) |
2171 | 0 | listener->closeGroup(); |
2172 | 0 | break; |
2173 | 0 | } |
2174 | 0 | case 0x4f4c6e6b : { // OLnk |
2175 | 0 | if (data.m_vertices.size()<2) { |
2176 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, can not find the link extremities\n")); |
2177 | 0 | return false; |
2178 | 0 | } |
2179 | 0 | fShape=MWAWGraphicShape::line(data.m_vertices[0], data.m_vertices[1]); |
2180 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2181 | 0 | break; |
2182 | 0 | } |
2183 | 0 | case 0x4d41434f: { // MACO |
2184 | 0 | auto sIt=m_state->m_sendMACOIdSet.find(data.m_macoId); |
2185 | 0 | if (sIt!=m_state->m_sendMACOIdSet.end()) { |
2186 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry find a loop sending MACO\n")); |
2187 | 0 | break; |
2188 | 0 | } |
2189 | 0 | auto maco=m_imageParser->getMACO(data.m_macoId); |
2190 | 0 | if (!maco) |
2191 | 0 | break; |
2192 | | |
2193 | 0 | m_state->m_sendMACOIdSet.insert(data.m_macoId); |
2194 | 0 | listener->openGroup(local.m_position); |
2195 | 0 | m_imageParser->send(maco, listener, shape.m_initialBox, local.m_transform); |
2196 | 0 | listener->closeGroup(); |
2197 | 0 | m_state->m_sendMACOIdSet.erase(data.m_macoId); |
2198 | 0 | break; |
2199 | 0 | } |
2200 | 0 | case 0x706f626a: { // pobj |
2201 | 0 | MWAWEmbeddedObject bitmap; |
2202 | 0 | if (!m_imageParser->getBitmap(data.m_specials[1], bitmap)) |
2203 | 0 | return false; |
2204 | 0 | MWAWTransformation transf; |
2205 | 0 | float rotation=0; |
2206 | 0 | MWAWVec2f shearing; |
2207 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) { |
2208 | 0 | MWAWBox2f shapeBox=transf*shape.m_initialBox; |
2209 | 0 | MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
2210 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
2211 | 0 | MWAWGraphicStyle style(local.m_style); |
2212 | 0 | style.m_rotate=-rotation; |
2213 | 0 | listener->insertPicture(pos, bitmap, style); |
2214 | 0 | } |
2215 | 0 | else |
2216 | 0 | listener->insertPicture(local.m_position, bitmap, local.m_style); |
2217 | 0 | break; |
2218 | 0 | } |
2219 | 0 | case 0x53504952: { // SPIR |
2220 | 0 | if (data.m_specials[0]<=0) { |
2221 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of spirals seems bad\n")); |
2222 | 0 | return false; |
2223 | 0 | } |
2224 | 0 | fShape=MWAWGraphicShape::path(box); |
2225 | 0 | auto const center = box.center(); |
2226 | 0 | auto const dir = 0.5f/4/float(data.m_specials[0]) * box.size(); |
2227 | 0 | std::vector<MWAWGraphicShape::PathData> &path=fShape.m_path; |
2228 | 0 | auto pt=center; |
2229 | 0 | path.push_back(MWAWGraphicShape::PathData('M', center)); |
2230 | 0 | for (int i=1; i<=4*data.m_specials[0]; ++i) { |
2231 | 0 | auto nextPt=center; |
2232 | 0 | nextPt[(i&1)] += ((i%4)<2 ? 1 : -1)*float(i)*dir[(i&1)]; |
2233 | 0 | MWAWVec2f l; |
2234 | 0 | l[1-(i&1)]=pt[1-(i&1)]; |
2235 | 0 | l[(i&1)]=nextPt[(i&1)]; |
2236 | 0 | path.push_back(MWAWGraphicShape::PathData('Q', nextPt, l)); |
2237 | 0 | pt=nextPt; |
2238 | 0 | } |
2239 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2240 | 0 | break; |
2241 | 0 | } |
2242 | 0 | case 0x43574542: { // CWEB: ie a button with 3 state |
2243 | 0 | auto input=stream.input(); |
2244 | 0 | bool isSent=false; |
2245 | 0 | for (auto const &e : data.m_cweb) { |
2246 | 0 | if (!e.valid()) continue; |
2247 | 0 | input->seek(e.begin(), librevenge::RVNG_SEEK_SET); |
2248 | 0 | input->pushLimit(e.end()); |
2249 | 0 | bool ok=true; |
2250 | 0 | std::shared_ptr<Canvas5ImageInternal::VKFLImage> image; |
2251 | 0 | if (!m_imageParser->readVKFL(data.m_stream, e.length(), image)) { |
2252 | 0 | auto &ascFile=stream.ascii(); |
2253 | 0 | ok=false; |
2254 | 0 | ascFile.addPos(e.begin()); |
2255 | 0 | ascFile.addNote("DataShap:special,image:###"); |
2256 | 0 | } |
2257 | 0 | else if (!isSent) { |
2258 | 0 | isSent=true; |
2259 | 0 | listener->openGroup(local.m_position); |
2260 | 0 | m_imageParser->send(image, listener, shape.m_initialBox, local.m_transform); |
2261 | 0 | listener->closeGroup(); |
2262 | 0 | static bool first=true; |
2263 | 0 | if (first) { |
2264 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecialData[button]: send only the first picture (instead of the three state pictures)\n")); |
2265 | 0 | first=false; |
2266 | 0 | } |
2267 | 0 | } |
2268 | 0 | input->popLimit(); |
2269 | 0 | if (!ok) |
2270 | 0 | continue; |
2271 | 0 | #ifndef DEBUG |
2272 | 0 | break; |
2273 | 0 | #endif |
2274 | 0 | } |
2275 | 0 | break; |
2276 | 0 | } |
2277 | 0 | case 0x54585420: { // TXT : only in Vkfl |
2278 | 0 | if (data.m_inMainZone) { |
2279 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecialData: unexpected text in main zone\n")); |
2280 | 0 | return false; |
2281 | 0 | } |
2282 | 0 | auto lStyle=local.m_style; |
2283 | 0 | lStyle.m_lineWidth=0; |
2284 | 0 | std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, stream.input(), shape, data)); |
2285 | 0 | MWAWTransformation transf; |
2286 | 0 | float rotation=0; |
2287 | 0 | MWAWVec2f shearing; |
2288 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) { |
2289 | 0 | MWAWBox2f shapeBox=transf*shape.m_initialBox; |
2290 | 0 | MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
2291 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
2292 | 0 | lStyle.m_rotate=-rotation; |
2293 | 0 | listener->insertTextBox(pos, doc, lStyle); |
2294 | 0 | } |
2295 | 0 | else |
2296 | 0 | listener->insertTextBox(local.m_position, doc, lStyle); |
2297 | 0 | break; |
2298 | 0 | } |
2299 | 0 | case 0x41474946: { // AGIF appear in v6 |
2300 | 0 | auto sIt=m_state->m_sendAGIFIdSet.find(data.m_specials[1]); |
2301 | 0 | if (sIt!=m_state->m_sendAGIFIdSet.end()) { |
2302 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry find a loop sending AGIF\n")); |
2303 | 0 | break; |
2304 | 0 | } |
2305 | 0 | auto gif=m_imageParser->getGIF(data.m_specials[1]); |
2306 | 0 | if (!gif) |
2307 | 0 | break; |
2308 | | |
2309 | 0 | m_state->m_sendAGIFIdSet.insert(data.m_specials[1]); |
2310 | 0 | listener->openGroup(local.m_position); |
2311 | 0 | m_imageParser->send(gif, listener, shape.m_initialBox, local.m_transform); |
2312 | 0 | listener->closeGroup(); |
2313 | 0 | m_state->m_sendAGIFIdSet.erase(data.m_specials[1]); |
2314 | 0 | break; |
2315 | 0 | } |
2316 | 0 | case 0x516b546d: { // QkTm |
2317 | 0 | MWAWEmbeddedObject movie; |
2318 | 0 | if (!m_imageParser->getQuickTime(data.m_specials[0], movie)) |
2319 | 0 | return false; |
2320 | 0 | static bool first=true; |
2321 | 0 | if (first) { |
2322 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial[QkTm]: this file contains movie, there will be probably illisible\n")); |
2323 | 0 | first=false; |
2324 | 0 | } |
2325 | 0 | MWAWTransformation transf; |
2326 | 0 | float rotation=0; |
2327 | 0 | MWAWVec2f shearing; |
2328 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) { |
2329 | 0 | MWAWBox2f shapeBox=transf*shape.m_initialBox; |
2330 | 0 | MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
2331 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
2332 | 0 | MWAWGraphicStyle style(local.m_style); |
2333 | 0 | style.m_rotate=-rotation; |
2334 | 0 | listener->insertPicture(pos, movie, style); |
2335 | 0 | } |
2336 | 0 | else |
2337 | 0 | listener->insertPicture(local.m_position, movie, local.m_style); |
2338 | 0 | break; |
2339 | 0 | } |
2340 | 0 | case 0x23476465: { // #Gde: appear in v6 |
2341 | 0 | if (data.m_gdeType!=3) |
2342 | 0 | return true; |
2343 | 0 | for (auto const § : data.m_sections) { |
2344 | | // add only a basic frame, todo: add also a frame to separate column |
2345 | 0 | fShape=MWAWGraphicShape::rectangle(sect.m_bdBox); |
2346 | 0 | MWAWGraphicStyle basicStyle; |
2347 | 0 | basicStyle.m_lineColor=MWAWColor(127,127,255); |
2348 | 0 | basicStyle.m_lineWidth=0.5f; |
2349 | 0 | send(listener, fShape, local.m_transform, basicStyle); |
2350 | 0 | } |
2351 | 0 | break; |
2352 | 0 | } |
2353 | 0 | case 0x416e4766: // AnGf: appear in v7 |
2354 | 0 | return sendGIF(listener, shape, data, local); |
2355 | 0 | case 0x54656368: // Tech: appear in v7 |
2356 | 0 | return sendTechnical(listener, shape, data, local); |
2357 | 0 | case 0x494d534c: { // SIML: a slice mask?, appear in v8 |
2358 | 0 | fShape=MWAWGraphicShape::rectangle(shape.m_initialBox); |
2359 | 0 | MWAWGraphicStyle basicStyle; |
2360 | 0 | basicStyle.m_lineColor=MWAWColor(250,128,114); |
2361 | 0 | basicStyle.m_lineWidth=0.5f; |
2362 | 0 | basicStyle.setSurfaceColor(MWAWColor(255,255,0),0.5); |
2363 | 0 | send(listener, fShape, local.m_transform, basicStyle); |
2364 | 0 | break; |
2365 | 0 | } |
2366 | 0 | case 0x72656750: { // regP: appear in v8 |
2367 | 0 | listener->openGroup(local.m_position); |
2368 | 0 | MWAWBox2f const &shapeBox=shape.m_initialBox; |
2369 | 0 | auto const center=shapeBox.center(); |
2370 | 0 | MWAWGraphicStyle basicStyle; |
2371 | 0 | for (int i=0; i<3; ++i) { |
2372 | 0 | switch (i) { |
2373 | 0 | case 0: { |
2374 | 0 | MWAWBox2f cBox=shapeBox; |
2375 | 0 | cBox.resizeFromCenter(0.5f*shapeBox.size()); |
2376 | 0 | fShape=MWAWGraphicShape::circle(cBox); |
2377 | 0 | break; |
2378 | 0 | } |
2379 | 0 | case 1: |
2380 | 0 | fShape=MWAWGraphicShape::line(MWAWVec2f(shapeBox[0][0],center[1]), MWAWVec2f(shapeBox[1][0],center[1])); |
2381 | 0 | break; |
2382 | 0 | case 2: |
2383 | 0 | default: |
2384 | 0 | fShape=MWAWGraphicShape::line(MWAWVec2f(center[0],shapeBox[0][1]), MWAWVec2f(center[0],shapeBox[1][1])); |
2385 | 0 | break; |
2386 | 0 | } |
2387 | 0 | send(listener, fShape, local.m_transform, basicStyle); |
2388 | 0 | } |
2389 | 0 | listener->closeGroup(); |
2390 | 0 | break; |
2391 | 0 | } |
2392 | 0 | default: |
2393 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, sending %s is not implemented\n", Canvas5Structure::getString(data.m_type).c_str())); |
2394 | 0 | return false; |
2395 | 0 | } |
2396 | 0 | return true; |
2397 | 0 | } |
2398 | | |
2399 | | bool Canvas5Graph::sendText(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/, Canvas5GraphInternal::ShapeData const &data) |
2400 | 0 | { |
2401 | 0 | if (!data.m_stream) |
2402 | 0 | return false; |
2403 | | |
2404 | 0 | if (!listener) { |
2405 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the listener\n")); |
2406 | 0 | return false; |
2407 | 0 | } |
2408 | 0 | auto &stream=data.getStream(); |
2409 | 0 | int const vers=version(); |
2410 | 0 | libmwaw::DebugStream f; |
2411 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
2412 | 0 | auto input=stream.input(); |
2413 | 0 | auto entry=data.m_entry; |
2414 | 0 | MWAWEntry fontEntry; |
2415 | 0 | if (!data.m_inMainZone) { |
2416 | 0 | if (!entry.valid() || entry.length()<16 || !input->checkPosition(entry.end())) { |
2417 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the text entry\n")); |
2418 | 0 | return false; |
2419 | 0 | } |
2420 | | |
2421 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2422 | 0 | long pos=input->tell(); |
2423 | 0 | f << "Text[zones]:"; |
2424 | 0 | MWAWEntry childs[2]; |
2425 | 0 | for (auto &c : childs) { |
2426 | 0 | c.setBegin(entry.begin()+input->readLong(4)); |
2427 | 0 | c.setLength(input->readLong(4)); |
2428 | 0 | if (c.begin()<entry.begin() || c.end()>entry.end()) { |
2429 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the main child entry\n")); |
2430 | 0 | f << "###"; |
2431 | 0 | ascFile.addPos(pos); |
2432 | 0 | ascFile.addNote(f.str().c_str()); |
2433 | 0 | return false; |
2434 | 0 | } |
2435 | 0 | f << std::hex << c.begin() << "<->" << c.end() << ","; |
2436 | 0 | } |
2437 | 0 | ascFile.addPos(pos); |
2438 | 0 | ascFile.addNote(f.str().c_str()); |
2439 | 0 | entry=childs[0]; |
2440 | 0 | fontEntry=childs[1]; |
2441 | 0 | ascFile.addPos(fontEntry.begin()); |
2442 | 0 | ascFile.addNote("Text[fonts]:"); |
2443 | 0 | } |
2444 | 0 | if (!entry.valid() || entry.length()<20+5*4 || !input->checkPosition(entry.end())) { |
2445 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the text entry\n")); |
2446 | 0 | return false; |
2447 | 0 | } |
2448 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2449 | |
|
2450 | 0 | long pos=input->tell(); |
2451 | 0 | f.str(""); |
2452 | 0 | f << "Entries(Text):"; |
2453 | 0 | int val; |
2454 | 0 | for (int i=0; i<7; ++i) { |
2455 | 0 | val=int(input->readLong(2)); |
2456 | 0 | int const expected[]= {1,0,0xc,0,0,0,1}; |
2457 | 0 | if (val!=expected[i]) |
2458 | 0 | f << "f" << i << "=" << val << ","; |
2459 | 0 | } |
2460 | 0 | val=int(input->readULong(2)); |
2461 | 0 | if (val!=0x7071) f << "fl=" << std::hex << val << std::dec << ","; |
2462 | 0 | val=int(input->readLong(2)); |
2463 | 0 | MWAWParagraph para; |
2464 | 0 | switch (val) { |
2465 | 0 | case -1: |
2466 | 0 | para.m_justify=MWAWParagraph::JustificationRight; |
2467 | 0 | f << "right,"; |
2468 | 0 | break; |
2469 | 0 | case 0: // left |
2470 | 0 | break; |
2471 | 0 | case 1: |
2472 | 0 | para.m_justify=MWAWParagraph::JustificationCenter; |
2473 | 0 | f << "center,"; |
2474 | 0 | break; |
2475 | 0 | case 4: |
2476 | 0 | para.m_justify=MWAWParagraph::JustificationFull; |
2477 | 0 | f << "justify,"; |
2478 | 0 | break; |
2479 | 0 | default: |
2480 | 0 | f << "#align=" << val << ","; |
2481 | 0 | } |
2482 | 0 | val=int(input->readLong(2)); |
2483 | 0 | if (val) f << "f7=" << val << ","; |
2484 | 0 | unsigned long lengths[5], totalLength=0; |
2485 | 0 | f << "len=["; |
2486 | 0 | for (auto &l : lengths) { |
2487 | 0 | l=input->readULong(4); |
2488 | 0 | if (totalLength+l<totalLength) { |
2489 | 0 | f << "###"; |
2490 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: bad lengths\n")); |
2491 | 0 | ascFile.addPos(pos); |
2492 | 0 | ascFile.addNote(f.str().c_str()); |
2493 | 0 | return false; |
2494 | 0 | } |
2495 | 0 | totalLength+=l; |
2496 | 0 | if (l) |
2497 | 0 | f << l << ","; |
2498 | 0 | else |
2499 | 0 | f << "_,"; |
2500 | 0 | } |
2501 | 0 | f << "],"; |
2502 | 0 | if (pos+24+5*4+long(totalLength)<pos+24+20 || pos+24+5*4+long(totalLength)>=entry.end()) { |
2503 | 0 | f << "###"; |
2504 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: bad lengths\n")); |
2505 | 0 | ascFile.addPos(pos); |
2506 | 0 | ascFile.addNote(f.str().c_str()); |
2507 | 0 | return false; |
2508 | 0 | } |
2509 | 0 | ascFile.addPos(pos); |
2510 | 0 | ascFile.addNote(f.str().c_str()); |
2511 | |
|
2512 | 0 | pos=input->tell(); |
2513 | 0 | MWAWEntry textEntry; |
2514 | 0 | textEntry.setBegin(pos); |
2515 | 0 | textEntry.setLength(int(lengths[0])); |
2516 | 0 | input->seek((lengths[0]&1) ? long(lengths[0])+1 : long(lengths[0]), librevenge::RVNG_SEEK_CUR); |
2517 | |
|
2518 | 0 | if (lengths[1]) { |
2519 | 0 | ascFile.addPos(input->tell()); |
2520 | 0 | ascFile.addNote("Text-Unkn:"); |
2521 | 0 | input->seek(long(lengths[1]), librevenge::RVNG_SEEK_CUR); |
2522 | 0 | } |
2523 | 0 | bool ok=true; |
2524 | 0 | if (lengths[2]<8) { |
2525 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 2 seems too short\n")); |
2526 | 0 | ok=false; |
2527 | 0 | } |
2528 | |
|
2529 | 0 | std::map<int, int> posToFontIdMap; |
2530 | 0 | if (ok) { |
2531 | 0 | pos=input->tell(); |
2532 | 0 | f.str(""); |
2533 | 0 | f << "Text-plc:"; |
2534 | 0 | int N0=int(input->readLong(2)); |
2535 | 0 | if (N0!=1) f << "f0=" << N0 << ","; |
2536 | 0 | int N=int(input->readULong(2)); |
2537 | 0 | f << "numPLC=" << N << ","; |
2538 | 0 | if (int(lengths[2])<20+N0*8) { |
2539 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 2 seems bad\n")); |
2540 | 0 | f << "###"; |
2541 | 0 | } |
2542 | 0 | else { |
2543 | 0 | for (int i=0; i<8; ++i) { // 0 |
2544 | 0 | val=int(input->readLong(2)); |
2545 | 0 | if (val) f << "f" << i << "=" << val << ","; |
2546 | 0 | } |
2547 | 0 | f << "plcs=["; |
2548 | 0 | for (int i=0; i<N0; ++i) { |
2549 | 0 | int posi=int(input->readULong(4)); |
2550 | 0 | int id=int(input->readULong(2)); |
2551 | 0 | val=int(input->readLong(2)); // almost always 0, but find 4447|a0 ? |
2552 | 0 | f << posi << ":" << id; |
2553 | 0 | if (val) f << "[" << val << "]"; |
2554 | 0 | f << ","; |
2555 | 0 | posToFontIdMap[posi]=id; |
2556 | 0 | } |
2557 | 0 | f << input->readULong(4); |
2558 | 0 | f << "],"; |
2559 | 0 | } |
2560 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
2561 | 0 | ascFile.addPos(pos); |
2562 | 0 | ascFile.addNote(f.str().c_str()); |
2563 | 0 | input->seek(pos+long(lengths[2]), librevenge::RVNG_SEEK_SET); |
2564 | 0 | } |
2565 | |
|
2566 | 0 | int const styleSz=vers<9 ? 60 : 96; |
2567 | 0 | if (ok && (int(lengths[4])%styleSz)!=0) { |
2568 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 4 seems bads\n")); |
2569 | 0 | ok=false; |
2570 | 0 | } |
2571 | |
|
2572 | 0 | Canvas5StyleManager::StyleList styles; |
2573 | 0 | if (ok) { |
2574 | 0 | int N=int(lengths[4])/styleSz; |
2575 | 0 | styles.m_fonts.resize(size_t(N)); |
2576 | 0 | for (int n=0; n<N; ++n) { |
2577 | 0 | pos=input->tell(); |
2578 | 0 | m_styleManager->readCharStyle(stream, n, styles.m_fonts[size_t(n)], data.m_inMainZone); |
2579 | 0 | input->seek(pos+styleSz, librevenge::RVNG_SEEK_SET); |
2580 | 0 | } |
2581 | 0 | } |
2582 | |
|
2583 | 0 | if (ok && (lengths[3]%16)) { |
2584 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 3 seems bads\n")); |
2585 | 0 | ok=false; |
2586 | 0 | } |
2587 | |
|
2588 | 0 | if (ok) { |
2589 | 0 | int N=int(lengths[3]/16); |
2590 | 0 | for (int n=0; n<N; ++n) { |
2591 | | // unsure maybe |
2592 | | // before v9 n*[2 double:int4 + 32 bytes] |
2593 | | // in v9 n*[2 double + 32 bytes] + n*[2 int] |
2594 | 0 | pos=input->tell(); |
2595 | 0 | f.str(""); |
2596 | 0 | f << "Text-A" << n << ":"; |
2597 | 0 | ascFile.addPos(pos); |
2598 | 0 | ascFile.addNote(f.str().c_str()); |
2599 | 0 | input->seek(pos+16, librevenge::RVNG_SEEK_SET); |
2600 | 0 | } |
2601 | |
|
2602 | 0 | pos=input->tell(); |
2603 | 0 | if (!readDeR3(data.m_stream, styles)) { |
2604 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2605 | 0 | ok=false; |
2606 | 0 | } |
2607 | 0 | } |
2608 | |
|
2609 | 0 | pos=input->tell(); |
2610 | 0 | input->seek(textEntry.begin(), librevenge::RVNG_SEEK_SET); |
2611 | 0 | f.str(""); |
2612 | 0 | f << "Text-text:"; |
2613 | 0 | listener->setParagraph(para); |
2614 | |
|
2615 | 0 | int linkId=0; |
2616 | 0 | bool linkIsOpen=false; |
2617 | 0 | for (int n=0; n<int(lengths[0]); ++n) { |
2618 | 0 | auto it=posToFontIdMap.find(n); |
2619 | 0 | if (it!=posToFontIdMap.end()) { |
2620 | 0 | if (it->second<0 || it->second>=int(styles.m_fonts.size())) { |
2621 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not read find the font=%d\n", it->second)); |
2622 | 0 | } |
2623 | 0 | else { |
2624 | 0 | auto const &font=styles.m_fonts[size_t(it->second)]; |
2625 | 0 | if (font.m_paragraphId>0 && size_t(font.m_paragraphId)<styles.m_paragraphs.size()) |
2626 | 0 | listener->setParagraph(styles.m_paragraphs[size_t(font.m_paragraphId)].first); |
2627 | 0 | listener->setFont(font.m_font); |
2628 | 0 | if (font.m_linkId!=linkId) { |
2629 | 0 | if (linkIsOpen) { |
2630 | 0 | listener->closeLink(); |
2631 | 0 | linkIsOpen=false; |
2632 | 0 | } |
2633 | 0 | linkId=font.m_linkId; |
2634 | 0 | if (linkId) { |
2635 | 0 | auto ref=m_mainParser->getTextLink(linkId); |
2636 | 0 | if (!ref.empty()) { |
2637 | 0 | MWAWLink link; |
2638 | 0 | link.m_HRef=ref.cstr(); |
2639 | 0 | listener->openLink(link); |
2640 | 0 | linkIsOpen=true; |
2641 | 0 | } |
2642 | 0 | } |
2643 | 0 | } |
2644 | 0 | } |
2645 | 0 | } |
2646 | 0 | unsigned char c=(unsigned char)(input->readULong(1)); |
2647 | 0 | f << c; |
2648 | 0 | switch (c) { |
2649 | 0 | case 0x9: |
2650 | 0 | listener->insertTab(); |
2651 | 0 | break; |
2652 | 0 | case 0xd: |
2653 | 0 | if (linkIsOpen) { |
2654 | 0 | listener->closeLink(); |
2655 | 0 | linkIsOpen=false; |
2656 | 0 | } |
2657 | 0 | listener->insertEOL(); |
2658 | 0 | break; |
2659 | 0 | default: |
2660 | 0 | if (c<=0x1f) { |
2661 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendText: find unexpected char=%x\n", (unsigned int)(c))); |
2662 | 0 | } |
2663 | 0 | else |
2664 | 0 | listener->insertCharacter(c); |
2665 | 0 | } |
2666 | 0 | } |
2667 | 0 | if (linkIsOpen) |
2668 | 0 | listener->closeLink(); |
2669 | 0 | ascFile.addPos(textEntry.begin()); |
2670 | 0 | ascFile.addNote(f.str().c_str()); |
2671 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2672 | 0 | return ok; |
2673 | 0 | } |
2674 | | |
2675 | | bool Canvas5Graph::sendEffect(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, |
2676 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
2677 | 0 | { |
2678 | 0 | if (!listener || !data.m_stream) { |
2679 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: can not find the listener\n")); |
2680 | 0 | return false; |
2681 | 0 | } |
2682 | 0 | auto &stream=data.getStream(); |
2683 | 0 | auto input=stream.input(); |
2684 | 0 | auto const &entry=data.m_entry; |
2685 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
2686 | 0 | if (!entry.valid() || entry.length()<8 || !input->checkPosition(entry.end())) { |
2687 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: can not find the number of zone\n")); |
2688 | 0 | return false; |
2689 | 0 | } |
2690 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2691 | 0 | long pos=input->tell(); |
2692 | 0 | libmwaw::DebugStream f; |
2693 | 0 | f << "Entries(Effect):"; |
2694 | 0 | for (int i=0; i<2; ++i) { |
2695 | 0 | int val=int(input->readLong(i==0 ? 4 : 2)); |
2696 | 0 | if (val!=1-i) f << "f" << i << "=" << val << ","; |
2697 | 0 | } |
2698 | 0 | int N=int(input->readULong(2)); |
2699 | 0 | f << "N=" << N << ","; |
2700 | 0 | ascFile.addPos(pos); |
2701 | 0 | ascFile.addNote(f.str().c_str()); |
2702 | |
|
2703 | 0 | if (N>2) |
2704 | 0 | listener->openGroup(local.m_position); |
2705 | 0 | for (int i=0; i<N; ++i) { |
2706 | 0 | pos=input->tell(); |
2707 | 0 | f.str(""); |
2708 | 0 | f << "Effect-" << i << ":"; |
2709 | 0 | long dLen=input->readLong(4); |
2710 | 0 | f << "sz=" << dLen << ","; |
2711 | 0 | long endPos=pos+4+dLen; |
2712 | 0 | if (endPos<pos+4 || !input->checkPosition(endPos)) { |
2713 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: the length seems bad\n")); |
2714 | 0 | f << "###"; |
2715 | 0 | ascFile.addPos(pos); |
2716 | 0 | ascFile.addNote(f.str().c_str()); |
2717 | 0 | break; |
2718 | 0 | } |
2719 | 0 | ascFile.addPos(pos); |
2720 | 0 | ascFile.addNote(f.str().c_str()); |
2721 | 0 | std::shared_ptr<Canvas5ImageInternal::VKFLImage> image; |
2722 | 0 | if (m_imageParser->readVKFL(data.m_stream, dLen, image) && image) |
2723 | 0 | m_imageParser->send(image, listener, shape.m_initialBox, local.m_transform); |
2724 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
2725 | 0 | } |
2726 | |
|
2727 | 0 | if (N>2) |
2728 | 0 | listener->closeGroup(); |
2729 | 0 | return true; |
2730 | 0 | } |
2731 | | |
2732 | | bool Canvas5Graph::sendExtrude(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, |
2733 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
2734 | 0 | { |
2735 | 0 | if (!listener || !data.m_stream) { |
2736 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not find the listener\n")); |
2737 | 0 | return false; |
2738 | 0 | } |
2739 | 0 | auto &stream=data.getStream(); |
2740 | 0 | auto input=stream.input(); |
2741 | 0 | auto const &entry=data.m_entry; |
2742 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
2743 | 0 | if (!entry.valid() || entry.length()<1000+48 || !input->checkPosition(entry.end())) { |
2744 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not find the text entry\n")); |
2745 | 0 | return false; |
2746 | 0 | } |
2747 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2748 | 0 | long pos=input->tell(); |
2749 | 0 | libmwaw::DebugStream f; |
2750 | 0 | f << "Entries(Extrude):"; |
2751 | 0 | ascFile.addPos(pos); |
2752 | 0 | ascFile.addNote(f.str().c_str()); |
2753 | |
|
2754 | 0 | int val; |
2755 | 0 | for (int i=0; i<25; ++i) { |
2756 | | // 0: width |
2757 | | // 1: height |
2758 | | // 2: width[far] |
2759 | | // 12: 0, w, h, w2 |
2760 | | // 13: w/2, h |
2761 | | // |
2762 | |
|
2763 | 0 | pos=input->tell(); |
2764 | 0 | f.str(""); |
2765 | 0 | f << "Extrude-" << i << ":"; |
2766 | 0 | for (int j=0; j<5; ++j) { |
2767 | 0 | val=int(input->readULong(1)); |
2768 | 0 | input->seek(-1, librevenge::RVNG_SEEK_CUR); |
2769 | 0 | if (val==0) { |
2770 | 0 | for (int k=0; k<2; ++k) { |
2771 | 0 | val=int(input->readLong(4)); |
2772 | 0 | if (val) f << "f" << 2*j+k << "=" << val << ","; |
2773 | 0 | } |
2774 | 0 | } |
2775 | 0 | else { |
2776 | 0 | double value; |
2777 | 0 | bool isNAN; |
2778 | 0 | if (!m_mainParser->readDouble(stream, value, isNAN)) { |
2779 | 0 | f << "###"; |
2780 | 0 | input->seek(pos+8*(j+1), librevenge::RVNG_SEEK_SET); |
2781 | 0 | } |
2782 | 0 | else |
2783 | 0 | f << "g" << j << "=" << value << ","; |
2784 | 0 | } |
2785 | 0 | } |
2786 | 0 | ascFile.addPos(pos); |
2787 | 0 | ascFile.addNote(f.str().c_str()); |
2788 | 0 | input->seek(pos+40, librevenge::RVNG_SEEK_SET); |
2789 | 0 | } |
2790 | 0 | pos=input->tell(); |
2791 | 0 | f.str(""); |
2792 | 0 | f << "Extrude-A:"; |
2793 | 0 | int N=0; |
2794 | 0 | for (int i=0; i<12; ++i) { |
2795 | 0 | val=int(input->readLong(4)); |
2796 | 0 | if (!val) continue; |
2797 | 0 | if (i==4) { |
2798 | 0 | N=val; |
2799 | 0 | f << "N=" << N << ","; |
2800 | 0 | } |
2801 | 0 | else |
2802 | 0 | f << "f" << i << "=" << val << ","; |
2803 | 0 | } |
2804 | 0 | if (N<2 || 1048+N*24<1048 || 1048+N*24>entry.length()) { |
2805 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: the number of points seems bad\n")); |
2806 | 0 | f << "###"; |
2807 | 0 | ascFile.addPos(pos); |
2808 | 0 | ascFile.addNote(f.str().c_str()); |
2809 | 0 | return false; |
2810 | 0 | } |
2811 | 0 | ascFile.addPos(pos); |
2812 | 0 | ascFile.addNote(f.str().c_str()); |
2813 | 0 | MWAWPosition const &position=local.m_position; |
2814 | 0 | MWAWVec2f origin=position.origin()+0.5*position.size(); |
2815 | 0 | MWAWVec2f dir=0.5*position.size(); |
2816 | 0 | bool ok=true; |
2817 | |
|
2818 | 0 | std::vector<MWAWVec2f> pts; |
2819 | 0 | for (int i=0; i<N; ++i) { |
2820 | 0 | pos=input->tell(); |
2821 | 0 | f.str(""); |
2822 | 0 | f << "Extrude-B" << i << ":"; |
2823 | 0 | float coords[]= {0,0}; |
2824 | 0 | for (int j=0; j<2; ++j) { |
2825 | 0 | double value; |
2826 | 0 | bool isNAN; |
2827 | 0 | if (!m_mainParser->readDouble(stream, value, isNAN) || value<-2 || value>2) { |
2828 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not read a coordinate\n")); |
2829 | 0 | f << "###"; |
2830 | 0 | input->seek(pos+8*(j+1), librevenge::RVNG_SEEK_SET); |
2831 | 0 | ok=false; |
2832 | 0 | } |
2833 | 0 | else { |
2834 | 0 | coords[j]=float(value); |
2835 | 0 | f << "g" << j << "=" << value << ","; |
2836 | 0 | } |
2837 | 0 | } |
2838 | 0 | pts.push_back(origin+MWAWVec2f(coords[0]*dir[0], coords[1]*dir[1])); |
2839 | 0 | for (int j=0; j<2; ++j) { |
2840 | 0 | val=int(input->readLong(4)); |
2841 | 0 | if (!val) continue; |
2842 | 0 | f << "f" << i << "=" << val << ","; |
2843 | 0 | } |
2844 | 0 | ascFile.addPos(pos); |
2845 | 0 | ascFile.addNote(f.str().c_str()); |
2846 | 0 | input->seek(pos+24, librevenge::RVNG_SEEK_SET); |
2847 | 0 | } |
2848 | 0 | if (input->tell()<entry.end()) { |
2849 | 0 | ascFile.addPos(input->tell()); |
2850 | 0 | ascFile.addNote("Extrude-End:"); |
2851 | 0 | } |
2852 | 0 | if (!ok) |
2853 | 0 | return false; |
2854 | | |
2855 | | // FIXME: sometimes there is multiple contours in this list of points ... |
2856 | 0 | static bool first=true; |
2857 | 0 | if (first) { |
2858 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: sorry, sending extrude's shape is not reliable\n")); |
2859 | 0 | first=false; |
2860 | 0 | } |
2861 | 0 | auto fShape=MWAWGraphicShape::polygon(shape.m_initialBox); |
2862 | 0 | fShape.m_vertices=pts; |
2863 | 0 | send(listener, fShape, local.m_transform, local.m_style); |
2864 | 0 | return true; |
2865 | 0 | } |
2866 | | |
2867 | | bool Canvas5Graph::sendGIF(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, |
2868 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
2869 | 0 | { |
2870 | 0 | if (!listener || !data.m_stream) { |
2871 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the listener\n")); |
2872 | 0 | return false; |
2873 | 0 | } |
2874 | 0 | auto &stream=data.getStream(); |
2875 | 0 | auto input=stream.input(); |
2876 | 0 | auto const &entry=data.m_entry; |
2877 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
2878 | 0 | if (!entry.valid() || entry.length()<104 || !input->checkPosition(entry.end())) { |
2879 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the number of zone\n")); |
2880 | 0 | return false; |
2881 | 0 | } |
2882 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2883 | 0 | long pos=input->tell(); |
2884 | 0 | libmwaw::DebugStream f; |
2885 | 0 | f << "Entries(ANGF):"; |
2886 | 0 | int val=int(input->readULong(4)); |
2887 | 0 | if (val) f << "id=" << std::hex << val << std::dec << ","; |
2888 | 0 | auto len=input->readLong(4); |
2889 | 0 | if (104+len<104 || 104+len>entry.length()) { |
2890 | 0 | f << "###"; |
2891 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the GIF length\n")); |
2892 | 0 | ascFile.addPos(pos); |
2893 | 0 | ascFile.addNote(f.str().c_str()); |
2894 | 0 | return false; |
2895 | 0 | } |
2896 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
2897 | 0 | input->seek(pos+8+80, librevenge::RVNG_SEEK_SET); |
2898 | 0 | int dim[2]; |
2899 | 0 | for (auto &d : dim) |
2900 | 0 | d = int(input->readLong(4)); |
2901 | 0 | f << "dim=" << MWAWVec2i(dim[0],dim[1]) << ","; |
2902 | 0 | val=int(input->readLong(4)); |
2903 | 0 | if (val!=1) |
2904 | 0 | f << "f0=" << val << ","; |
2905 | 0 | val=int(input->readLong(4)); |
2906 | 0 | if (val!=4) |
2907 | 0 | f << "f0=" << val << ","; |
2908 | 0 | ascFile.addPos(pos); |
2909 | 0 | ascFile.addNote(f.str().c_str()); |
2910 | |
|
2911 | 0 | if (!len) { |
2912 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the GIF picture\n")); |
2913 | 0 | } |
2914 | 0 | else { |
2915 | 0 | pos=input->tell(); |
2916 | 0 | librevenge::RVNGBinaryData gif; |
2917 | 0 | if (!input->readDataBlock(len, gif)) { |
2918 | 0 | MWAW_DEBUG_MSG(("Canvas5Image::sendGIF: oops can not retrieve the gif\n")); |
2919 | 0 | ascFile.addPos(pos); |
2920 | 0 | ascFile.addNote("ANGF:###"); |
2921 | 0 | return false; |
2922 | 0 | } |
2923 | | |
2924 | 0 | ascFile.skipZone(pos, pos+len-1); |
2925 | | #ifdef DEBUG_WITH_FILES |
2926 | | std::stringstream s; |
2927 | | static int index=0; |
2928 | | s << "gif" << ++index << ".gif"; |
2929 | | libmwaw::Debug::dumpFile(gif, s.str().c_str()); |
2930 | | #endif |
2931 | |
|
2932 | 0 | MWAWEmbeddedObject obj(gif, "image/gif"); |
2933 | 0 | MWAWTransformation transf; |
2934 | 0 | float rotation=0; |
2935 | 0 | MWAWVec2f shearing; |
2936 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) { |
2937 | 0 | MWAWBox2f shapeBox=transf*shape.m_initialBox; |
2938 | 0 | MWAWPosition posi(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT); |
2939 | 0 | posi.m_anchorTo = MWAWPosition::Page; |
2940 | 0 | MWAWGraphicStyle style(local.m_style); |
2941 | 0 | style.m_rotate=-rotation; |
2942 | 0 | listener->insertPicture(posi, obj, style); |
2943 | 0 | } |
2944 | 0 | else |
2945 | 0 | listener->insertPicture(local.m_position, obj, local.m_style); |
2946 | 0 | } |
2947 | | |
2948 | 0 | while (!input->tell()+4<entry.end()) { |
2949 | | // find 4 blocks with size 28 |
2950 | 0 | pos=input->tell(); |
2951 | 0 | len=input->readLong(4); |
2952 | 0 | if (pos+len<pos+4 || pos+len>entry.end()) { |
2953 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2954 | 0 | break; |
2955 | 0 | } |
2956 | 0 | ascFile.addPos(pos); |
2957 | 0 | ascFile.addNote("ANGF-Dt:"); |
2958 | 0 | input->seek(pos+len, librevenge::RVNG_SEEK_SET); |
2959 | 0 | } |
2960 | |
|
2961 | 0 | pos=input->tell(); |
2962 | 0 | if (pos!=entry.end()) { |
2963 | 0 | MWAW_DEBUG_MSG(("Canvas5Image::sendGIF: find extra data\n")); |
2964 | 0 | ascFile.addPos(pos); |
2965 | 0 | ascFile.addNote("ANGF[extra]:###"); |
2966 | 0 | } |
2967 | 0 | return true; |
2968 | 0 | } |
2969 | | |
2970 | | bool Canvas5Graph::sendTechnical(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, |
2971 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
2972 | 0 | { |
2973 | 0 | if (!listener || !data.m_stream) { |
2974 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not find the listener\n")); |
2975 | 0 | return false; |
2976 | 0 | } |
2977 | 0 | auto &stream=data.getStream(); |
2978 | 0 | auto input=stream.input(); |
2979 | 0 | auto const &entry=data.m_entry; |
2980 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
2981 | 0 | if (!entry.valid() || entry.length()<8 || !input->checkPosition(entry.end())) { |
2982 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not find the number of zone\n")); |
2983 | 0 | return false; |
2984 | 0 | } |
2985 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
2986 | 0 | long pos=input->tell(); |
2987 | 0 | libmwaw::DebugStream f; |
2988 | 0 | f << "Entries(Technical):"; |
2989 | 0 | int N[2]; |
2990 | 0 | f << "N=["; |
2991 | 0 | for (auto &n : N) { |
2992 | 0 | n=m_mainParser->readInteger(stream, 8); |
2993 | 0 | f << n << ","; |
2994 | 0 | } |
2995 | |
|
2996 | 0 | bool isGroupOpened=false; |
2997 | 0 | if (N[0]>1) { |
2998 | 0 | isGroupOpened=true; |
2999 | 0 | listener->openGroup(local.m_position); |
3000 | 0 | } |
3001 | 0 | ascFile.addPos(pos); |
3002 | 0 | ascFile.addNote(f.str().c_str()); |
3003 | 0 | for (int poly=0; poly<N[0]; ++poly) { |
3004 | 0 | f.str(""); |
3005 | 0 | pos=input->tell(); |
3006 | 0 | f << "Technical-T" << poly << ":"; |
3007 | 0 | if (pos+8 > data.m_entry.end()) { |
3008 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a spline\n")); |
3009 | 0 | f << "###"; |
3010 | 0 | ascFile.addPos(pos); |
3011 | 0 | ascFile.addNote(f.str().c_str()); |
3012 | 0 | if (isGroupOpened) |
3013 | 0 | listener->closeGroup(); |
3014 | 0 | return false; |
3015 | 0 | } |
3016 | 0 | int N1[2]; // id, num pt |
3017 | 0 | f << "N=["; |
3018 | 0 | for (auto &n : N1) { |
3019 | 0 | double value; |
3020 | 0 | bool isNan; |
3021 | 0 | if (!m_mainParser->readDouble(stream, value, isNan)) { |
3022 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a generic number\n")); |
3023 | 0 | f << "###"; |
3024 | 0 | ascFile.addPos(pos); |
3025 | 0 | ascFile.addNote(f.str().c_str()); |
3026 | 0 | if (isGroupOpened) |
3027 | 0 | listener->closeGroup(); |
3028 | 0 | return false; |
3029 | 0 | } |
3030 | 0 | n=int(value+0.2); |
3031 | 0 | f << n << ","; |
3032 | 0 | } |
3033 | 0 | f << "],"; |
3034 | 0 | if (N1[1]<0 || (data.m_entry.end()-pos-8)/16<N1[1] || pos+8+16*N1[1] > data.m_entry.end()) { |
3035 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a sub shape\n")); |
3036 | 0 | f << "###"; |
3037 | 0 | ascFile.addPos(pos); |
3038 | 0 | ascFile.addNote(f.str().c_str()); |
3039 | 0 | if (isGroupOpened) |
3040 | 0 | listener->closeGroup(); |
3041 | 0 | return false; |
3042 | 0 | } |
3043 | | |
3044 | 0 | f << "pts=["; |
3045 | 0 | std::vector<MWAWVec2f> points; |
3046 | 0 | for (int p=0; p<N1[1]; ++p) { |
3047 | 0 | double coord[2]; |
3048 | 0 | for (auto &c : coord) { |
3049 | 0 | bool isNan; |
3050 | 0 | long actPos=input->tell(); |
3051 | 0 | if (!m_mainParser->readDouble(stream, c, isNan)) { |
3052 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a number\n")); |
3053 | 0 | f << "###"; |
3054 | 0 | input->seek(actPos+8, librevenge::RVNG_SEEK_SET); |
3055 | 0 | c=0; |
3056 | 0 | } |
3057 | 0 | } |
3058 | 0 | points.push_back(MWAWVec2f(float(coord[1]), float(coord[0]))); |
3059 | 0 | f << points.back() << ","; |
3060 | 0 | } |
3061 | 0 | f << "],"; |
3062 | |
|
3063 | 0 | auto const orig=shape.m_initialBox[0]; |
3064 | 0 | auto const dir=shape.m_initialBox.size(); |
3065 | 0 | for (auto &p : points) |
3066 | 0 | p=orig+MWAWVec2f(p[0]*dir[0],p[1]*dir[1]); |
3067 | 0 | if (points.size()<4) { |
3068 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: the spline seems bad\n")); |
3069 | 0 | f << "###"; |
3070 | 0 | } |
3071 | 0 | else { |
3072 | 0 | auto finalShape=MWAWGraphicShape::path(shape.m_initialBox); |
3073 | 0 | std::vector<MWAWGraphicShape::PathData> &path=finalShape.m_path; |
3074 | 0 | path.push_back(MWAWGraphicShape::PathData('M', points[0])); |
3075 | 0 | for (size_t p=3; p < points.size(); p+=4) { |
3076 | 0 | if (p>=4 && points[p-4]!=points[p-3]) |
3077 | 0 | path.push_back(MWAWGraphicShape::PathData('M', points[p-3])); |
3078 | 0 | bool hasFirstC=points[p-3]!=points[p-2]; |
3079 | 0 | bool hasSecondC=points[p-1]!=points[p]; |
3080 | 0 | if (!hasFirstC && !hasSecondC) |
3081 | 0 | path.push_back(MWAWGraphicShape::PathData('L', points[p])); |
3082 | 0 | else |
3083 | 0 | path.push_back(MWAWGraphicShape::PathData('C', points[p], points[p-2], points[p-1])); |
3084 | 0 | } |
3085 | 0 | if (local.m_style.hasSurface()) |
3086 | 0 | path.push_back(MWAWGraphicShape::PathData('Z')); |
3087 | 0 | send(listener, finalShape, local.m_transform, local.m_style); |
3088 | 0 | } |
3089 | |
|
3090 | 0 | ascFile.addPos(pos); |
3091 | 0 | ascFile.addNote(f.str().c_str()); |
3092 | 0 | } |
3093 | 0 | if (isGroupOpened) |
3094 | 0 | listener->closeGroup(); |
3095 | |
|
3096 | 0 | pos=input->tell(); |
3097 | 0 | f.str(""); |
3098 | 0 | f << "Technical-A:"; |
3099 | 0 | if (pos+16>entry.end()) { |
3100 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read the last part\n")); |
3101 | 0 | f << "###"; |
3102 | 0 | ascFile.addPos(pos); |
3103 | 0 | ascFile.addNote(f.str().c_str()); |
3104 | 0 | return false; |
3105 | 0 | } |
3106 | 0 | for (int i=0; i<6; ++i) { |
3107 | 0 | int val=int(input->readLong(2)); |
3108 | 0 | int const expected[]= {0,0,0,0,0x6ef0,1}; |
3109 | 0 | if (val==expected[i]) |
3110 | 0 | continue; |
3111 | 0 | if (i==3) |
3112 | 0 | f << "fl=" << std::hex << val << std::dec << ","; // 5X01 |
3113 | 0 | else |
3114 | 0 | f << "f" << i << "=" << val << ","; |
3115 | 0 | } |
3116 | 0 | int n=int(input->readULong(4)); |
3117 | 0 | f << "N=" << n << ","; |
3118 | 0 | ascFile.addPos(pos); |
3119 | 0 | ascFile.addNote(f.str().c_str()); |
3120 | |
|
3121 | 0 | for (int i=0; i<n; ++i) { |
3122 | 0 | pos=input->tell(); |
3123 | 0 | f.str(""); |
3124 | 0 | f << "Technical-A" << i << ":"; |
3125 | 0 | if (pos+12>entry.end()) { |
3126 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a type block\n")); |
3127 | 0 | f << "###"; |
3128 | 0 | ascFile.addPos(pos); |
3129 | 0 | ascFile.addNote(f.str().c_str()); |
3130 | 0 | return false; |
3131 | 0 | } |
3132 | 0 | unsigned type=unsigned(input->readULong(4)); |
3133 | 0 | f << Canvas5Structure::getString(type) << ","; |
3134 | 0 | int val=int(input->readLong(4)); |
3135 | 0 | if (val) |
3136 | 0 | f << "id=" << val << ","; |
3137 | 0 | long len=input->readLong(4); |
3138 | 0 | long endPos=pos+12+len; |
3139 | 0 | if (endPos<pos+12 || endPos>entry.end()) { |
3140 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a type block\n")); |
3141 | 0 | f << "###"; |
3142 | 0 | ascFile.addPos(pos); |
3143 | 0 | ascFile.addNote(f.str().c_str()); |
3144 | 0 | return false; |
3145 | 0 | } |
3146 | 0 | switch (type) { |
3147 | 0 | case 0x42507473: { //BPts copy of main zone of points but store with int |
3148 | 0 | libmwaw::DebugStream f2; |
3149 | 0 | while (input->tell()+8<endPos) { |
3150 | 0 | long actPos=input->tell(); |
3151 | 0 | f2.str(""); |
3152 | 0 | f2 << "Technical-bPts:"; |
3153 | 0 | f2 << "id=" << input->readLong(4) << ","; |
3154 | 0 | int nbPts=int(input->readLong(4)); |
3155 | 0 | f2 << "N=" << nbPts << ","; |
3156 | 0 | if (nbPts<4 || (endPos-actPos-8)/8 < nbPts) { |
3157 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
3158 | 0 | break; |
3159 | 0 | } |
3160 | 0 | f2 << "pts=["; |
3161 | 0 | for (int j=0; j<nbPts; ++j) { |
3162 | 0 | float coord[2]; |
3163 | 0 | for (auto &c : coord) c=float(input->readLong(4))/65536; |
3164 | 0 | f2 << MWAWVec2f(coord[0],coord[1]) << ","; |
3165 | 0 | } |
3166 | 0 | f2 << "],"; |
3167 | 0 | ascFile.addPos(actPos); |
3168 | 0 | ascFile.addNote(f2.str().c_str()); |
3169 | 0 | } |
3170 | 0 | if (input->tell()!=endPos) { |
3171 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[bPts]: can not read some data\n")); |
3172 | 0 | ascFile.addPos(input->tell()); |
3173 | 0 | ascFile.addNote("Technical-bPts:###"); |
3174 | 0 | } |
3175 | 0 | break; |
3176 | 0 | } |
3177 | 0 | case 0x4374726c: // Ctrl |
3178 | 0 | if (long(int(len/4))*4!=len || (len%4)!=0) { |
3179 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Ctrl]: unexpected length\n")); |
3180 | 0 | f << "###"; |
3181 | 0 | break; |
3182 | 0 | } |
3183 | 0 | f << "val=["; // [4] or [1,2,3] |
3184 | 0 | for (int j=0; j<int(len)/4; ++j) |
3185 | 0 | f << input->readLong(4) << ","; |
3186 | 0 | f << "],"; |
3187 | 0 | break; |
3188 | 0 | case 0x44697263: // Dirc |
3189 | 0 | if (len!=4) { |
3190 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Dirc]: unexpected length\n")); |
3191 | 0 | f << "###"; |
3192 | 0 | break; |
3193 | 0 | } |
3194 | 0 | f << "f0=" << input->readLong(4) << ","; // 4 |
3195 | 0 | break; |
3196 | 0 | case 0x53686450: // ShdP |
3197 | 0 | if (long(int(len/4))*4!=len || (len%4)!=0) { |
3198 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[ShdP]: unexpected length\n")); |
3199 | 0 | f << "###"; |
3200 | 0 | break; |
3201 | 0 | } |
3202 | 0 | f << "val=["; // [2] or [2,3] |
3203 | 0 | for (int j=0; j<int(len)/4; ++j) |
3204 | 0 | f << input->readLong(4) << ","; |
3205 | 0 | f << "],"; |
3206 | 0 | break; |
3207 | 0 | case 0x53796d6d: // Symm |
3208 | 0 | if (len!=4) { |
3209 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Symm]: unexpected length\n")); |
3210 | 0 | f << "###"; |
3211 | 0 | break; |
3212 | 0 | } |
3213 | 0 | f << "f0=" << input->readLong(4) << ","; // 0 |
3214 | 0 | break; |
3215 | 0 | case 0x54787450: // TxtP |
3216 | 0 | if (len!=4) { |
3217 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[TxtP]: unexpected length\n")); |
3218 | 0 | f << "###"; |
3219 | 0 | break; |
3220 | 0 | } |
3221 | 0 | f << "f0=" << input->readLong(4) << ","; // 1 |
3222 | 0 | break; |
3223 | 0 | case 0x57547874: // WTxt |
3224 | 0 | if (len!=4) { |
3225 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[WTxt]: unexpected length\n")); |
3226 | 0 | f << "###"; |
3227 | 0 | break; |
3228 | 0 | } |
3229 | 0 | f << "f0=" << input->readLong(4) << ","; // 0 |
3230 | 0 | break; |
3231 | 0 | case 0x6b696e64: // kind |
3232 | 0 | if (len!=4) { |
3233 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[kind]: unexpected length\n")); |
3234 | 0 | f << "###"; |
3235 | 0 | break; |
3236 | 0 | } |
3237 | 0 | f << input->readLong(4) << ","; |
3238 | 0 | break; |
3239 | 0 | default: |
3240 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: unexpected type=%s\n", Canvas5Structure::getString(type).c_str())); |
3241 | 0 | f << "###"; |
3242 | 0 | break; |
3243 | 0 | } |
3244 | 0 | if (input->tell()!=endPos) { |
3245 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3246 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
3247 | 0 | } |
3248 | 0 | ascFile.addPos(pos); |
3249 | 0 | ascFile.addNote(f.str().c_str()); |
3250 | 0 | } |
3251 | | |
3252 | 0 | return true; |
3253 | 0 | } |
3254 | | |
3255 | | bool Canvas5Graph::sendCurveText(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/, |
3256 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
3257 | 0 | { |
3258 | 0 | if (!listener || !data.m_stream) { |
3259 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: can not find the listener\n")); |
3260 | 0 | return false; |
3261 | 0 | } |
3262 | 0 | auto &stream=data.getStream(); |
3263 | 0 | auto input=stream.input(); |
3264 | 0 | int const vers=version(); |
3265 | 0 | auto const &entry=data.m_entry; |
3266 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
3267 | 0 | int const headerSz=vers<9 ? 176 : 344; |
3268 | 0 | if (!entry.valid() || entry.length()<headerSz || !input->checkPosition(entry.end())) { |
3269 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: can not find the text entry\n")); |
3270 | 0 | return false; |
3271 | 0 | } |
3272 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
3273 | 0 | long pos=input->tell(); |
3274 | 0 | libmwaw::DebugStream f; |
3275 | 0 | f << "Entries(CurveTxt):"; |
3276 | |
|
3277 | 0 | input->seek(pos+(vers<9 ? 24 : 40), librevenge::RVNG_SEEK_SET); |
3278 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3279 | 0 | f << "unk=["; |
3280 | 0 | MWAWVec2f origin=local.m_position.origin(); |
3281 | 0 | for (int p=0; p<9; ++p) { // pt7: origin bdbox max, pt8 origin bdbox min |
3282 | 0 | float dim[2]; |
3283 | 0 | for (auto &d : dim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8)); |
3284 | 0 | if (vers>=9) |
3285 | 0 | std::swap(dim[0],dim[1]); |
3286 | 0 | f << MWAWVec2f(dim[1],dim[0]) << ","; |
3287 | 0 | if (p==8) origin=MWAWVec2f(dim[1],dim[0]); // checkme: not always fine |
3288 | 0 | } |
3289 | 0 | f << "],"; |
3290 | 0 | int N=int(input->readULong(2)), val; |
3291 | 0 | f << "N=" << N << ","; |
3292 | 0 | for (int i=0; i<4; ++i) { // g0: current style ? |
3293 | 0 | val=int(input->readLong(2)); |
3294 | 0 | if (val!=(i==0 ? 1 : 0)) |
3295 | 0 | f << "g" << i << "=" << val << ","; |
3296 | 0 | } |
3297 | 0 | int nFonts=int(input->readULong(2)); |
3298 | 0 | f << "nFonts=" << nFonts << ","; |
3299 | 0 | int const fontSize=vers<9 ? 72 : 120; |
3300 | 0 | int const textSize=vers<9 ? 60 : 112; |
3301 | 0 | if (headerSz+nFonts*fontSize+N*textSize<0 || headerSz+nFonts*fontSize+N*textSize>entry.length()) { |
3302 | 0 | f << "###"; |
3303 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: N seems bad\n")); |
3304 | 0 | return false; |
3305 | 0 | } |
3306 | 0 | input->seek(pos+headerSz, librevenge::RVNG_SEEK_SET); |
3307 | 0 | ascFile.addPos(pos); |
3308 | 0 | ascFile.addNote(f.str().c_str()); |
3309 | |
|
3310 | 0 | std::vector<Canvas5StyleManager::CharStyle> fonts; |
3311 | 0 | fonts.resize(size_t(nFonts)); |
3312 | 0 | for (size_t i=0; i<size_t(nFonts); ++i) { |
3313 | 0 | pos=input->tell(); |
3314 | 0 | f.str(""); |
3315 | 0 | f << "CurveTxt-F" << i+1 << ":"; |
3316 | 0 | for (int j=0; j<(vers<9 ? 2 : 4); ++j) { // f0: small number |
3317 | 0 | val=int(input->readLong(4)); |
3318 | 0 | if (val) f << "f" << j << "=" << val << ","; |
3319 | 0 | } |
3320 | 0 | ascFile.addPos(pos); |
3321 | 0 | ascFile.addNote(f.str().c_str()); |
3322 | 0 | m_styleManager->readCharStyle(stream, int(i+1), fonts[i]); |
3323 | 0 | for (int j=0; j<(vers<9 ? 2 : 4); ++j) { |
3324 | 0 | val=int(input->readLong(2)); |
3325 | 0 | if (val) f << "f" << j+4 << "=" << val << ","; |
3326 | 0 | } |
3327 | 0 | } |
3328 | |
|
3329 | 0 | if (N>1) |
3330 | 0 | listener->openGroup(local.m_position); |
3331 | 0 | auto fontConverter=m_parserState->m_fontConverter; |
3332 | 0 | MWAWGraphicStyle charStyle=MWAWGraphicStyle::emptyStyle(); |
3333 | 0 | MWAWPosition charPos(local.m_position); |
3334 | 0 | for (int i=0; i<N; ++i) { |
3335 | 0 | pos=input->tell(); |
3336 | 0 | f.str(""); |
3337 | 0 | f << "CurveTxt-" << i << ":"; |
3338 | 0 | int fId=int(input->readULong(2)); |
3339 | 0 | f << "F" << fId+1 << ","; |
3340 | 0 | MWAWFont font; |
3341 | 0 | if (fId>=0 && fId<int(nFonts)) |
3342 | 0 | font=fonts[size_t(fId)].m_font; |
3343 | 0 | else { |
3344 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: find unknow fonts\n")); |
3345 | 0 | f << "###"; |
3346 | 0 | } |
3347 | 0 | librevenge::RVNGString text; |
3348 | 0 | char c=char(input->readULong(1)); |
3349 | 0 | int unicode = fontConverter->unicode(font.id(), (unsigned char)(c)); |
3350 | 0 | if (unicode == -1) { |
3351 | 0 | if (c < 0x20) { |
3352 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: Find odd char %x\n", static_cast<unsigned int>(c))); |
3353 | 0 | } |
3354 | 0 | else |
3355 | 0 | text.append(c); |
3356 | 0 | } |
3357 | 0 | else |
3358 | 0 | libmwaw::appendUnicode(uint32_t(unicode), text); |
3359 | 0 | if (!text.empty()) |
3360 | 0 | f << text.cstr() << ","; |
3361 | 0 | input->seek(1, librevenge::RVNG_SEEK_CUR); |
3362 | 0 | val=int(input->readULong(4)); |
3363 | 0 | if (val!=0x17c94) |
3364 | 0 | f << "f0=" << val << ","; |
3365 | 0 | float angle=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8)); |
3366 | 0 | f << "angle=" << angle << ","; |
3367 | 0 | MWAWVec2f points[5]; |
3368 | 0 | f << "pts=["; |
3369 | 0 | for (auto &pt : points) { // decal, then a box? |
3370 | 0 | float pts[2]; |
3371 | 0 | for (auto &p : pts) p=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8)); |
3372 | 0 | if (vers<9) |
3373 | 0 | pt= MWAWVec2f(pts[1],pts[0]); |
3374 | 0 | else |
3375 | 0 | pt= MWAWVec2f(pts[0],pts[1]); |
3376 | 0 | f << pt << ","; |
3377 | 0 | } |
3378 | 0 | f << "],"; |
3379 | 0 | ascFile.addPos(pos); |
3380 | 0 | ascFile.addNote(f.str().c_str()); |
3381 | 0 | input->seek(pos+textSize, librevenge::RVNG_SEEK_SET); |
3382 | |
|
3383 | 0 | if (text.empty()) continue; |
3384 | 0 | std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, input, text, font)); |
3385 | |
|
3386 | 0 | MWAWTransformation transf; |
3387 | 0 | float rotation=0; |
3388 | 0 | MWAWVec2f shearing; |
3389 | 0 | if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,origin+0.5*points[2]+0.5*points[3])) { |
3390 | 0 | MWAWBox2f shapeBox=transf*MWAWBox2f(origin+points[2],origin+points[3]); |
3391 | 0 | charPos.setOrigin(shapeBox[0]); |
3392 | 0 | charPos.setSize(shapeBox[1]-shapeBox[0]); |
3393 | 0 | charStyle.m_rotate=-angle-rotation; |
3394 | 0 | } |
3395 | 0 | else { |
3396 | 0 | charPos.setOrigin(origin+points[2]); |
3397 | 0 | charPos.setSize(points[3]-points[2]); |
3398 | 0 | charStyle.m_rotate=-angle; |
3399 | 0 | } |
3400 | 0 | listener->insertTextBox(charPos, doc, charStyle); |
3401 | 0 | } |
3402 | 0 | if (N>1) |
3403 | 0 | listener->closeGroup(); |
3404 | |
|
3405 | 0 | pos=input->tell(); |
3406 | 0 | f.str(""); |
3407 | 0 | f << "CurveTxt-End:"; |
3408 | 0 | ascFile.addPos(pos); |
3409 | 0 | ascFile.addNote(f.str().c_str()); |
3410 | 0 | return true; |
3411 | 0 | } |
3412 | | |
3413 | | bool Canvas5Graph::sendDimension(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, |
3414 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
3415 | 0 | { |
3416 | 0 | if (!listener || !data.m_stream || version()>=9) { |
3417 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not find the listener\n")); |
3418 | 0 | return false; |
3419 | 0 | } |
3420 | 0 | auto &stream=data.getStream(); |
3421 | 0 | auto input=stream.input(); |
3422 | 0 | auto const &entry=data.m_entry; |
3423 | 0 | if (!entry.valid() || !input->checkPosition(entry.end())) { |
3424 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not find the shape enntry\n")); |
3425 | 0 | return false; |
3426 | 0 | } |
3427 | | |
3428 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
3429 | 0 | libmwaw::DebugStream f; |
3430 | 0 | f << "Entries(Dimension):"; |
3431 | 0 | if (entry.length()<420) { |
3432 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: the data seens too short\n")); |
3433 | 0 | f << "###sz"; |
3434 | 0 | ascFile.addPos(entry.begin()); |
3435 | 0 | ascFile.addNote(f.str().c_str()); |
3436 | 0 | return false; |
3437 | 0 | } |
3438 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
3439 | 0 | int type=int(input->readLong(2)); // 1-15 |
3440 | 0 | if (type) f << "type=" << type << ","; |
3441 | 0 | int val=int(input->readLong(2)); // 0 |
3442 | 0 | if (val) f << "f0=" << val << ","; |
3443 | 0 | f << "points=["; |
3444 | 0 | std::vector<MWAWVec2f> pts; |
3445 | 0 | for (int i=0; i<18; ++i) { |
3446 | 0 | float dims[2]; |
3447 | | // fract type: between -2 and 2 |
3448 | 0 | for (auto &d : dims) d=4*float(input->readLong(4))/65536.f/65536.f; |
3449 | 0 | pts.push_back(MWAWVec2f(dims[1],dims[0])); |
3450 | 0 | f << pts.back() << ","; |
3451 | 0 | } |
3452 | 0 | f << "],"; |
3453 | 0 | ascFile.addPos(entry.begin()); |
3454 | 0 | ascFile.addNote(f.str().c_str()); |
3455 | |
|
3456 | 0 | long posi=input->tell(); |
3457 | 0 | f.str(""); |
3458 | 0 | f << "Dimension[data1]:"; |
3459 | 0 | input->seek(posi+40, librevenge::RVNG_SEEK_SET); |
3460 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3461 | 0 | bool arrowInside=true; |
3462 | 0 | bool hasFrame=false; |
3463 | 0 | for (int i=0; i<3; ++i) { |
3464 | 0 | val=int(input->readLong(2)); |
3465 | 0 | int const expected[]= {1,0,0}; |
3466 | 0 | if (val==expected[i]) continue; |
3467 | 0 | char const *wh[]= {"arrows[inside]", "text[centered]", "frame[text]"}; |
3468 | 0 | if (val==0) { |
3469 | 0 | if (i==0) arrowInside=false; |
3470 | 0 | f << wh[i] << "=off,"; |
3471 | 0 | } |
3472 | 0 | else if (val==1) { |
3473 | 0 | if (i==2) hasFrame=true; |
3474 | 0 | f << wh[i] << "=on,"; |
3475 | 0 | } |
3476 | 0 | else |
3477 | 0 | f << "###" << wh[i] << "=" << val << ","; |
3478 | 0 | } |
3479 | 0 | for (int i=0; i<5; ++i) { |
3480 | 0 | val=int(input->readLong(2)); |
3481 | 0 | int const expected[]= { 1, 1, 1, 0, 3}; |
3482 | 0 | if (val==expected[i]) continue; |
3483 | 0 | char const *wh[]= { |
3484 | 0 | "leader", // none, left, right, automatic |
3485 | 0 | nullptr, |
3486 | 0 | "display[text]", // hori, hori/90, aligned, above, below |
3487 | 0 | "what", // 1: line, 3: arc? |
3488 | 0 | "precision", // X, X.X, X.XX, X.XXX, X.XXXX, X X/X |
3489 | 0 | }; |
3490 | 0 | if (i==3 && val==3) |
3491 | 0 | f << "print[angle],"; |
3492 | 0 | else if (wh[i]) |
3493 | 0 | f << wh[i] << "=" << val << ","; |
3494 | 0 | else |
3495 | 0 | f << "f" << i << "=" << val << ","; |
3496 | 0 | } |
3497 | 0 | f << "tolerances=["; |
3498 | 0 | for (int i=0; i<3; ++i) f << float(input->readLong(4))/65536.f << ","; |
3499 | 0 | f << "],"; |
3500 | 0 | val=int(input->readLong(2)); |
3501 | 0 | if (val!=1) |
3502 | 0 | f << "f6=" << val << ","; |
3503 | 0 | librevenge::RVNGString format; |
3504 | 0 | long actPos=input->tell(); |
3505 | 0 | if (m_mainParser->readString(stream, format, 19)) |
3506 | 0 | f << "unit=" << format.cstr() << ","; |
3507 | 0 | else { |
3508 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not read the format's name\n")); |
3509 | 0 | f << "###format,"; |
3510 | 0 | input->seek(actPos+20, librevenge::RVNG_SEEK_SET); |
3511 | 0 | } |
3512 | 0 | ascFile.addDelimiter(input->tell(), '|'); |
3513 | 0 | input->seek(posi+162, librevenge::RVNG_SEEK_SET); |
3514 | 0 | ascFile.addPos(posi); |
3515 | 0 | ascFile.addNote(f.str().c_str()); |
3516 | |
|
3517 | 0 | posi=input->tell(); |
3518 | 0 | f.str(""); |
3519 | 0 | f << "Dimension-format:"; |
3520 | 0 | input->seek(posi+22, librevenge::RVNG_SEEK_SET); |
3521 | 0 | ascFile.addDelimiter(input->tell(), '|'); |
3522 | 0 | if (m_mainParser->readString(stream, format, 19)) |
3523 | 0 | f << "name=" << format.cstr() << ","; |
3524 | 0 | else { |
3525 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not read the format's name\n")); |
3526 | 0 | f << "###format,"; |
3527 | 0 | } |
3528 | 0 | input->seek(posi+22+20, librevenge::RVNG_SEEK_SET); |
3529 | 0 | ascFile.addDelimiter(input->tell(), '|'); |
3530 | 0 | ascFile.addPos(posi); |
3531 | 0 | ascFile.addNote(f.str().c_str()); |
3532 | |
|
3533 | 0 | MWAWVec2f bDir=shape.m_initialBox.size(); |
3534 | 0 | for (auto &pt : pts) |
3535 | 0 | pt=shape.m_initialBox[0]+MWAWVec2f(pt[0]*bDir[0], pt[1]*bDir[1]); |
3536 | |
|
3537 | 0 | MWAWGraphicStyle style=local.m_style; |
3538 | 0 | listener->openGroup(local.m_position); |
3539 | |
|
3540 | 0 | MWAWGraphicShape fShape; |
3541 | 0 | MWAWBox2f shapeBox; |
3542 | |
|
3543 | 0 | MWAWVec2f textOrigin; |
3544 | 0 | librevenge::RVNGString text; |
3545 | 0 | if (type==12) { // a sector instead of a line |
3546 | | // circle between pts[0], pts[1]->pts[2] |
3547 | 0 | float angles[2]; |
3548 | 0 | for (size_t i=0; i<2; ++i) { |
3549 | 0 | MWAWVec2f dir=pts[i+1]-pts[0]; |
3550 | 0 | angles[i]=180*std::atan2(-dir[1],dir[0])/float(M_PI); |
3551 | 0 | } |
3552 | 0 | if (std::isnan(angles[0]) || std::isnan(angles[1])) { |
3553 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not compute the sector angles\n")); |
3554 | 0 | } |
3555 | 0 | else { |
3556 | 0 | if (angles[1]<angles[0]) |
3557 | 0 | std::swap(angles[0],angles[1]); |
3558 | 0 | MWAWVec2f dir=pts[5]-pts[0]; |
3559 | 0 | float len=std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]); |
3560 | 0 | MWAWBox2f circleBox(pts[0]-len *MWAWVec2f(1,1), pts[0]+len *MWAWVec2f(1,1)); |
3561 | 0 | for (int st=0; st<2; ++st) { |
3562 | 0 | float angle[2]; |
3563 | 0 | if (arrowInside) { |
3564 | 0 | if (st==1) |
3565 | 0 | break; |
3566 | 0 | angle[0]=angles[0]; |
3567 | 0 | angle[1]=angles[1]; |
3568 | 0 | } |
3569 | 0 | else if (st==0) { |
3570 | 0 | angle[0]=angles[0]-10; |
3571 | 0 | angle[1]=angles[0]; |
3572 | 0 | } |
3573 | 0 | else { |
3574 | 0 | angle[0]=angles[1]; |
3575 | 0 | angle[1]=angles[1]+10; |
3576 | 0 | } |
3577 | | // we must compute the real bd box |
3578 | 0 | float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 }; |
3579 | 0 | int limitAngle[2]; |
3580 | 0 | for (int i = 0; i < 2; ++i) |
3581 | 0 | limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90); |
3582 | 0 | for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) { |
3583 | 0 | float ang = (bord == limitAngle[0]) ? float(angle[0]) : |
3584 | 0 | (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord); |
3585 | 0 | ang *= float(M_PI/180.); |
3586 | 0 | float const actVal[2] = { std::cos(ang), -std::sin(ang)}; |
3587 | 0 | if (actVal[0] < minVal[0]) minVal[0] = actVal[0]; |
3588 | 0 | else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0]; |
3589 | 0 | if (actVal[1] < minVal[1]) minVal[1] = actVal[1]; |
3590 | 0 | else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1]; |
3591 | 0 | } |
3592 | 0 | MWAWBox2f arcBox=circleBox; |
3593 | | // we have the shape box, we need to reconstruct the circle box |
3594 | 0 | if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) { |
3595 | 0 | float scaling[2]= { (circleBox[1][0]-circleBox[0][0])/(maxVal[0]-minVal[0]), |
3596 | 0 | (circleBox[1][1]-circleBox[0][1])/(maxVal[1]-minVal[1]) |
3597 | 0 | }; |
3598 | 0 | for (auto &s : scaling) { |
3599 | 0 | if (s>1e7) |
3600 | 0 | s=100; |
3601 | 0 | else if (s<-1e7) |
3602 | 0 | s=-100; |
3603 | 0 | } |
3604 | 0 | float const constant[2]= { circleBox[0][0]-minVal[0] *scaling[0], circleBox[0][1]-minVal[1] *scaling[1]}; |
3605 | 0 | arcBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]), |
3606 | 0 | MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1])); |
3607 | 0 | } |
3608 | 0 | style.setSurfaceColor(MWAWColor::white(), 0); |
3609 | 0 | style.m_arrows[st]=arrowInside ? MWAWGraphicStyle::Arrow::plain(): MWAWGraphicStyle::Arrow(); |
3610 | 0 | style.m_arrows[1-st]=MWAWGraphicStyle::Arrow::plain(); |
3611 | |
|
3612 | 0 | fShape = MWAWGraphicShape::arc(arcBox, circleBox, MWAWVec2f(float(angle[0]), float(angle[1]))); |
3613 | 0 | send(listener, fShape, local.m_transform, style); |
3614 | 0 | } |
3615 | 0 | } |
3616 | | // TODO: use format for unit, ... |
3617 | 0 | textOrigin=pts[9]; |
3618 | 0 | std::stringstream s; |
3619 | 0 | s << std::setprecision(0) << std::fixed << angles[1]-angles[0] << " "; |
3620 | 0 | text=s.str().c_str(); |
3621 | 0 | libmwaw::appendUnicode(0xb0, text); |
3622 | 0 | } |
3623 | 0 | else if (type>12 && type<=14) { // radius/diameter inside an circle/ellipse |
3624 | 0 | size_t orig=type==13 ? 0 : 4; |
3625 | 0 | fShape=MWAWGraphicShape::line(pts[orig],pts[3]); |
3626 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
3627 | 0 | send(listener, fShape, local.m_transform, style); |
3628 | |
|
3629 | 0 | fShape=MWAWGraphicShape::line(pts[1],pts[3]); |
3630 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
3631 | 0 | send(listener, fShape, local.m_transform, style); |
3632 | |
|
3633 | 0 | textOrigin=pts[1]; |
3634 | | // TODO: use format for unit, ... |
3635 | 0 | MWAWVec2f lineSz=pts[orig]-pts[3]; |
3636 | 0 | std::stringstream s; |
3637 | 0 | s << std::setprecision(0) << std::fixed << std::sqrt(lineSz[0]*lineSz[0]+lineSz[1]*lineSz[1]) << " pt"; |
3638 | 0 | text=s.str().c_str(); |
3639 | 0 | } |
3640 | 0 | else if (type==15) { // four segments, no text |
3641 | 0 | for (size_t i=0; i<4; ++i) { |
3642 | 0 | fShape=MWAWGraphicShape::line(pts[1],pts[i+14]); |
3643 | 0 | send(listener, fShape, local.m_transform, style); |
3644 | 0 | } |
3645 | 0 | } |
3646 | 0 | else { |
3647 | 0 | for (size_t i=0; i<2; ++i) { |
3648 | 0 | size_t const limits[]= {4,6, 7,9 }; // outside1, outside2 |
3649 | 0 | fShape=MWAWGraphicShape::line(pts[limits[2*i]],pts[limits[2*i+1]]); |
3650 | 0 | send(listener, fShape, local.m_transform, style); |
3651 | 0 | } |
3652 | |
|
3653 | 0 | if (arrowInside) { |
3654 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
3655 | 0 | fShape=MWAWGraphicShape::line(pts[5],pts[8]); |
3656 | 0 | send(listener, fShape, local.m_transform, style); |
3657 | 0 | } |
3658 | 0 | else { |
3659 | 0 | style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain(); |
3660 | 0 | for (size_t i=0; i<2; ++i) { |
3661 | 0 | size_t const limits[]= {5,10, 8,11 }; // arrows1, arrows2 |
3662 | 0 | fShape=MWAWGraphicShape::line(pts[limits[2*i]],pts[limits[2*i+1]]); |
3663 | 0 | send(listener, fShape, local.m_transform, style); |
3664 | 0 | } |
3665 | 0 | } |
3666 | | |
3667 | | // sometimes there is also a line to rely pts[5/8] and the text |
3668 | |
|
3669 | 0 | textOrigin=pts[3]; |
3670 | | // TODO: use format for unit, ... |
3671 | 0 | MWAWVec2f lineSz=pts[5]-pts[8]; |
3672 | 0 | std::stringstream s; |
3673 | 0 | s << std::setprecision(0) << std::fixed << std::sqrt(lineSz[0]*lineSz[0]+lineSz[1]*lineSz[1]) << " pt"; |
3674 | 0 | text=s.str().c_str(); |
3675 | 0 | } |
3676 | | // TODO: use local style to define the text's color... |
3677 | 0 | if (!text.empty()) |
3678 | 0 | send(listener, text, textOrigin, local.m_transform, MWAWFont(3,10), hasFrame); |
3679 | |
|
3680 | 0 | listener->closeGroup(); |
3681 | 0 | return true; |
3682 | 0 | } |
3683 | | |
3684 | | namespace Canvas5GraphInternal |
3685 | | { |
3686 | | bool intersect(MWAWVec2f const &A, MWAWVec2f const &dirA, MWAWVec2f const &B, MWAWVec2f const &dirB, MWAWVec2f &pt) |
3687 | 0 | { |
3688 | 0 | float cross=dirA[0]*dirB[1]-dirA[1]*dirB[0]; |
3689 | 0 | if (cross>-1e-9f && cross<1e-9f) return false; |
3690 | 0 | MWAWVec2f AB=B-A; |
3691 | 0 | float alpha=(AB[0]*dirB[1]-AB[1]*dirB[0])/cross; |
3692 | 0 | pt=A+alpha*dirA; |
3693 | 0 | return true; |
3694 | 0 | } |
3695 | | |
3696 | | std::vector<MWAWVec2f> intersect(MWAWBox2f const &box, MWAWVec2f const &pt, MWAWVec2f const &dir) |
3697 | 0 | { |
3698 | 0 | std::vector<MWAWVec2f> res; |
3699 | 0 | for (int d=0; d<2; ++d) { |
3700 | 0 | for (int wh=0; wh<2; ++wh) { |
3701 | 0 | MWAWVec2f pts[]= {box[0],box[1]}; |
3702 | 0 | pts[1-wh][1-d]=pts[wh][1-d]; |
3703 | 0 | MWAWVec2f AB=pts[1]-pts[0]; |
3704 | 0 | float cross=AB[0]*dir[1]-AB[1]*dir[0]; |
3705 | 0 | if (cross>-1e-9f && cross<1e-9f) continue; |
3706 | 0 | MWAWVec2f AO=pt-pts[0]; |
3707 | 0 | float alpha=(AO[0]*dir[1]-AO[1]*dir[0])/cross; |
3708 | 0 | if (alpha<-1e-9f || alpha>1+1e-9f) continue; |
3709 | 0 | if (alpha<0) |
3710 | 0 | alpha=0; |
3711 | 0 | else if (alpha>1) |
3712 | 0 | alpha=1; |
3713 | 0 | res.push_back((1-alpha)*pts[0]+alpha *pts[1]); |
3714 | 0 | } |
3715 | 0 | } |
3716 | 0 | for (size_t i=0; i<res.size(); ++i) { |
3717 | 0 | for (size_t j=i+1; j<res.size(); ++j) { |
3718 | 0 | MWAWVec2f diff=res[j]-res[i]; |
3719 | 0 | if (diff[0]*diff[0]+diff[1]*diff[1]>1e-8f) |
3720 | 0 | continue; |
3721 | 0 | std::swap(res[j],res.back()); |
3722 | 0 | res.resize(res.size()-1); |
3723 | 0 | --j; |
3724 | 0 | } |
3725 | 0 | } |
3726 | 0 | if (res.size()!=2) { |
3727 | 0 | MWAW_DEBUG_MSG(("Canvas5GraphInternal::intersect:: find %d intersections\n", int(res.size()))); |
3728 | 0 | return std::vector<MWAWVec2f>(); |
3729 | 0 | } |
3730 | 0 | return res; |
3731 | 0 | } |
3732 | | } |
3733 | | bool Canvas5Graph::sendDimension9(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/, |
3734 | | Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local) |
3735 | 0 | { |
3736 | 0 | if (!listener || !data.m_stream || version()<9) { |
3737 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not find the listener\n")); |
3738 | 0 | return false; |
3739 | 0 | } |
3740 | 0 | auto &stream=data.getStream(); |
3741 | 0 | auto input=stream.input(); |
3742 | 0 | auto const &entry=data.m_entry; |
3743 | 0 | if (!entry.valid() || !input->checkPosition(entry.end())) { |
3744 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not find the shape enntry\n")); |
3745 | 0 | return false; |
3746 | 0 | } |
3747 | | |
3748 | 0 | libmwaw::DebugFile &ascFile = stream.ascii(); |
3749 | 0 | libmwaw::DebugStream f; |
3750 | 0 | f << "Entries(Dimension):"; |
3751 | 0 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
3752 | 0 | long zoneSize=input->readLong(4); |
3753 | 0 | if (zoneSize<0x796 || zoneSize>entry.end()) { |
3754 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not read the zone size\n")); |
3755 | 0 | f << "###sz"; |
3756 | 0 | ascFile.addPos(entry.begin()); |
3757 | 0 | ascFile.addNote(f.str().c_str()); |
3758 | 0 | return false; |
3759 | 0 | } |
3760 | 0 | int val=int(input->readLong(4)); // 4 |
3761 | 0 | if (val!=4) f << "f0=" << val << ","; |
3762 | 0 | int type=int(input->readLong(1)); |
3763 | 0 | if (type) f << "type=" << type << ","; |
3764 | 0 | input->seek(1, librevenge::RVNG_SEEK_CUR); |
3765 | 0 | val=int(input->readLong(4)); // 1 |
3766 | 0 | if (val!=1) f << "f1=" << val << ","; |
3767 | 0 | MWAWBox2f bdbox; |
3768 | 0 | for (int i=0; i<2; ++i) { |
3769 | 0 | float dims[2]; |
3770 | | // fract type: between -2 and 2 |
3771 | 0 | for (auto &d : dims) d=float(m_mainParser->readDouble(stream,8)); |
3772 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3773 | 0 | if (i==0) |
3774 | 0 | bdbox.setMin(MWAWVec2f(dims[0],dims[1])); |
3775 | 0 | else |
3776 | 0 | bdbox.setMax(MWAWVec2f(dims[0],dims[1])); |
3777 | 0 | } |
3778 | 0 | f << "box=" << bdbox << ","; |
3779 | 0 | for (int i=0; i<2; ++i) { |
3780 | 0 | val=int(input->readLong(4)); |
3781 | 0 | if (val) |
3782 | 0 | f << "f" << i << "=" << val << ","; |
3783 | 0 | } |
3784 | 0 | long posi=input->tell(); |
3785 | 0 | int N=0; |
3786 | 0 | bool finishedWithN=type!=4 && type!=7; |
3787 | 0 | if (finishedWithN) { |
3788 | 0 | input->seek(entry.end()-4, librevenge::RVNG_SEEK_SET); |
3789 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3790 | 0 | N=int(input->readULong(4)); |
3791 | 0 | f << "N=" << N << ","; |
3792 | 0 | input->seek(posi, librevenge::RVNG_SEEK_SET); |
3793 | 0 | } |
3794 | 0 | ascFile.addPos(entry.begin()); |
3795 | 0 | ascFile.addNote(f.str().c_str()); |
3796 | |
|
3797 | 0 | for (int i=0; i<2; ++i) { |
3798 | 0 | posi=input->tell(); |
3799 | 0 | f.str(""); |
3800 | 0 | f << "Dimension[" << (i==0 ? "prefix" : "suffix") << "]:"; |
3801 | 0 | std::string name; |
3802 | 0 | for (int j=0; j<64; ++j) { |
3803 | 0 | char c=char(input->readULong(1)); |
3804 | 0 | if (!c) |
3805 | 0 | break; |
3806 | 0 | name+=c; |
3807 | 0 | } |
3808 | 0 | if (!name.empty()) |
3809 | 0 | f << name << ","; |
3810 | 0 | input->seek(posi+64, librevenge::RVNG_SEEK_SET); |
3811 | 0 | val=int(input->readLong(4)); |
3812 | 0 | if (val) |
3813 | 0 | f << "f0=" << val << ","; |
3814 | 0 | ascFile.addPos(posi); |
3815 | 0 | ascFile.addNote(f.str().c_str()); |
3816 | 0 | } |
3817 | 0 | for (int i=0; i<12; ++i) { |
3818 | 0 | posi=input->tell(); |
3819 | 0 | f.str(""); |
3820 | 0 | f << "Dimension[data" << i << "]:"; |
3821 | 0 | ascFile.addPos(posi); |
3822 | 0 | ascFile.addNote(f.str().c_str()); |
3823 | 0 | input->seek(posi+(i<11 ? 128 : 112), librevenge::RVNG_SEEK_SET); |
3824 | 0 | } |
3825 | |
|
3826 | 0 | posi=input->tell(); |
3827 | 0 | f.str(""); |
3828 | 0 | f << "Dimension[format]:"; |
3829 | 0 | int arrowType=3; |
3830 | 0 | for (int i=0; i<8; ++i) { // f5=f6=3, f7=2 |
3831 | 0 | val=int(input->readLong(4)); |
3832 | 0 | int const expected[]= {0,0,0,0,0, 3,3,2}; |
3833 | 0 | if (val==expected[i]) continue; |
3834 | 0 | if (i==5) { |
3835 | 0 | arrowType=val; |
3836 | 0 | f << "arrow=" << val << ","; // 0-3: none, inside, outside, auto |
3837 | 0 | } |
3838 | 0 | else if (i==7) |
3839 | 0 | f << "witness[line]=" << val << ","; // 0-2: none, short, long |
3840 | 0 | else |
3841 | 0 | f << "f" << i << "=" << val << ","; |
3842 | 0 | } |
3843 | 0 | MWAWFont font; |
3844 | 0 | f << "font=["; |
3845 | 0 | font.setSize(float(m_mainParser->readDouble(stream, 8))); |
3846 | 0 | val=int(input->readULong(4)); // 0 |
3847 | 0 | uint32_t flags = 0; |
3848 | 0 | if (val&0x1) flags |= MWAWFont::boldBit; |
3849 | 0 | if (val&0x2) flags |= MWAWFont::italicBit; |
3850 | 0 | if (val&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple); |
3851 | 0 | if (val&0x8) flags |= MWAWFont::embossBit; |
3852 | 0 | if (val&0x10) flags |= MWAWFont::shadowBit; |
3853 | 0 | if (val&0x80) font.setStrikeOutStyle(MWAWFont::Line::Simple); |
3854 | 0 | font.setFlags(flags); |
3855 | 0 | val &= 0xffffff60; |
3856 | 0 | if (val) |
3857 | 0 | f << "flag=" << std::hex << val << std::dec << ","; |
3858 | 0 | std::string name; |
3859 | 0 | for (int i=0; i<32; ++i) { |
3860 | 0 | char c=char(input->readULong(1)); |
3861 | 0 | if (!c) |
3862 | 0 | break; |
3863 | 0 | name+=c; |
3864 | 0 | } |
3865 | 0 | auto fontConverter=m_parserState->m_fontConverter; |
3866 | 0 | std::string const family=m_mainParser->isWindowsFile() ? "CP1252" : ""; |
3867 | 0 | if (!name.empty()) |
3868 | 0 | font.setId(fontConverter->getId(name, family)); |
3869 | 0 | f << font.getDebugString(fontConverter) << ","; |
3870 | 0 | f << "],"; |
3871 | 0 | input->seek(posi+76, librevenge::RVNG_SEEK_SET); |
3872 | 0 | ascFile.addPos(posi); |
3873 | 0 | ascFile.addNote(f.str().c_str()); |
3874 | |
|
3875 | 0 | posi=input->tell(); |
3876 | 0 | f.str(""); |
3877 | 0 | f << "Dimension[formatA]:"; |
3878 | 0 | for (int i=0; i<7; ++i) { // f2=-1|3, f4=1, |
3879 | 0 | val=int(input->readLong(4)); |
3880 | 0 | if (!val) |
3881 | 0 | continue; |
3882 | 0 | if (i==2) // -1-20 |
3883 | 0 | f << "dimension=" << val << ","; |
3884 | 0 | else if (i==5) { |
3885 | 0 | if (val==1) |
3886 | 0 | f << "use[secondary],"; |
3887 | 0 | else |
3888 | 0 | f << "use[secondary]=" << val << ","; |
3889 | 0 | } |
3890 | 0 | else if (i==6) // 0-3 |
3891 | 0 | f << "tolerance=" << val << ","; |
3892 | 0 | else |
3893 | 0 | f << "f" << i << "=" << val << ","; |
3894 | 0 | } |
3895 | 0 | f << "unkn=["; // 0.05*3 |
3896 | 0 | for (int i=0; i<3; ++i) |
3897 | 0 | f << m_mainParser->readDouble(stream, 8) << ","; |
3898 | 0 | f << "],"; |
3899 | 0 | val=int(input->readLong(4)); // 0 |
3900 | 0 | if (val) |
3901 | 0 | f << "f10=" << val << ","; |
3902 | 0 | f << "unkn1=" << m_mainParser->readDouble(stream, 8) << ","; // 18 |
3903 | 0 | for (int i=0; i<2; ++i) { |
3904 | 0 | val=int(input->readLong(4)); |
3905 | 0 | if (val==(i==0 ? 0 : 2)) continue; |
3906 | 0 | if (i==1) |
3907 | 0 | f << "digits=" << val << ","; |
3908 | 0 | else |
3909 | 0 | f << "g" << i << "=" << val << ","; |
3910 | 0 | } |
3911 | 0 | f << "displ[scaling]=" << m_mainParser->readDouble(stream, 8) << ","; // 1 |
3912 | 0 | for (int i=0; i<12; ++i) { |
3913 | 0 | val=int(input->readLong(4)); |
3914 | 0 | if (val) |
3915 | 0 | f << "g" << i+2 << "=" << val << ","; |
3916 | 0 | } |
3917 | 0 | ascFile.addPos(posi); |
3918 | 0 | ascFile.addNote(f.str().c_str()); |
3919 | |
|
3920 | 0 | posi=input->tell(); |
3921 | 0 | f.str(""); |
3922 | 0 | f << "Dimension[last,type=" << type << "]:"; |
3923 | 0 | if (type<1 || type>11) { |
3924 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: unknown type\n")); |
3925 | 0 | f << "###type=" << type << ","; |
3926 | 0 | ascFile.addPos(posi); |
3927 | 0 | ascFile.addNote(f.str().c_str()); |
3928 | 0 | return false; |
3929 | 0 | } |
3930 | | |
3931 | 0 | std::vector<MWAWVec2f> pts; |
3932 | 0 | f << "unkn=["; |
3933 | 0 | for (int i=0; i<((type==11||type==10) ? 2 : type==7 ? 3 : 4); ++i) { |
3934 | 0 | float dim[2]; |
3935 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
3936 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
3937 | 0 | f << pts.back() << ","; |
3938 | 0 | } |
3939 | 0 | f << "],"; |
3940 | |
|
3941 | 0 | long remain=entry.end()-input->tell()-(finishedWithN ? 4 : 0); |
3942 | 0 | switch (type) { |
3943 | 0 | case 1: // simple |
3944 | 0 | if (remain<0) { |
3945 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[1]: can not read the last part\n")); |
3946 | 0 | f << "###"; |
3947 | 0 | ascFile.addPos(posi); |
3948 | 0 | ascFile.addNote(f.str().c_str()); |
3949 | 0 | return false; |
3950 | 0 | } |
3951 | 0 | break; |
3952 | 0 | case 2: // array 1d <->|<-> |
3953 | 0 | case 3: { // array 1D |
3954 | 0 | if (N<0 || remain/64<N+1 || remain<64*(N+1)+(type==2 ? 4 : 0)) { |
3955 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[1]: can not read the last part\n")); |
3956 | 0 | f << "###"; |
3957 | 0 | ascFile.addPos(posi); |
3958 | 0 | ascFile.addNote(f.str().c_str()); |
3959 | 0 | return false; |
3960 | 0 | } |
3961 | 0 | f << "unk2=["; |
3962 | 0 | for (int i=0; i<=N; ++i) { |
3963 | 0 | f << "["; |
3964 | 0 | for (int j=0; j<4; ++j) { |
3965 | 0 | float dim[2]; |
3966 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
3967 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
3968 | 0 | f << pts.back() << ","; |
3969 | 0 | } |
3970 | 0 | f << "],"; |
3971 | 0 | } |
3972 | 0 | f << "],"; |
3973 | 0 | ascFile.addDelimiter(input->tell(),'|'); |
3974 | 0 | if (type==2) { |
3975 | 0 | input->seek(entry.end()-8, librevenge::RVNG_SEEK_SET); |
3976 | 0 | int direction=int(input->readULong(4)); |
3977 | 0 | f << "dir=" << direction << ","; // 1: hori, 2: verti, 0: all? |
3978 | 0 | if (direction<0 || direction>2) { |
3979 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[2]: unexpected direction\n")); |
3980 | 0 | f << "###"; |
3981 | 0 | } |
3982 | 0 | } |
3983 | 0 | input->seek(entry.end(), librevenge::RVNG_SEEK_SET); |
3984 | 0 | break; |
3985 | 0 | } |
3986 | 0 | case 4: { // perpendicular line ... |
3987 | 0 | if (remain<4 || (remain%16)!=4) { |
3988 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[4]: can not read the last part\n")); |
3989 | 0 | f << "###"; |
3990 | 0 | ascFile.addPos(posi); |
3991 | 0 | ascFile.addNote(f.str().c_str()); |
3992 | 0 | return false; |
3993 | 0 | } |
3994 | 0 | val=int(input->readLong(4)); |
3995 | 0 | if (val) |
3996 | 0 | f << "f0=" << val << ","; |
3997 | 0 | int n=int(remain/16); |
3998 | 0 | f << "unk2=["; |
3999 | 0 | for (int i=0; i<n; ++i) { // then the line |
4000 | 0 | float dim[2]; |
4001 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
4002 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
4003 | 0 | f << pts.back() << ","; |
4004 | 0 | } |
4005 | 0 | f << "],"; |
4006 | 0 | break; |
4007 | 0 | } |
4008 | | // case 5: side object (no data) |
4009 | 0 | case 6: { // arc |
4010 | 0 | if (remain!=48) { |
4011 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[6]: can not read the last part\n")); |
4012 | 0 | f << "###"; |
4013 | 0 | ascFile.addPos(posi); |
4014 | 0 | ascFile.addNote(f.str().c_str()); |
4015 | 0 | return false; |
4016 | 0 | } |
4017 | 0 | f << "unk2=["; |
4018 | 0 | for (int i=0; i<3; ++i) { |
4019 | 0 | float dim[2]; |
4020 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
4021 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
4022 | 0 | f << pts.back() << ","; |
4023 | 0 | } |
4024 | 0 | f << "],"; |
4025 | 0 | break; |
4026 | 0 | } |
4027 | 0 | case 7: // radius |
4028 | 0 | if (remain!=40) { |
4029 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[9]: can not read the last part\n")); |
4030 | 0 | f << "###"; |
4031 | 0 | ascFile.addPos(posi); |
4032 | 0 | ascFile.addNote(f.str().c_str()); |
4033 | 0 | return false; |
4034 | 0 | } |
4035 | 0 | input->seek(6, librevenge::RVNG_SEEK_CUR); |
4036 | 0 | f << "unk2=["; |
4037 | 0 | for (int i=0; i<2; ++i) { |
4038 | 0 | float dim[2]; |
4039 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
4040 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
4041 | 0 | f << pts.back() << ","; |
4042 | 0 | } |
4043 | 0 | f << "],"; |
4044 | 0 | val=int(input->readLong(2)); |
4045 | 0 | if (val) |
4046 | 0 | f << "f0=" << val << ","; |
4047 | 0 | break; |
4048 | | // case 8: diameter(no data) |
4049 | 0 | case 9: // cross in circle |
4050 | 0 | if (remain!=20) { |
4051 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[9]: can not read the last part\n")); |
4052 | 0 | f << "###"; |
4053 | 0 | ascFile.addPos(posi); |
4054 | 0 | ascFile.addNote(f.str().c_str()); |
4055 | 0 | return false; |
4056 | 0 | } |
4057 | 0 | float dim[2]; |
4058 | 0 | for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8)); |
4059 | 0 | pts.push_back(MWAWVec2f(dim[0], dim[1])); |
4060 | 0 | f << "unkn2=" << pts.back() << ","; // center? |
4061 | 0 | val=int(input->readLong(4)); |
4062 | 0 | if (val) |
4063 | 0 | f << "f0=" << val << ","; |
4064 | 0 | break; |
4065 | | // case 10: inside area |
4066 | | // case 11: outside area |
4067 | 0 | default: |
4068 | 0 | break; |
4069 | 0 | } |
4070 | 0 | ascFile.addPos(posi); |
4071 | 0 | ascFile.addNote(f.str().c_str()); |
4072 | |
|
4073 | 0 | if (input->tell()+(finishedWithN ? 4 : 0)<entry.end()) { |
4074 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: find extra data\n", type)); |
4075 | 0 | posi=input->tell(); |
4076 | 0 | f.str(""); |
4077 | 0 | f << "Dimension[end]:type=" << type << ","; |
4078 | 0 | ascFile.addPos(posi); |
4079 | 0 | ascFile.addNote(f.str().c_str()); |
4080 | 0 | } |
4081 | |
|
4082 | 0 | MWAWGraphicShape fShape; |
4083 | 0 | MWAWBox2f shapeBox; |
4084 | 0 | MWAWGraphicStyle style=local.m_style; |
4085 | 0 | MWAWPosition pos; |
4086 | 0 | pos.m_anchorTo = MWAWPosition::Page; |
4087 | |
|
4088 | 0 | listener->openGroup(local.m_position); |
4089 | 0 | switch (type) { |
4090 | 0 | case 1: |
4091 | 0 | case 2: |
4092 | 0 | case 3: |
4093 | 0 | case 4: |
4094 | 0 | case 5: { |
4095 | 0 | if (type>=2 && type<=3 && pts.size()<12) { |
4096 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems to small\n", type)); |
4097 | 0 | break; |
4098 | 0 | } |
4099 | 0 | else if (type==4 && pts.size()<6) { |
4100 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems to small\n", type)); |
4101 | 0 | break; |
4102 | 0 | } |
4103 | 0 | int num=(type==1 || type==4 || type==5) ? 1 : int(pts.size()-8)/4; |
4104 | 0 | for (int n=0; n<num; ++n) { |
4105 | 0 | if (n>0) { |
4106 | 0 | static bool first=true; |
4107 | 0 | if (first) { |
4108 | 0 | first=false; |
4109 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: oops, do not know how to retrieve multi-dimension type=%d\n", type)); |
4110 | 0 | } |
4111 | | #if 0 |
4112 | | style.m_surfaceOpacity=0; |
4113 | | fShape=MWAWGraphicShape::rectangle(bdbox); |
4114 | | send(listener, fShape, local.m_transform, style); |
4115 | | #endif |
4116 | 0 | break; |
4117 | 0 | } |
4118 | 0 | MWAWVec2f v=pts[3]-pts[2]; |
4119 | 0 | MWAWVec2f dir(v[1], -v[0]); |
4120 | | // first border |
4121 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
4122 | 0 | for (size_t i=0; i<2; ++i) { |
4123 | 0 | std::vector<MWAWVec2f> points=Canvas5GraphInternal::intersect(bdbox, pts[i], dir); |
4124 | 0 | if (points.size()!=2) continue; |
4125 | 0 | fShape=MWAWGraphicShape::line(points[0],points[1]); |
4126 | 0 | send(listener, fShape, local.m_transform, style); |
4127 | 0 | } |
4128 | 0 | MWAWVec2f points[2]; |
4129 | 0 | bool ok=true; |
4130 | 0 | for (size_t j=0; j<2; ++j) { |
4131 | 0 | if (Canvas5GraphInternal::intersect(pts[2],v, pts[j], dir, points[j])) |
4132 | 0 | continue; |
4133 | 0 | ok=true; |
4134 | 0 | break; |
4135 | 0 | } |
4136 | 0 | if (!ok) continue; |
4137 | | // now the main arrow |
4138 | 0 | MWAWVec2f u=pts[1]-pts[0]; |
4139 | 0 | bool outside=arrowType==2 || (arrowType!=1 && u[0]*u[0]+u[1]*u[1]<50*50); |
4140 | 0 | if (outside) { |
4141 | 0 | std::vector<MWAWVec2f> points2=Canvas5GraphInternal::intersect(bdbox, points[0], points[1]-points[0]); |
4142 | 0 | if (points2.size()==2) { |
4143 | 0 | MWAWVec2f dir0=points[1]-points[0]; |
4144 | 0 | MWAWVec2f dir1=points2[1]-points2[0]; |
4145 | 0 | if (dir0[0]*dir1[0]+dir0[1]*dir1[1]<0) |
4146 | 0 | std::swap(points2[0],points2[1]); |
4147 | 0 | if (arrowType!=0) |
4148 | 0 | style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
4149 | 0 | for (size_t i=0; i<2; ++i) { |
4150 | 0 | fShape=MWAWGraphicShape::line(points2[i],points[i]); |
4151 | 0 | send(listener, fShape, local.m_transform, style); |
4152 | 0 | } |
4153 | 0 | } |
4154 | 0 | } |
4155 | 0 | else { |
4156 | 0 | if (arrowType!=0) |
4157 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
4158 | 0 | fShape=MWAWGraphicShape::line(points[0],points[1]); |
4159 | 0 | send(listener, fShape, local.m_transform, style); |
4160 | 0 | } |
4161 | | |
4162 | | // and the text |
4163 | 0 | std::stringstream s; |
4164 | 0 | s << std::setprecision(0) << std::fixed << std::sqrt(u[0]*u[0]+u[1]*u[1]) << " pt"; |
4165 | 0 | librevenge::RVNGString text=s.str().c_str(); |
4166 | |
|
4167 | 0 | MWAWVec2f textOrigin=0.5f*(points[0]+points[1]); |
4168 | 0 | send(listener, text, textOrigin, local.m_transform, font, false); |
4169 | 0 | } |
4170 | 0 | break; |
4171 | 0 | } |
4172 | 0 | case 6: { |
4173 | 0 | if (pts.size()!=7) { |
4174 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type)); |
4175 | 0 | break; |
4176 | 0 | } |
4177 | 0 | MWAWVec2f orig; |
4178 | 0 | if (!Canvas5GraphInternal::intersect(pts[0],pts[1]-pts[0], pts[3],pts[3]-pts[2],orig)) { |
4179 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, can not find the origin\n", type)); |
4180 | 0 | break; |
4181 | 0 | } |
4182 | 0 | float angles[2]; |
4183 | 0 | for (size_t i=0; i<2; ++i) { |
4184 | 0 | MWAWVec2f dir=pts[1+2*i]-orig; |
4185 | 0 | angles[i]=std::atan2(-dir[1],dir[0]); |
4186 | 0 | } |
4187 | |
|
4188 | 0 | if (std::isnan(angles[0]) || std::isnan(angles[1])) { |
4189 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[6]: can not compute the sector angle\n")); |
4190 | 0 | } |
4191 | 0 | else { |
4192 | 0 | MWAWVec2f dir=pts[5]-orig; |
4193 | 0 | float radius=std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]); |
4194 | 0 | std::swap(angles[0],angles[1]); |
4195 | 0 | MWAWBox2f circleBox(MWAWVec2f(orig[0]-radius, orig[1]-radius),MWAWVec2f(orig[0]+radius, orig[1]+radius)); |
4196 | | |
4197 | | // we must compute the arc box |
4198 | 0 | float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 }; |
4199 | 0 | int limitAngle[2]; |
4200 | 0 | for (int i = 0; i < 2; ++i) |
4201 | 0 | limitAngle[i] = (angles[i] < 0) ? int(2*angles[i]/float(M_PI))-1 : int(2*angles[i]/float(M_PI)); |
4202 | 0 | for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) { |
4203 | 0 | float ang = (bord == limitAngle[0]) ? float(angles[0]) : |
4204 | 0 | (bord == limitAngle[1]+1) ? float(angles[1]) : float(M_PI/2*bord); |
4205 | 0 | float const actVal[2] = { std::cos(ang), -std::sin(ang)}; |
4206 | 0 | if (actVal[0] < minVal[0]) minVal[0] = actVal[0]; |
4207 | 0 | else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0]; |
4208 | 0 | if (actVal[1] < minVal[1]) minVal[1] = actVal[1]; |
4209 | 0 | else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1]; |
4210 | 0 | } |
4211 | 0 | MWAWBox2f arcBox(MWAWVec2f(orig[0]+minVal[0]*radius, orig[1]+minVal[1]*radius),MWAWVec2f(orig[0]+maxVal[0]*radius, orig[1]+maxVal[1]*radius)); |
4212 | 0 | fShape = MWAWGraphicShape::pie(arcBox, circleBox, MWAWVec2f(float(180/M_PI)*angles[0], float(180/M_PI)*angles[1])); |
4213 | 0 | send(listener, fShape, local.m_transform, style); |
4214 | 0 | } |
4215 | | // and the text |
4216 | 0 | std::stringstream s; |
4217 | 0 | s << std::setprecision(2) << std::fixed << float(180/M_PI)*(angles[1]-angles[0]) << " "; |
4218 | 0 | librevenge::RVNGString text=s.str().c_str(); |
4219 | |
|
4220 | 0 | send(listener, text, pts[5], local.m_transform, font, false); |
4221 | 0 | break; |
4222 | 0 | } |
4223 | 0 | case 7: { |
4224 | 0 | if (pts.size()!=5) { |
4225 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type)); |
4226 | 0 | break; |
4227 | 0 | } |
4228 | 0 | fShape=MWAWGraphicShape::line(pts[1],pts[2]); |
4229 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
4230 | 0 | send(listener, fShape, local.m_transform, style); |
4231 | 0 | fShape=MWAWGraphicShape::line(pts[0],pts[1]); |
4232 | 0 | if (arrowType!=0) |
4233 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
4234 | 0 | send(listener, fShape, local.m_transform, style); |
4235 | | // and the text |
4236 | 0 | std::stringstream s; |
4237 | 0 | MWAWVec2f dir=pts[2]-pts[0]; |
4238 | 0 | s << std::setprecision(0) << std::fixed << std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]) << " pt"; |
4239 | 0 | librevenge::RVNGString text=s.str().c_str(); |
4240 | 0 | send(listener, text, pts[1], local.m_transform, font, false); |
4241 | 0 | break; |
4242 | 0 | } |
4243 | 0 | case 8: { |
4244 | 0 | if (pts.size()!=4) { |
4245 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type)); |
4246 | 0 | break; |
4247 | 0 | } |
4248 | 0 | fShape=MWAWGraphicShape::line(pts[0],pts[1]); |
4249 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
4250 | 0 | send(listener, fShape, local.m_transform, style); |
4251 | 0 | fShape=MWAWGraphicShape::line(pts[0],pts[2]); |
4252 | 0 | if (arrowType!=0) |
4253 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
4254 | 0 | send(listener, fShape, local.m_transform, style); |
4255 | | // and the text |
4256 | 0 | std::stringstream s; |
4257 | 0 | MWAWVec2f dir=pts[2]-pts[0]; |
4258 | 0 | s << std::setprecision(0) << std::fixed << std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]) << " pt"; |
4259 | 0 | librevenge::RVNGString text=s.str().c_str(); |
4260 | 0 | send(listener, text, pts[1], local.m_transform, font, false); |
4261 | 0 | break; |
4262 | 0 | } |
4263 | 0 | case 9: // 0 is the center |
4264 | 0 | if (pts.size()!=5) { |
4265 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type)); |
4266 | 0 | break; |
4267 | 0 | } |
4268 | 0 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
4269 | 0 | fShape=MWAWGraphicShape::line(pts[1],pts[2]); |
4270 | 0 | send(listener, fShape, local.m_transform, style); |
4271 | 0 | fShape=MWAWGraphicShape::line(pts[3],pts[4]); |
4272 | 0 | send(listener, fShape, local.m_transform, style); |
4273 | 0 | break; |
4274 | 0 | case 10: |
4275 | 0 | case 11: { |
4276 | 0 | static bool first=true; |
4277 | 0 | if (first) { |
4278 | 0 | first=false; |
4279 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: sorry, sending area dimension of type=%d is not implemented\n", type)); |
4280 | 0 | } |
4281 | 0 | break; |
4282 | 0 | } |
4283 | 0 | default: |
4284 | 0 | static bool first=true; |
4285 | 0 | if (first) { |
4286 | 0 | first=false; |
4287 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: sorry, sending dimension of type=%d is not implemented\n", type)); |
4288 | 0 | } |
4289 | 0 | break; |
4290 | 0 | } |
4291 | 0 | listener->closeGroup(); |
4292 | 0 | return true; |
4293 | 0 | } |
4294 | | |
4295 | | //////////////////////////////////////////////////////////// |
4296 | | // auxilliary structure |
4297 | | //////////////////////////////////////////////////////////// |
4298 | | |
4299 | | void Canvas5Graph::LocalState::multiplyMatrix(std::array<double, 9> const &mat) |
4300 | 0 | { |
4301 | 0 | if (mat[8]>=-1e-3 && mat[8]<=1e-3) { |
4302 | | // checkme: this seems possible, unsure what this means ? |
4303 | 0 | static bool first=true; |
4304 | 0 | if (first) { |
4305 | 0 | first=false; |
4306 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::LocalState::multiplyMatrix: find some matrix with mat[3][3]=0\n")); |
4307 | 0 | } |
4308 | 0 | } |
4309 | 0 | if (mat[2]<-1e-3 || mat[2]>1e-3 || mat[5]<-1e-3 || mat[5]>1e-3) { |
4310 | 0 | MWAW_DEBUG_MSG(("Canvas5Graph::LocalState::multiplyMatrix: projection will be ignored\n")); |
4311 | 0 | return; |
4312 | 0 | } |
4313 | 0 | m_transform*=MWAWTransformation(MWAWVec3f((float)mat[0], (float)mat[3], (float)mat[6]), MWAWVec3f((float)mat[1], (float)mat[4], (float)mat[7])); |
4314 | 0 | } |
4315 | | |
4316 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |