📄 basic2.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: basic2.cpp
// Purpose: Basic OGL classes (2)
// Author: Julian Smart
// Modified by:
// Created: 12/07/98
// RCS-ID: $Id: basic2.cpp,v 1.25 2005/10/06 18:17:21 ABX Exp $
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if wxUSE_PROLOGIO
#include "wx/deprecated/wxexpr.h"
#endif
#ifdef new
#undef new
#endif
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "wx/ogl/ogl.h"
// Control point types
// Rectangle and most other shapes
#define CONTROL_POINT_VERTICAL 1
#define CONTROL_POINT_HORIZONTAL 2
#define CONTROL_POINT_DIAGONAL 3
// Line
#define CONTROL_POINT_ENDPOINT_TO 4
#define CONTROL_POINT_ENDPOINT_FROM 5
#define CONTROL_POINT_LINE 6
// Two stage construction: need to call Create
IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape, wxShape)
wxPolygonShape::wxPolygonShape()
{
m_points = NULL;
m_originalPoints = NULL;
}
void wxPolygonShape::Create(wxList *the_points)
{
ClearPoints();
if (!the_points)
{
m_originalPoints = new wxList;
m_points = new wxList;
}
else
{
m_originalPoints = the_points;
// Duplicate the list of points
m_points = new wxList;
wxObjectList::compatibility_iterator node = the_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
m_points->Append((wxObject*) new_point);
node = node->GetNext();
}
CalculateBoundingBox();
m_originalWidth = m_boundWidth;
m_originalHeight = m_boundHeight;
SetDefaultRegionSize();
}
}
wxPolygonShape::~wxPolygonShape()
{
ClearPoints();
}
void wxPolygonShape::ClearPoints()
{
if (m_points)
{
wxObjectList::compatibility_iterator node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
delete point;
m_points->Erase(node);
node = m_points->GetFirst();
}
delete m_points;
m_points = NULL;
}
if (m_originalPoints)
{
wxObjectList::compatibility_iterator node = m_originalPoints->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
delete point;
m_originalPoints->Erase(node);
node = m_originalPoints->GetFirst();
}
delete m_originalPoints;
m_originalPoints = NULL;
}
}
// Width and height. Centre of object is centre of box.
void wxPolygonShape::GetBoundingBoxMin(double *width, double *height)
{
*width = m_boundWidth;
*height = m_boundHeight;
}
void wxPolygonShape::CalculateBoundingBox()
{
// Calculate bounding box at construction (and presumably resize) time
double left = 10000;
double right = -10000;
double top = 10000;
double bottom = -10000;
wxObjectList::compatibility_iterator node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
if (point->x < left) left = point->x;
if (point->x > right) right = point->x;
if (point->y < top) top = point->y;
if (point->y > bottom) bottom = point->y;
node = node->GetNext();
}
m_boundWidth = right - left;
m_boundHeight = bottom - top;
}
// Recalculates the centre of the polygon, and
// readjusts the point offsets accordingly.
// Necessary since the centre of the polygon
// is expected to be the real centre of the bounding
// box.
void wxPolygonShape::CalculatePolygonCentre()
{
double left = 10000;
double right = -10000;
double top = 10000;
double bottom = -10000;
wxObjectList::compatibility_iterator node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
if (point->x < left) left = point->x;
if (point->x > right) right = point->x;
if (point->y < top) top = point->y;
if (point->y > bottom) bottom = point->y;
node = node->GetNext();
}
double bwidth = right - left;
double bheight = bottom - top;
double newCentreX = (double)(left + (bwidth/2.0));
double newCentreY = (double)(top + (bheight/2.0));
node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
point->x -= newCentreX;
point->y -= newCentreY;
node = node->GetNext();
}
m_xpos += newCentreX;
m_ypos += newCentreY;
}
bool PolylineHitTest(double n, double xvec[], double yvec[],
double x1, double y1, double x2, double y2)
{
bool isAHit = false;
int i;
double lastx = xvec[0];
double lasty = yvec[0];
double min_ratio = 1.0;
double line_ratio;
double other_ratio;
for (i = 1; i < n; i++)
{
oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
&line_ratio, &other_ratio);
if (line_ratio != 1.0)
isAHit = true;
lastx = xvec[i];
lasty = yvec[i];
if (line_ratio < min_ratio)
min_ratio = line_ratio;
}
// Do last (implicit) line if last and first doubles are not identical
if (!(xvec[0] == lastx && yvec[0] == lasty))
{
oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
&line_ratio, &other_ratio);
if (line_ratio != 1.0)
isAHit = true;
}
return isAHit;
}
bool wxPolygonShape::HitTest(double x, double y, int *attachment, double *distance)
{
// Imagine four lines radiating from this point. If all of these lines hit the polygon,
// we're inside it, otherwise we're not. Obviously we'd need more radiating lines
// to be sure of correct results for very strange (concave) shapes.
double endPointsX[4];
double endPointsY[4];
// North
endPointsX[0] = x;
endPointsY[0] = (double)(y - 1000.0);
// East
endPointsX[1] = (double)(x + 1000.0);
endPointsY[1] = y;
// South
endPointsX[2] = x;
endPointsY[2] = (double)(y + 1000.0);
// West
endPointsX[3] = (double)(x - 1000.0);
endPointsY[3] = y;
// Store polygon points in an array
int np = m_points->GetCount();
double *xpoints = new double[np];
double *ypoints = new double[np];
wxObjectList::compatibility_iterator node = m_points->GetFirst();
int i = 0;
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
xpoints[i] = point->x + m_xpos;
ypoints[i] = point->y + m_ypos;
node = node->GetNext();
i ++;
}
// We assume it's inside the polygon UNLESS one or more
// lines don't hit the outline.
bool isContained = true;
int noPoints = 4;
for (i = 0; i < noPoints; i++)
{
if (!PolylineHitTest(np, xpoints, ypoints, x, y, endPointsX[i], endPointsY[i]))
isContained = false;
}
/*
if (isContained)
ClipsErrorFunction("It's a hit!\n");
else
ClipsErrorFunction("No hit.\n");
*/
delete[] xpoints;
delete[] ypoints;
if (!isContained)
return false;
int nearest_attachment = 0;
// If a hit, check the attachment points within the object.
int n = GetNumberOfAttachments();
double nearest = 999999.0;
for (i = 0; i < n; i++)
{
double xp, yp;
if (GetAttachmentPositionEdge(i, &xp, &yp))
{
double l = (double)sqrt(((xp - x) * (xp - x)) +
((yp - y) * (yp - y)));
if (l < nearest)
{
nearest = l;
nearest_attachment = i;
}
}
}
*attachment = nearest_attachment;
*distance = nearest;
return true;
}
// Really need to be able to reset the shape! Otherwise, if the
// points ever go to zero, we've lost it, and can't resize.
void wxPolygonShape::SetSize(double new_width, double new_height, bool WXUNUSED(recursive))
{
SetAttachmentSize(new_width, new_height);
// Multiply all points by proportion of new size to old size
double x_proportion = (double)(fabs(new_width/m_originalWidth));
double y_proportion = (double)(fabs(new_height/m_originalHeight));
wxObjectList::compatibility_iterator node = m_points->GetFirst();
wxObjectList::compatibility_iterator original_node = m_originalPoints->GetFirst();
while (node && original_node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
wxRealPoint *original_point = (wxRealPoint *)original_node->GetData();
point->x = (original_point->x * x_proportion);
point->y = (original_point->y * y_proportion);
node = node->GetNext();
original_node = original_node->GetNext();
}
// CalculateBoundingBox();
m_boundWidth = (double)fabs(new_width);
m_boundHeight = (double)fabs(new_height);
SetDefaultRegionSize();
}
// Make the original points the same as the working points
void wxPolygonShape::UpdateOriginalPoints()
{
if (!m_originalPoints) m_originalPoints = new wxList;
wxObjectList::compatibility_iterator original_node = m_originalPoints->GetFirst();
while (original_node)
{
wxObjectList::compatibility_iterator next_node = original_node->GetNext();
wxRealPoint *original_point = (wxRealPoint *)original_node->GetData();
delete original_point;
m_originalPoints->Erase(original_node);
original_node = next_node;
}
wxObjectList::compatibility_iterator node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
wxRealPoint *original_point = new wxRealPoint(point->x, point->y);
m_originalPoints->Append((wxObject*) original_point);
node = node->GetNext();
}
CalculateBoundingBox();
m_originalWidth = m_boundWidth;
m_originalHeight = m_boundHeight;
}
void wxPolygonShape::AddPolygonPoint(int pos)
{
wxObjectList::compatibility_iterator node = m_points->Item(pos);
if (!node) node = m_points->GetFirst();
wxRealPoint *firstPoint = (wxRealPoint *)node->GetData();
wxObjectList::compatibility_iterator node2 = m_points->Item(pos + 1);
if (!node2) node2 = m_points->GetFirst();
wxRealPoint *secondPoint = (wxRealPoint *)node2->GetData();
double x = (double)((secondPoint->x - firstPoint->x)/2.0 + firstPoint->x);
double y = (double)((secondPoint->y - firstPoint->y)/2.0 + firstPoint->y);
wxRealPoint *point = new wxRealPoint(x, y);
if (pos >= (int) (m_points->GetCount() - 1))
m_points->Append((wxObject*) point);
else
m_points->Insert(node2, (wxObject*) point);
UpdateOriginalPoints();
if (m_selected)
{
DeleteControlPoints();
MakeControlPoints();
}
}
void wxPolygonShape::DeletePolygonPoint(int pos)
{
wxObjectList::compatibility_iterator node = m_points->Item(pos);
if (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
delete point;
m_points->Erase(node);
UpdateOriginalPoints();
if (m_selected)
{
DeleteControlPoints();
MakeControlPoints();
}
}
}
// Assume (x1, y1) is centre of box (most generally, line end at box)
bool wxPolygonShape::GetPerimeterPoint(double x1, double y1,
double x2, double y2,
double *x3, double *y3)
{
int n = m_points->GetCount();
// First check for situation where the line is vertical,
// and we would want to connect to a point on that vertical --
// oglFindEndForPolyline can't cope with this (the arrow
// gets drawn to the wrong place).
if ((m_attachmentMode == ATTACHMENT_MODE_NONE) && (x1 == x2))
{
// Look for the point we'd be connecting to. This is
// a heuristic...
wxObjectList::compatibility_iterator node = m_points->GetFirst();
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
if (point->x == 0.0)
{
if ((y2 > y1) && (point->y > 0.0))
{
*x3 = point->x + m_xpos;
*y3 = point->y + m_ypos;
return true;
}
else if ((y2 < y1) && (point->y < 0.0))
{
*x3 = point->x + m_xpos;
*y3 = point->y + m_ypos;
return true;
}
}
node = node->GetNext();
}
}
double *xpoints = new double[n];
double *ypoints = new double[n];
wxObjectList::compatibility_iterator node = m_points->GetFirst();
int i = 0;
while (node)
{
wxRealPoint *point = (wxRealPoint *)node->GetData();
xpoints[i] = point->x + m_xpos;
ypoints[i] = point->y + m_ypos;
node = node->GetNext();
i ++;
}
oglFindEndForPolyline(n, xpoints, ypoints,
x1, y1, x2, y2, x3, y3);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -