Files
Slnkdwf/Whiptk702/ellipse.cpp
Jos Groot Lipman 0b9083fc17 SLNKDWF 2.11
svn path=/Slnkdwf/trunk/; revision=12487
2008-02-12 07:07:56 +00:00

721 lines
28 KiB
C++

// Copyright (c) 1996-2001 by Autodesk, Inc.
//
// By using this code, you are agreeing to the terms and conditions of
// the License Agreement included in the documentation for this code.
//
// AUTODESK MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE CORRECTNESS
// OF THIS CODE OR ANY DERIVATIVE WORKS WHICH INCORPORATE IT. AUTODESK
// PROVIDES THE CODE ON AN "AS-IS" BASIS AND EXPLICITLY DISCLAIMS ANY
// LIABILITY, INCLUDING CONSEQUENTIAL AND INCIDENTAL DAMAGES FOR ERRORS,
// OMISSIONS, AND OTHER PROBLEMS IN THE CODE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer Software
// Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical
// Data and Computer Software), as applicable.
//
// $Header: /NewRoot/DWF Toolkit/v6/develop/global/src/dwf/whiptk/ellipse.cpp 1 9/12/04 8:52p Evansg $
#include "whiptk/pch.h"
#include "whiptk/wversion.h"
const double PI = 3.14159265358979323846;
///////////////////////////////////////////////////////////////////////////
WT_Object::WT_ID WT_Filled_Ellipse::object_id() const
{
return Filled_Ellipse_ID;
}
///////////////////////////////////////////////////////////////////////////
WT_Object::WT_ID WT_Outline_Ellipse::object_id() const
{
return Outline_Ellipse_ID;
}
///////////////////////////////////////////////////////////////////////////
#if DESIRED_CODE(WHIP_OUTPUT)
WT_Result WT_Filled_Ellipse::serialize(WT_File & file) const
{
return WT_Ellipse::serialize (file, WD_True);
}
#else
WT_Result WT_Filled_Ellipse::serialize(WT_File &) const
{
return WT_Result::Success;
}
#endif // DESIRED_CODE()
///////////////////////////////////////////////////////////////////////////
#if DESIRED_CODE(WHIP_OUTPUT)
WT_Result WT_Outline_Ellipse::serialize(WT_File & file) const
{
return WT_Ellipse::serialize (file, WD_False);
}
#else
WT_Result WT_Outline_Ellipse::serialize(WT_File &) const
{
return WT_Result::Success;
}
#endif // DESIRED_CODE()
///////////////////////////////////////////////////////////////////////////
#if DESIRED_CODE(WHIP_OUTPUT)
WT_Result WT_Ellipse::serialize(WT_File & file, WT_Boolean filled) const
{
WD_CHECK (file.dump_delayed_drawable());
// TODO: Check rendition incarnation
// Attributes that Filled_Ellipses care about:
// color, line weight, line cap, line join,
// line pattern, fill mode, visibility, URL
// layer
WT_Integer32 parts_to_sync = WT_Rendition::Color_Bit |
// WT_Rendition::Color_Map_Bit |
// WT_Rendition::Fill_Bit |
WT_Rendition::Fill_Pattern_Bit |
WT_Rendition::Merge_Control_Bit |
WT_Rendition::BlockRef_Bit |
WT_Rendition::Visibility_Bit |
// WT_Rendition::Marker_Size_Bit |
// WT_Rendition::Marker_Symbol_Bit |
WT_Rendition::URL_Bit |
WT_Rendition::Viewport_Bit |
WT_Rendition::Layer_Bit |
WT_Rendition::Object_Node_Bit;
if (filled)
{
if (!file.rendition().fill().fill())
{
file.desired_rendition().fill() = WD_True;
parts_to_sync |= WT_Rendition::Fill_Bit;
}
}
else
{
parts_to_sync |= WT_Rendition::Line_Weight_Bit |
WT_Rendition::Pen_Pattern_Bit |
WT_Rendition::Line_Pattern_Bit |
WT_Rendition::Dash_Pattern_Bit |
WT_Rendition::Line_Style_Bit;
if (file.rendition().fill().fill())
{
file.desired_rendition().fill() = WD_False;
parts_to_sync |= WT_Rendition::Fill_Bit;
}
}
WD_CHECK (file.desired_rendition().sync(file, parts_to_sync));
if (file.heuristics().apply_transform())
((WT_Filled_Ellipse *)this)->transform(file.heuristics().transform()); // Cast "this" from const to alterable
if (file.heuristics().allow_binary_data())
{
WT_Logical_Point relpos = file.update_current_point(m_position);
// Binary output
if (m_major != m_minor)
{
// output as Ellipse
WD_CHECK (file.write ((WT_Byte)'e'));
WD_CHECK (file.write (1, &relpos));
WD_CHECK (file.write (m_major));
WD_CHECK (file.write (m_minor));
WD_CHECK (file.write (m_start));
WD_CHECK (file.write ((WT_Unsigned_Integer16)(m_end & 0xFFFF)));
return file.write (m_tilt);
}
else if (m_start != m_end)
{
// Output a 32 bit partial circle
// merge any ellipse tilt into the circle angles
long start = ((long)m_start + (long)m_tilt) & 0x0000FFFF;
long end = ((long)m_end + (long)m_tilt) & 0x0000FFFF;
WD_CHECK (file.write ((WT_Byte)0x92));
WD_CHECK (file.write (1, &relpos));
WD_CHECK (file.write (m_major));
WD_CHECK (file.write ((WT_Unsigned_Integer16)start));
return file.write ((WT_Unsigned_Integer16)end);
}
else if (WD_fits_in_short (relpos.m_x) && WD_fits_in_short (relpos.m_y) &&
WD_fits_in_short (m_major))
{
// Output a 16 bit relative full circle
WT_Logical_Point_16 tmp_point;
tmp_point = relpos;
WD_CHECK (file.write ((WT_Byte)0x12));
WD_CHECK (file.write (1, &tmp_point));
return file.write ((WT_Integer16)m_major);
}
else
{
// Output a 32 bit relative full circle
WD_CHECK (file.write ((WT_Byte)'r'));
WD_CHECK (file.write (1, &relpos));
return file.write (m_major);
}
} // allow binary data
else
{
// ASCII only output -----------------------
WD_CHECK (file.write_geom_tab_level());
if (m_major != m_minor)
{
// output as Ellipse in ASCII
if ((m_start != m_end) || m_tilt)
{
// Full description of an ellipse
WD_CHECK (file.write ("(Ellipse "));
WD_CHECK (file.write_ascii (m_position));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (m_major));
WD_CHECK (file.write ((WT_Byte) ','));
WD_CHECK (file.write_ascii (m_minor));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (m_start));
WD_CHECK (file.write ((WT_Byte) ','));
WD_CHECK (file.write_ascii (m_end));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (m_tilt));
return file.write((WT_Byte) ')');
}
else
{
// Basic description of an ellipse
WD_CHECK (file.write ("E "));
WD_CHECK (file.write_ascii (1, &m_position));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (m_major));
WD_CHECK (file.write ((WT_Byte) ','));
return file.write_ascii (m_minor);
}
}
else
{
// merge any ellipse tilt into the circle angles
long start = ((long)m_start + (long)m_tilt) & 0x0000FFFF;
long end = ((long)m_end + (long)m_tilt) & 0x0000FFFF;
// Output a circle in ASCII
if (start != end)
{
// Full description of the circle/arc
WD_CHECK (file.write ("(Circle "));
WD_CHECK (file.write_ascii (m_position));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (m_major));
WD_CHECK (file.write ((WT_Byte) ' '));
WD_CHECK (file.write_ascii (start));
WD_CHECK (file.write ((WT_Byte) ','));
WD_CHECK (file.write_ascii (end));
return file.write((WT_Byte) ')');
}
else
{
// Basic circle
WD_CHECK (file.write ("R "));
WD_CHECK (file.write_ascii (m_position));
WD_CHECK (file.write ((WT_Byte) ' '));
return file.write_ascii (m_major);
}
}
}
}
#else
WT_Result WT_Ellipse::serialize(WT_File &, WT_Boolean) const
{
return WT_Result::Success;
}
#endif // DESIRED_CODE()
///////////////////////////////////////////////////////////////////////////
bool containsAngle(double angle, double angleStart, double angleEnd)
{
// get the orientation
bool isCCW = angleStart < angleEnd;
// put the supplied parameter value on the extent side of the start angle
if (isCCW)
{
while (angle < angleStart)
angle += 2.0*PI;
while (angle- 2.0*PI > angleStart)
angle -= 2.0*PI;
}
else
{
while (angle > angleStart)
angle -= 2.0*PI;
while (angle+2.0*PI < angleStart)
angle += 2.0*PI;
}
// do the range check
if (isCCW)
{
// normal orientation
if (angle >= angleStart && angle <= angleEnd)
return true;
}
else
{
// reversed orientation
if (angle >= angleEnd && angle <= angleStart)
return true;
}
// not in range
return false;
}
///////////////////////////////////////////////////////////////////////////
void WT_Ellipse::update_bounds(WT_File * file)
{
//Bounds algorithm lifted and ported from Kona
double maj = major();
double min = minor();
double ang = tilt_radian();
double csa = cos(ang);
double sna = sin(ang);
double ax = maj * csa;
double bx = min * sna;
double ay = maj * sna;
double by = min * csa;
double xmax = sqrt(ax*ax + bx*bx);
double ymax = sqrt(ay*ay + by*by);
double asValue = start_radian();;
double css = cos(asValue);
double sns = sin(asValue);
double xs = ax*css - bx*sns;
double ys = ay*css + by*sns;
double ae = end_radian();
double cse = cos(ae);
double sne = sin(ae);
double xe = ax*cse - bx*sne;
double ye = ay*cse + by*sne;
WT_Drawable::update_bounds(WT_Logical_Point((int)xs+m_position.m_x,(int)ys+m_position.m_y), file);
WT_Drawable::update_bounds(WT_Logical_Point(((int)xs)+m_position.m_x+1,((int)ys)+m_position.m_y+1), file);
WT_Drawable::update_bounds(WT_Logical_Point((int)xe+m_position.m_x,(int)ye+m_position.m_y), file);
WT_Drawable::update_bounds(WT_Logical_Point(((int)xe)+m_position.m_x+1,((int)ye)+m_position.m_y+1), file);
double asnorm = atan2(sns, css);
double aenorm = ae + (asnorm - asValue);
double txmax = atan2(-min*sna, maj*csa);
double txmin = txmax - PI;
if (txmin <= -PI)
txmin += 2.0*PI;
if (containsAngle(txmax, asnorm, aenorm))
WT_Drawable::update_bounds(WT_Logical_Point(((int)xmax)+m_position.m_x+1, ((int)ys)+m_position.m_y+1), file);
if (containsAngle(txmin, asnorm, aenorm))
WT_Drawable::update_bounds(WT_Logical_Point((int)-xmax+m_position.m_x, (int)ys+m_position.m_y), file);
double tymax = atan2(min*csa, maj*sna);
double tymin = tymax - PI;
if (tymin <= -PI)
tymin += 2.0*PI;
if (containsAngle(tymax, asnorm, aenorm))
WT_Drawable::update_bounds(WT_Logical_Point(((int)xs)+m_position.m_x+1, ((int)ymax)+m_position.m_y+1), file);
if (containsAngle(tymin, asnorm, aenorm))
WT_Drawable::update_bounds(WT_Logical_Point((int)xs+m_position.m_x, (int)-ymax+m_position.m_y), file);
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Ellipse::materialize(WT_Opcode const & opcode, WT_File & file)
{
WT_Logical_Point tmp_point;
switch (opcode.type())
{
case WT_Opcode::Single_Byte:
{
switch (opcode.token()[0])
{
case 'E':
{
// Ellipse, single-byte full ASCII
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read_ascii (m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read_ascii (tmp_point));
m_major = tmp_point.m_x;
m_minor = tmp_point.m_y;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// Note: for full ASCII we *don't* de-relativize since we already have absolute coords.
} break;
case 'e':
{
// Ellipse, binary, long relative coordinates
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read (1, &m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read (m_major));
m_stage = Get_Minor;
case Get_Minor: WD_CHECK (file.read (m_minor));
m_stage = Get_Start;
case Get_Start: WD_CHECK (file.read (m_start));
m_stage = Get_End;
case Get_End: WT_Unsigned_Integer16 tmp;
WD_CHECK (file.read (tmp));
m_end = tmp;
m_stage = Get_Tilt;
case Get_Tilt: WD_CHECK (file.read (m_tilt));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// convert from relative to absolute, transform if appropriate
m_position = file.de_update_current_point(m_position);
} break;
case 'R':
{
// Basic Circle, Ascii
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read_ascii (m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read_ascii (m_major));
m_minor = m_major;
m_start = 0;
m_end = 0;
m_tilt = 0;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// Note: for full ASCII we *don't* de-relativize since we already have absolute coords.
} break;
case 'r':
{
// Full Circle, long relative coordinates
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read (1, &m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read (m_major));
m_minor = m_major;
m_start = 0;
m_end = 0x00010000;
m_tilt = 0;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// convert from relative to absolute, transform if appropriate
m_position = file.de_update_current_point(m_position);
} break;
case 0x12: // Ctrl-R
{
// Full Circle, short relative coordinates
WT_Logical_Point_16 position;
WT_Unsigned_Integer16 radius;
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read (1, &position));
m_position = position;
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read (radius));
m_major = m_minor = radius;
m_start = 0;
m_end = 0x00010000;
m_tilt = 0;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// convert from relative to absolute, transform if appropriate
m_position = file.de_update_current_point(m_position);
} break;
case 0x92: // X-Ctrl-R
{
// Partial or Full Circle, long relative coordinates, short angles
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read (1, &m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read (m_major));
m_minor = m_major;
m_stage = Get_Start;
case Get_Start: WD_CHECK (file.read (m_start));
m_stage = Get_End;
case Get_End: WT_Unsigned_Integer16 tmp;
WD_CHECK (file.read (tmp));
m_end = tmp;
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// convert from relative to absolute, transform if appropriate
m_position = file.de_update_current_point(m_position);
} break;
default:
return WT_Result::Opcode_Not_Valid_For_This_Object;
// break;
} // switch
} break;
case WT_Opcode::Extended_ASCII:
{
if (!strcmp((char const *) opcode.token(), "(Circle"))
{
// Partial or Full Circle, absolute coordinates, short angles
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read_ascii (m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read_ascii (m_major));
m_minor = m_major;
m_stage = Get_Start;
case Get_Start: WD_CHECK (file.read_ascii (tmp_point));
if (tmp_point.m_x < 0 || tmp_point.m_y < 0)
return WT_Result::Corrupt_File_Error;
m_start = (WT_Unsigned_Integer16)(tmp_point.m_x & 0XFFFF);
m_end = tmp_point.m_y & 0x0001FFFF;
m_stage = Get_Close_Paren;
case Get_Close_Paren:
WD_CHECK (opcode.skip_past_matching_paren(file));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// Note: for full ASCII we *don't* de-relativize since we already have absolute coords.
}
else if (!strcmp((char const *) opcode.token(), "(Ellipse"))
{
// Ellipse, single-byte full ASCII
switch (m_stage)
{
case Get_Position: WD_CHECK (file.read_ascii (m_position));
m_stage = Get_Major;
case Get_Major: WD_CHECK (file.read_ascii (tmp_point));
m_major = tmp_point.m_x;
m_minor = tmp_point.m_y;
m_stage = Get_Start;
case Get_Start: WD_CHECK (file.read_ascii (tmp_point));
if (tmp_point.m_x < 0 || tmp_point.m_y < 0)
return WT_Result::Corrupt_File_Error;
m_start = (WT_Unsigned_Integer16)(tmp_point.m_x & 0XFFFF);
m_end = tmp_point.m_y & 0x0001FFFF;
m_stage = Get_Tilt;
case Get_Tilt: WD_CHECK (file.read_ascii (m_tilt));
m_stage = Get_Close_Paren;
case Get_Close_Paren:
WD_CHECK (opcode.skip_past_matching_paren(file));
m_stage = Completed;
break;
default:
return WT_Result::Internal_Error;
}
// Note: for full ASCII we *don't* de-relativize since we already have absolute coords.
}
else
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
case WT_Opcode::Extended_Binary:
default:
{
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
} // switch
if (file.heuristics().apply_transform())
transform(file.heuristics().transform());
m_materialized = WD_True;
if (file.rendition().drawing_info().decimal_revision() <= WHIP20_DWF_FILE_VERSION)
{
// Note that in old versions, if m_start == m_end this is
// a null ellipse/circle that shouldn't be drawn. In this case
// we leave both m_start and m_end the same since Heidi knows not
// to draw such a case.
if (m_start == m_end)
return WT_Result::Success;
// In old versions, a complete circle was when m_end was one less than m_start.
// Adjust for the current definition which is that a complete circle is when
// they are the same value. (If you want a null circle, just don't put it
// in the DWF file, stupid!).
if (m_end < 0x00010000)
m_end++;
}
if (m_end <= m_start)
m_end += 0x00010000;
return WT_Result::Success;
}
WT_Result WT_Ellipse::skip_operand(WT_Opcode const & opcode, WT_File & file)
{
switch (opcode.type())
{
case WT_Opcode::Single_Byte:
{
switch (opcode.token()[0])
{
case 'E':
{
WT_Logical_Point tmp_pt;
WD_CHECK(file.read_ascii(tmp_pt));
WD_CHECK(file.read_ascii(tmp_pt));
} break;
case 'e':
{
// This is an ellipse, with 32-bit relative coords, 32-bit axes, 16-bit angles
file.skip(2 * sizeof(WT_Integer32) +
2 * sizeof(WT_Unsigned_Integer32) +
3 * sizeof(WT_Unsigned_Integer16));
} break;
case 'R':
{
WT_Integer32 tmp;
WT_Logical_Point tmp_pt;
WD_CHECK(file.read_ascii(tmp_pt));
WD_CHECK(file.read_ascii(tmp));
} break;
case 'r':
{
// This is a circle, with 32-bit relative coords, 32-bit radius
file.skip(2 * sizeof(WT_Integer32) +
sizeof(WT_Unsigned_Integer32));
} break;
case 0x12: // Ctrl-R
{
// This is a circle, with 16-bit relative coords, 16-bit radius
file.skip(2 * sizeof(WT_Integer16) +
sizeof(WT_Unsigned_Integer16));
} break;
case 0x92: // X-Ctrl-R
{
// This is a circle, with 32-bit relative coords, 32-bit radius, 16-bit angles
file.skip(2 * sizeof(WT_Integer32) +
sizeof(WT_Unsigned_Integer32) +
2 * sizeof(WT_Unsigned_Integer16));
} break;
default:
return WT_Result::Opcode_Not_Valid_For_This_Object;
// break;
} // switch
} break;
case WT_Opcode::Extended_ASCII:
WD_CHECK(opcode.skip_past_matching_paren(file));
break;
case WT_Opcode::Extended_Binary:
default:
{
return WT_Result::Opcode_Not_Valid_For_This_Object;
} break;
} // switch
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
void WT_Ellipse::transform(WT_Transform const & transform)
{
if (!m_transformed)
{
// m_position.m_x = (WT_Integer32)((m_position.m_x + transform.m_translate.m_x) * transform.m_x_scale);
// m_position.m_y = (WT_Integer32)((m_position.m_y + transform.m_translate.m_y) * transform.m_y_scale);
// m_position.m_x = (WT_Integer32)((m_position.m_x * transform.m_x_scale) + transform.m_translate.m_x);
// m_position.m_y = (WT_Integer32)((m_position.m_y * transform.m_y_scale) + transform.m_translate.m_y);
WT_Logical_Point orig_pt(m_position);
m_position = orig_pt * transform; // we should use *=, but there seems to be a problem?
m_major = (WT_Unsigned_Integer32)(m_major * transform.m_x_scale);
m_minor = (WT_Unsigned_Integer32)(m_minor * transform.m_y_scale);
if (m_major < 0)
m_major = - m_major;
if (m_minor < 0)
m_minor = - m_minor;
m_tilt = (WT_Unsigned_Integer16)(
(WT_Unsigned_Integer16)
( (long)m_tilt +
(long)WD_90_DEGREES_AS_SHORT * ((double)transform.rotation() / 90)
) & 0x0000FFFF);
// TODO: note that we can simplify some ellipses by incorporating the tilt in and
// exchanging the major and minor axes or by rotating the start and end points.
m_transformed = WD_True;
}
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Filled_Ellipse::process(WT_File & file)
{
WD_Assert (file.filled_ellipse_action());
return (file.filled_ellipse_action())(*this, file);
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Filled_Ellipse::default_process(WT_Filled_Ellipse &, WT_File &)
{
return WT_Result::Success;
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Outline_Ellipse::process(WT_File & file)
{
WD_Assert (file.outline_ellipse_action());
return (file.outline_ellipse_action())(*this, file);
}
///////////////////////////////////////////////////////////////////////////
WT_Result WT_Outline_Ellipse::default_process(WT_Outline_Ellipse &, WT_File &)
{
return WT_Result::Success;
}