示例#1
0
    std::string packLineData(LineData lineData)
    {
        rapidjson::Document document;

        document.SetObject();
        
        rapidjson::Value startPt(rapidjson::kObjectType);
        startPt.AddMember("x", lineData.startPoint.x, document.GetAllocator());
        startPt.AddMember("y", lineData.startPoint.y, document.GetAllocator());

        rapidjson::Value endPt(rapidjson::kObjectType);
        endPt.AddMember("x", lineData.endPoint.x, document.GetAllocator());
        endPt.AddMember("y", lineData.endPoint.y, document.GetAllocator());
        
        rapidjson::Value lineColor(rapidjson::kObjectType);
        lineColor.AddMember("r", lineData.color.r, document.GetAllocator());
        lineColor.AddMember("g", lineData.color.g, document.GetAllocator());
        lineColor.AddMember("b", lineData.color.b, document.GetAllocator());
        lineColor.AddMember("a", lineData.color.a, document.GetAllocator());
        
        document.AddMember("startPoint", startPt, document.GetAllocator());
        document.AddMember("endPoint", endPt, document.GetAllocator());
        document.AddMember("radius", lineData.radius, document.GetAllocator());
        document.AddMember("color", lineColor, document.GetAllocator());
        
        rapidjson::StringBuffer buffer;
        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
        document.Accept(writer);
        
        return std::string(buffer.GetString(), buffer.GetSize());
    }
示例#2
0
//----------------------------------------------------------						
void ofxVectorGraphics::endShape(bool bClose){
	if(bDraw){
		ofEndShape(bClose);
	}
	if(bRecord){
											
		//catmull roms - we need at least 4 points to draw
		if( whichShapeMode == 1 && curvePts.size() > 3){												
			
			//we go through and we calculate the bezier of each 
			//catmull rom curve - smart right? :)
			for (int i = 1; i< curvePts.size()-2; i++) {
				
				ofPoint3 prevPt(	curvePts[i-1][0],	curvePts[i-1][1]);
				ofPoint3 startPt(curvePts[i][0],		curvePts[i][1]);							
				ofPoint3 endPt(	curvePts[i+1][0],	curvePts[i+1][1]);
				ofPoint3 nextPt(	curvePts[i+2][0],	curvePts[i+2][1]);
				
				//SUPER WEIRD MAGIC CONSTANT = 1/6
				//Someone please explain this!!! 
				//It works and is 100% accurate but wtf!
				ofPoint3 cp1 = startPt + ( endPt - prevPt ) * (1.0/6);
				ofPoint3 cp2 = endPt + ( startPt - nextPt ) * (1.0/6);						
				
				//if this is the first line we are drawing 
				//we have to start the path at a location
				if( i == 1 ){
					creeps.startPath(startPt.x, startPt.y);
					bShouldClose = true;
				}
				
				creeps.addCurve( cp1.x, cp1.y, cp2.x, cp2.y, endPt.x, endPt.y);
			}						
		}
		
		if(bShouldClose){														
			//we close the path if requested
			if(bClose)creeps.closeSubpath();
		
			//render the stroke as either a fill or a stroke.
			if(bFill){
				creeps.endPath(CreEPS::FILL);
			}else{
				creeps.endPath(CreEPS::STROKE);
			}
			bShouldClose = false;
		}
		
		//we want to clear all the vertices
		//otherwise we keep adding points from
		//the previous file - cool but not what we want!
		clearAllVertices();
		
	}
}			
示例#3
0
void CXMLExporter::WriteEdge(CComPtr<ISkpEdge> pEdge)
{
    HResult hr;

    m_Stats.m_nEdges += 1;

    if (m_pOptions->GetExportLayers())
    {
        CComPtr<ISkpDrawingElement> pDE;
        hr = pEdge->QueryInterface(IID_ISkpDrawingElement, (void**) &pDE);

        CComPtr<ISkpLayer> pLayer;
        hr = pDE->get_Layer(&pLayer);

        long layerId = GetEntityId(pLayer);

        Write("<Edge layer=\"%d\">\n", layerId);
    }
    else
    {
        Write("<Edge>\n");
    }

    IncreaseIndent();

    CComPtr<ISkpPoint3d> pStartPoint;
    hr = pEdge->get_StartPoint(&pStartPoint);
    CPoint3d startPt(pStartPoint);
    CPoint3d startPoint = m_InheritanceManager.GetCurrentTransform() * startPt;
    Write("<Start x=\"%f\" y=\"%f\" z=\"%f\" />\n", startPoint.X(), startPoint.Y(), startPoint.Z());

    CComPtr<ISkpPoint3d> pEndPoint;
    hr = pEdge->get_EndPoint(&pEndPoint);
    CPoint3d endPt(pEndPoint);
    CPoint3d endPoint = m_InheritanceManager.GetCurrentTransform() * endPt;
    Write("<End x=\"%f\" y=\"%f\" z=\"%f\" />\n", endPoint.X(), endPoint.Y(), endPoint.Z());

    DecreaseIndent();

    Write("</Edge>\n");
}
示例#4
0
void WorldMap::restartGame(){
	Sound::stopSound(GameSound::GameOver);
	Static::gameState = GameState::Playing;
	Point startPt(1280, 2464);//original starting pt
	player->currentLayer = Layer::OverWorld;
	player->prevWorldX = player->worldX;
	player->prevWorldY = player->worldY;
	player->worldX = 4;
	player->worldY = 2;
	float inventoryNewX = player->worldY*Global::roomHeight;
	float inventoryNewY = player->worldX*Global::roomWidth;
	player->inventory->setInventoryPosition(Point(inventoryNewX, inventoryNewY));
	player->inventory->playerBar->setPlayerBar(Point(inventoryNewX, inventoryNewY));
	player->inventory->playerBar->healPlayerToFull();
	player->movePlayerToNewVector = true;
	player->position = startPt;
	player->updateSprites();
	Global::gameView.setCenter(player->worldY*Global::roomWidth + Global::SCREEN_WIDTH / 2,
		player->worldX*Global::roomHeight + Global::SCREEN_HEIGHT / 2);
	Sound::playSound(GameSound::OverWorld);
}
示例#5
0
文件: mgarc.cpp 项目: Vito2015/vgcore
bool MgArc::_setHandlePoint2(int index, const Point2d& pt, float, int& data)
{
    static float lastSweepAngle;
    
    if (index == 1 || index == 2) {     // 起点、终点
        return setCenterRadius(getCenter(), pt.distanceTo(getCenter()), getStartAngle(), getSweepAngle());
    }
    if (index == 3) {                   // 弧线中点
        return setStartMidEnd(getStartPoint(), pt, getEndPoint());
    }
    if (index == 4) {                   // 改变起始角度
        if (data == 0) {
            lastSweepAngle = getSweepAngle();
            data++;
        }
        Point2d startPt(getCenter().polarPoint((pt - getCenter()).angle2(), getRadius()));
        bool ret = setCSE(getCenter(), startPt, getEndPoint(), lastSweepAngle);
        lastSweepAngle = getSweepAngle();
        return ret;
    }
    if (index == 5) {                   // 改变终止角度
        if (data == 0) {
            lastSweepAngle = getSweepAngle();
            data++;
        }
        Point2d endPt(getCenter().polarPoint((pt - getCenter()).angle2(), getRadius()));
        bool ret = setCSE(getCenter(), getStartPoint(), endPt, lastSweepAngle);
        lastSweepAngle = getSweepAngle();
        return ret;
    }
    if (index == 6) {
        return setTanStartEnd(pt - getStartPoint(), getStartPoint(), getEndPoint());
    }
    if (index == 7) {
        return (setTanStartEnd(getEndPoint() - pt, getEndPoint(), getStartPoint())
            && _reverse());
    }
    return offset(pt - getCenter(), -1);
}
示例#6
0
void ObjectGroup::draw(cv::Mat& image)
{
	
	if(getContext()->getDrawingFlags()->mDrawBoundingBox)
	{
		cv::Rect_<float> r = mModel->getLastBoundingBox();

		cv::rectangle(image, r, getColor(), 2);

		cv::rectangle(image, cv::Rect_<float>(r.x - 5, r.y - 7, 12*getObjectId().size(), 14), cv::Scalar(0,0,0), CV_FILLED);
		cv::putText(image, getObjectId(), cv::Point(r.x-5, r.y+4), cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255,255,255),1,8, false);

		std::string stateStr = getStateRepresentativeString(getState());
		cv::Point startPt(r.x-5, r.height+r.y);
		cv::rectangle(image, cv::Rect_<float>(startPt.x, startPt.y-12, 12*stateStr.size(), 14), cv::Scalar(0,0,0), CV_FILLED);
		cv::putText(image, stateStr, startPt, cv::FONT_HERSHEY_DUPLEX, 0.5, cv::Scalar(255,255,255),1,8, false);
	}

	//We don't want to show the Centroid of the blob
	/*if(getContext()->getDrawingFlags()->mDrawCentroid)
	{
		const std::map<int, Blob>& blobs = mModel->getBlobs();
		if(blobs.size() > 1)
		{
			auto it = blobs.begin();
			cv::Point2f lastPt = it->second.getCentroid();
			++it;
			for(; it != blobs.end(); ++it)
			{
				cv::Point2f currentPt = it->second.getCentroid();
				cv::line(image, lastPt, currentPt, getColor(), 3);
				lastPt = currentPt;
			}
		}
	}*/
	for(auto objectIt = mObjectList.begin(); objectIt != mObjectList.end(); ++objectIt)	
		(*objectIt)->draw(image);
	
}
示例#7
0
BOOST_FIXTURE_TEST_CASE(BlockedPaths, WorldFixtureEmpty0P)
{
    MapPoint startPt(10, 10);
    // Create a circle of stones so the path is completely blocked
    std::vector<MapPoint> surroundingPts = world.GetPointsInRadius(startPt, 1);
    BOOST_FOREACH(const MapPoint& pt, surroundingPts)
        world.SetNO(pt, new noGranite(GT_1, 1));
    std::vector<MapPoint> surroundingPts2;
    for(unsigned i=0; i<12; i++)
        surroundingPts2.push_back(world.GetNeighbour2(startPt, i));
    BOOST_FOREACH(const MapPoint& pt, surroundingPts2)
        BOOST_REQUIRE_EQUAL(world.FindHumanPath(startPt, pt), INVALID_DIR);
    // Allow left exit
    world.DestroyNO(surroundingPts[0]);
    BOOST_REQUIRE_EQUAL(world.FindHumanPath(startPt, surroundingPts2[0]), 0);
    BOOST_REQUIRE(checkWalkOnTerrain(world, startPt, surroundingPts2[0], Direction::WEST, TT_WATER, true));
    BOOST_REQUIRE(checkWalkOnTerrain(world, startPt, surroundingPts2[0], Direction::WEST, TT_SWAMPLAND, true));
    BOOST_REQUIRE(checkWalkOnTerrain(world, startPt, surroundingPts2[0], Direction::WEST, TT_LAVA, false));
    BOOST_REQUIRE(checkWalkOnTerrain(world, startPt, surroundingPts2[0], Direction::WEST, TT_SNOW, false));

    BOOST_REQUIRE(checkWalkOnPoint(world, startPt, surroundingPts2[0], Direction::WEST, TT_WATER));
    BOOST_REQUIRE(checkWalkOnPoint(world, startPt, surroundingPts2[0], Direction::WEST, TT_SWAMPLAND));
}
示例#8
0
PointObject* calcPoint(const std::vector<int>& v)
{
	PointObject* pO = nullptr;

	int start_point = 0;
	int end_point = 0;

	auto it = std::find_if(v.begin(), v.end(), [](const int a) { return (a != 0); });
	auto it2 = std::find_if(v.rbegin(), v.rend(), [](int a) { return (a != 0); });

	if ((it != v.end()))
	{
		Point startPt(std::distance(v.begin(), it));
		Point endPt(std::distance(it2, v.rend()) - 1);

		pO = new Point(average(startPt, endPt));
	}
	else
	{
		pO = new NullPoint();
	}

	return pO;
}
示例#9
0
Acad::ErrorStatus
AcDbXmlPoly::xmlOut(
    AcDbObject* pObj,
    AcDbXmlOutFiler* pFiler)
{
    Acad::ErrorStatus es = eOk;

    AsdkPoly* pPoly = AsdkPoly::cast(pObj);
    if (!pPoly)
        return eInvalidInput;

    AcUtXMLDOMNode* pNode = NULL;
    AcUtXMLDOMElement* pElement = NULL;
    AcUtXMLDOMAttribute* pAttribute = NULL;

    try {
        es = pFiler->pushNode(L"asdk:Poly", MY_SCHEMA, pNode);
        if (es != eOk)
            throw es;

        pElement = new AcUtXMLDOMElement(pNode);
        if (pElement == NULL)
            throw eOutOfMemory;

        es = superXmlOut(pObj, pFiler);
        if (es != eOk)
            throw es;

        es = pFiler->appendAttribute(pPoly->numSides(), L"numSides", 
            pElement);
        if (es != eOk)
            throw es;

        AcUtString name=pPoly->name();
        es = pFiler->appendAttribute(name, L"name", pElement);
        if (es != eOk)
            throw es;

        AcGePoint2d pt2d = pPoly->center();
        AcGePoint3d centerPt(pt2d.x, pt2d.y, pPoly->elevation());

        // Convert the point from ECS to WCS
        acdbEcs2Wcs(asDblArray(centerPt), asDblArray(centerPt),
            asDblArray(pPoly->normal()), true);

        es = pFiler->writePoint(L"dxml:CenterPoint", centerPt);
        if (es != eOk)
            throw es;

        pt2d = pPoly->startPoint();
        AcGePoint3d startPt(pt2d.x, pt2d.y, pPoly->elevation());
        // Convert the point from ECS to WCS
        acdbEcs2Wcs(asDblArray(startPt), asDblArray(startPt),
            asDblArray(pPoly->normal()), true);

        es = pFiler->writePoint(L"dxml:StartPoint", startPt);
        if (es != eOk)
            throw es;

        es = pFiler->writeNormalVector(pPoly->normal());
        if (es != eOk)
            throw es;

        es = pFiler->writeHardPointerId(L"acdb:TextStyleTableRecordId", 
            pPoly->styleId());
        if (es != eOk)
            throw es;

        es = pFiler->popNode();
        if (es != eOk)
            throw es;
    }

    catch (Acad::ErrorStatus thrownEs) {
        es = thrownEs;
    }

    if (pAttribute)
        delete pAttribute;
    if (pElement)
        delete pElement;
    if (pNode && pNode != pFiler->getCurrentNode())
        delete pNode;

    return es;
}
void ossimQtVceCanvasWidget::contentsMousePressEvent(QMouseEvent * e )
{
   theMouseButtonState = e->button();
   
   switch(e->button())
   {
   case Qt::LeftButton:
   {
      theLeftDownFlag = true;
      deleteSelectionRect();
      theMouseStartPt = QPoint(e->x(),
                               e->y());
      theSelectionRect = new ossimQtVceShapeRect(QRect(e->x(),
                                                       e->y(),
                                                       1,
                                                       1),
                                                 canvas());
      // make sure that the selection rect is in front of everything
      //
      theSelectionRect->setZ(2);
      
      if(!intersectsSelection())
      {
         
         unselectItems();

         // initialize mode
         //
         QCanvasItemList collisionList    = theSelectionRect->collisions(true);
         ossimQtVceConnectableObject* obj = getObjectWhereConnectableSlotIntersectsPoint(collisionList,
                                                                                         theMouseStartPt);
         if(obj)
         {
            QRect rect;
            if(obj->getConnectionSlotBoundingRect(rect,
                                                  theMouseStartPt))
            {
               delete theSelectionRect;
               theSelectionRect = NULL;
               theLineObject = new QCanvasLine(canvas());
               QPoint startPt(rect.x() + rect.width()/2,
                              rect.y() + rect.height()/2);
               theLineObject->setPoints(startPt.x(),
                                        startPt.y(),
                                        theMouseStartPt.x(),
                                        theMouseStartPt.y());
               theLineObject->setPen(QPen(QColor(0,0,0), 2, Qt::DotLine));
               theLineObject->show();
            }
         }

         if(theSelectionRect)
         {
            // now set the pen style to dashed
            //
            theSelectionRect->hide();
            theSelectionRect->setPen(QPen(QColor(0,0,0), 2, Qt::DotLine));
            theSelectionRect->show();
         }
      }
      else
      {
         deleteSelectionRect();
      }
      
      break;
   }
   case Qt::RightButton:
     {
       thePopupMenu->hide();
       QPoint pt = mapToGlobal(pos());
       thePopupMenu->popup(e->globalPos());
     }
   default:
     {
       break;
     }
   }
   
   emit canvasWidgetMousePressEvent(e);
}
bool ThreadStereo::initializeThread(corresponding_pts& start, tangent_and_score& tan, vector<ThreadPiece_Vision*>& currPieces)
{
  Point3f lastPoint;

  //set opt params
  opt_params_vision.length_per_segment = myThread.length_thread_each_piece;
  opt_params_vision.threadStereo = &myThread;

  opt_params_vision.transform_back = Matrix4d::Identity();
  Vector3d startPt((double)start.pt3d.x, (double)start.pt3d.y, (double)start.pt3d.z);
  opt_params_vision.transform_back.corner(Eigen::TopRight,3,1) = startPt;

  opt_params_vision.orig_params_each_piece = new NEWMAT::ColumnVector(4*NUM_THREAD_PIECES_INIT_OPT+6); 


  //initialize x_sol as if we just finished one iteration
  NEWMAT::ColumnVector x_sol;
  x_sol.ReSize(2*NUM_THREAD_PIECES_FIRST_OPT+3);
  for (int i=0; i < NUM_THREAD_PIECES_FIRST_OPT; i++)
  {
      x_sol.element(2*i) = OPTIMIZATION_INIT_CURVATURE;
      x_sol.element(2*i+1) = OPTIMIZATION_INIT_TORSION;
  }
  x_sol.element(2*NUM_THREAD_PIECES_FIRST_OPT    ) = tan.rot1;
  x_sol.element(2*NUM_THREAD_PIECES_FIRST_OPT + 1) = tan.rot2;
  x_sol.element(2*NUM_THREAD_PIECES_FIRST_OPT + 2) = 0.0;


  //initialize thread as if we just finished one iteration
  Matrix4d transform_at_start;
  transformFromEulerAngles(transform_at_start, x_sol(x_sol.nrows()-2), x_sol(x_sol.nrows()-1), x_sol(x_sol.nrows()), startPt);
  currPieces.resize(0);
  currPieces.push_back(new ThreadPiece_Vision(x_sol(1), x_sol(2), myThread.length_thread_each_piece));
  currPieces.back()->setPrevTransform(transform_at_start);
  currPieces.back()->_numPieces = 1;
  for (int i=1; i < NUM_THREAD_PIECES_FIRST_OPT; i++)
  {
    currPieces.push_back(new ThreadPiece_Vision(x_sol.element(2*i), x_sol.element(2*i+1), myThread.length_thread_each_piece, currPieces[i-1]));
  } 



  for (int numPiecesThisOpt = NUM_THREAD_PIECES_FIRST_OPT; numPiecesThisOpt <= NUM_THREAD_PIECES_INIT_OPT; numPiecesThisOpt++)
  {
    opt_params_vision.num_segments = numPiecesThisOpt;

    for (int i=0; i < numPiecesThisOpt; i++)
    {
      if (i < (x_sol.nrows()-3)/2)
      {
        opt_params_vision.orig_params_each_piece->element(2*i) = x_sol.element(2*i);
        opt_params_vision.orig_params_each_piece->element(2*i+1) = x_sol.element(2*i+1);
      } else {
        opt_params_vision.orig_params_each_piece->element(2*i) = x_sol.element(2*(numPiecesThisOpt-1));
        opt_params_vision.orig_params_each_piece->element(2*i+1) = x_sol.element(2*(numPiecesThisOpt)-1);
      }
    }
    opt_params_vision.orig_params_each_piece->element(2*numPiecesThisOpt    ) = x_sol(x_sol.nrows()-2);
    opt_params_vision.orig_params_each_piece->element(2*numPiecesThisOpt + 1) = x_sol(x_sol.nrows()-1);
    opt_params_vision.orig_params_each_piece->element(2*numPiecesThisOpt + 2) = x_sol(x_sol.nrows());

    //optimize
#ifdef PDS
    if (numPiecesThisOpt == NUM_THREAD_PIECES_INIT_OPT)
      optimize_PDS(2*opt_params_vision.num_segments+3, energyEvalFunctionVisionFirst, energyEvalFunctionVision_init, x_sol, OPTIMIZATION_TOLERANCE_INIT);
    else
      optimize_PDS(2*opt_params_vision.num_segments+3, energyEvalFunctionVisionFirst, energyEvalFunctionVision_init, x_sol, OPTIMIZATION_TOLERANCE_NORMAL);
#else
    if (numPiecesThisOpt == NUM_THREAD_PIECES_INIT_OPT)
      optimize_GSS(2*opt_params_vision.num_segments+3, energyEvalFunctionVisionFirst, energyEvalFunctionVision_init, x_sol, OPTIMIZATION_TOLERANCE_INIT);
    else
      optimize_GSS(2*opt_params_vision.num_segments+3, energyEvalFunctionVisionFirst, energyEvalFunctionVision_init, x_sol, OPTIMIZATION_TOLERANCE_NORMAL);
#endif
    //reset thread params, see if we are done
    transformFromEulerAngles(transform_at_start, x_sol(x_sol.nrows()-2), x_sol(x_sol.nrows()-1), x_sol(x_sol.nrows()), startPt);
    currPieces[0]->setParams(x_sol(1), x_sol(2), myThread.length_thread_each_piece);
    currPieces[0]->setPrevTransform(transform_at_start);
    for (int i=1; i < numPiecesThisOpt; i++)
    {
      if (i < currPieces.size())
        currPieces[i]->setParams(x_sol.element(2*i), x_sol.element(2*i+1), myThread.length_thread_each_piece);
      else
        currPieces.push_back(new ThreadPiece_Vision(x_sol.element(2*i), x_sol.element(2*i+1), myThread.length_thread_each_piece, currPieces.back()));
    } 
    currPieces.back()->getLastPoint(lastPoint);
    if (myThread.isEndPiece(lastPoint))
    {
      //return false;
    }

  }

  return true;

}
/**
 * Function ConvertOutlineToPolygon
 * build a polygon (with holes) from a DRAWSEGMENT list, which is expected to be
 * a outline, therefore a closed main outline with perhaps closed inner outlines.
 * These closed inner outlines are considered as holes in the main outline
 * @param aSegList the initial list of drawsegments (only lines, circles and arcs).
 * @param aPolygons will contain the complex polygon.
 * @param aTolerance is the max distance between points that is still accepted as connected (internal units)
 * @param aErrorText is a wxString to return error message.
 * @param aErrorLocation is the optional position of the error in the outline
 */
bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SET& aPolygons,
                              wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation )
{
    if( aSegList.size() == 0 )
        return true;

    wxString msg;

    // Make a working copy of aSegList, because the list is modified during calculations
    std::vector< DRAWSEGMENT* > segList = aSegList;

    DRAWSEGMENT* graphic;
    wxPoint prevPt;

    // Find edge point with minimum x, this should be in the outer polygon
    // which will define the perimeter Edge.Cuts polygon.
    wxPoint xmin    = wxPoint( INT_MAX, 0 );
    int     xmini   = 0;

    for( size_t i = 0; i < segList.size(); i++ )
    {
        graphic = (DRAWSEGMENT*) segList[i];

        switch( graphic->GetShape() )
        {
        case S_SEGMENT:
            {
                if( graphic->GetStart().x < xmin.x )
                {
                    xmin    = graphic->GetStart();
                    xmini   = i;
                }

                if( graphic->GetEnd().x < xmin.x )
                {
                    xmin    = graphic->GetEnd();
                    xmini   = i;
                }
            }
            break;

        case S_ARC:
            // Freerouter does not yet understand arcs, so approximate
            // an arc with a series of short lines and put those
            // line segments into the !same! PATH.
            {
                wxPoint  pstart = graphic->GetArcStart();
                wxPoint  center = graphic->GetCenter();
                double   angle  = -graphic->GetAngle();
                double   radius = graphic->GetRadius();
                int      steps  = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );
                wxPoint  pt;

                for( int step = 1; step<=steps; ++step )
                {
                    double rotation = ( angle * step ) / steps;

                    pt = pstart;

                    RotatePoint( &pt, center, rotation );

                    if( pt.x < xmin.x )
                    {
                        xmin  = pt;
                        xmini = i;
                    }
                }
            }
            break;

        case S_CIRCLE:
            {
                wxPoint pt = graphic->GetCenter();

                // pt has minimum x point
                pt.x -= graphic->GetRadius();

                // when the radius <= 0, this is a mal-formed circle. Skip it
                if( graphic->GetRadius() > 0 && pt.x < xmin.x )
                {
                    xmin  = pt;
                    xmini = i;
                }
            }
            break;

        case S_CURVE:
            {
                graphic->RebuildBezierToSegmentsPointsList( graphic->GetWidth() );

                for( unsigned int jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
                {
                    wxPoint pt = graphic->GetBezierPoints()[jj];

                    if( pt.x < xmin.x )
                    {
                        xmin  = pt;
                        xmini = i;
                    }
                }
            }
            break;

        case S_POLYGON:
            {
                const auto poly = graphic->GetPolyShape();
                MODULE* module = aSegList[0]->GetParentModule();
                double orientation = module ? module->GetOrientation() : 0.0;
                VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );

                for( auto iter = poly.CIterate(); iter; iter++ )
                {
                    auto pt = *iter;
                    RotatePoint( pt, orientation );
                    pt += offset;

                    if( pt.x < xmin.x )
                    {
                        xmin.x = pt.x;
                        xmin.y = pt.y;
                        xmini = i;
                    }
                }
            }
            break;
        default:
            break;
        }
    }

    // Grab the left most point, assume its on the board's perimeter, and see if we
    // can put enough graphics together by matching endpoints to formulate a cohesive
    // polygon.

    graphic = (DRAWSEGMENT*) segList[xmini];

    // The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items'
    segList.erase( segList.begin() + xmini );

    // Output the Edge.Cuts perimeter as circle or polygon.
    if( graphic->GetShape() == S_CIRCLE )
    {
        int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_LOW_DEF, 360.0 );
        TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps );
    }
    else if( graphic->GetShape() == S_POLYGON )
    {
        MODULE* module = graphic->GetParentModule();     // NULL for items not in footprints
        double orientation = module ? module->GetOrientation() : 0.0;
        VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );

        aPolygons.NewOutline();

        for( auto it = graphic->GetPolyShape().CIterate( 0 ); it; it++ )
        {
            auto pt = *it;
            RotatePoint( pt, orientation );
            pt += offset;
            aPolygons.Append( pt );
        }
    }
    else
    {
        // Polygon start point. Arbitrarily chosen end of the
        // segment and build the poly from here.

        wxPoint startPt = wxPoint( graphic->GetEnd() );
        prevPt = graphic->GetEnd();
        aPolygons.NewOutline();
        aPolygons.Append( prevPt );

        // Do not append the other end point yet of this 'graphic', this first
        // 'graphic' might be an arc or a curve.

        for(;;)
        {
            switch( graphic->GetShape() )
            {
            case S_SEGMENT:
                {
                    wxPoint  nextPt;

                    // Use the line segment end point furthest away from
                    // prevPt as we assume the other end to be ON prevPt or
                    // very close to it.

                    if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
                        nextPt = graphic->GetEnd();
                    else
                        nextPt = graphic->GetStart();

                    aPolygons.Append( nextPt );
                    prevPt = nextPt;
                }
                break;

            case S_ARC:
                // We do not support arcs in polygons, so approximate
                // an arc with a series of short lines and put those
                // line segments into the !same! PATH.
                {
                    wxPoint pstart  = graphic->GetArcStart();
                    wxPoint pend    = graphic->GetArcEnd();
                    wxPoint pcenter = graphic->GetCenter();
                    double  angle   = -graphic->GetAngle();
                    double  radius  = graphic->GetRadius();
                    int     steps   = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );

                    if( !close_enough( prevPt, pstart, aTolerance ) )
                    {
                        wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );

                        angle = -angle;
                        std::swap( pstart, pend );
                    }

                    wxPoint nextPt;

                    for( int step = 1; step<=steps; ++step )
                    {
                        double rotation = ( angle * step ) / steps;
                        nextPt = pstart;
                        RotatePoint( &nextPt, pcenter, rotation );

                        aPolygons.Append( nextPt );
                    }

                    prevPt = nextPt;
                }
                break;

            case S_CURVE:
                // We do not support Bezier curves in polygons, so approximate
                // with a series of short lines and put those
                // line segments into the !same! PATH.
                {
                    wxPoint  nextPt;
                    bool reverse = false;

                    // Use the end point furthest away from
                    // prevPt as we assume the other end to be ON prevPt or
                    // very close to it.

                    if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
                        nextPt = graphic->GetEnd();
                    else
                    {
                        nextPt = graphic->GetStart();
                        reverse = true;
                    }

                    if( reverse )
                    {
                        for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
                            aPolygons.Append( graphic->GetBezierPoints()[jj] );
                    }
                    else
                    {
                        for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
                            aPolygons.Append( graphic->GetBezierPoints()[jj] );
                    }

                    prevPt = nextPt;
                }
                break;

            default:
                if( aErrorText )
                {
                    msg.Printf( "Unsupported DRAWSEGMENT type %s.",
                                BOARD_ITEM::ShowShape( graphic->GetShape() ) );

                    *aErrorText << msg << "\n";
                }

                if( aErrorLocation )
                    *aErrorLocation = graphic->GetPosition();

                return false;
            }

            // Get next closest segment.

            graphic = findPoint( prevPt, segList, aTolerance );

            // If there are no more close segments, check if the board
            // outline polygon can be closed.

            if( !graphic )
            {
                if( close_enough( startPt, prevPt, aTolerance ) )
                {
                    // Close the polygon back to start point
                    // aPolygons.Append( startPt ); // not needed
                }
                else
                {
                    if( aErrorText )
                    {
                        msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
                                    StringFromValue( MILLIMETRES, prevPt.x, true ),
                                    StringFromValue( MILLIMETRES, prevPt.y, true ) );

                        *aErrorText << msg << "\n";
                    }

                    if( aErrorLocation )
                        *aErrorLocation = prevPt;

                    return false;
                }
                break;
            }
        }
    }

    while( segList.size() )
    {
        // emit a signal layers keepout for every interior polygon left...
        int hole = aPolygons.NewHole();

        graphic = (DRAWSEGMENT*) segList[0];
        segList.erase( segList.begin() );

        // Both circles and polygons on the edge cuts layer are closed items that
        // do not connect to other elements, so we process them independently
        if( graphic->GetShape() == S_POLYGON )
        {
            MODULE* module = graphic->GetParentModule();     // NULL for items not in footprints
            double orientation = module ? module->GetOrientation() : 0.0;
            VECTOR2I offset = module ? module->GetPosition() : VECTOR2I( 0, 0 );

            for( auto it = graphic->GetPolyShape().CIterate(); it; it++ )
            {
                auto val = *it;
                RotatePoint( val, orientation );
                val += offset;

                aPolygons.Append( val, -1, hole );
            }
        }
        else if( graphic->GetShape() == S_CIRCLE )
        {
            // make a circle by segments;
            wxPoint  center  = graphic->GetCenter();
            double   angle   = 3600.0;
            wxPoint  start   = center;
            int      radius  = graphic->GetRadius();
            int      steps   = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
            wxPoint  nextPt;

            start.x += radius;

            for( int step = 0; step < steps; ++step )
            {
                double rotation = ( angle * step ) / steps;
                nextPt = start;
                RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
                aPolygons.Append( nextPt, -1, hole );
            }
        }
        else
        {
            // Polygon start point. Arbitrarily chosen end of the
            // segment and build the poly from here.

            wxPoint startPt( graphic->GetEnd() );
            prevPt = graphic->GetEnd();
            aPolygons.Append( prevPt, -1, hole );

            // do not append the other end point yet, this first 'graphic' might be an arc
            for(;;)
            {
                switch( graphic->GetShape() )
                {
                case S_SEGMENT:
                    {
                        wxPoint nextPt;

                        // Use the line segment end point furthest away from
                        // prevPt as we assume the other end to be ON prevPt or
                        // very close to it.

                        if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
                        {
                            nextPt = graphic->GetEnd();
                        }
                        else
                        {
                            nextPt = graphic->GetStart();
                        }

                        prevPt = nextPt;
                        aPolygons.Append( prevPt, -1, hole );
                    }
                    break;

                case S_ARC:
                    // Freerouter does not yet understand arcs, so approximate
                    // an arc with a series of short lines and put those
                    // line segments into the !same! PATH.
                    {
                        wxPoint pstart  = graphic->GetArcStart();
                        wxPoint pend    = graphic->GetArcEnd();
                        wxPoint pcenter = graphic->GetCenter();
                        double  angle   = -graphic->GetAngle();
                        int     radius  = graphic->GetRadius();
                        int     steps = GetArcToSegmentCount( radius, ARC_LOW_DEF, angle / 10.0 );

                        if( !close_enough( prevPt, pstart, aTolerance ) )
                        {
                            wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aTolerance ) );

                            angle = -angle;
                            std::swap( pstart, pend );
                        }

                        wxPoint nextPt;

                        for( int step = 1; step <= steps; ++step )
                        {
                            double rotation = ( angle * step ) / steps;

                            nextPt = pstart;
                            RotatePoint( &nextPt, pcenter, rotation );

                            aPolygons.Append( nextPt, -1, hole );
                        }

                        prevPt = nextPt;
                    }
                    break;

                case S_CURVE:
                    // We do not support Bezier curves in polygons, so approximate
                    // with a series of short lines and put those
                    // line segments into the !same! PATH.
                    {
                        wxPoint  nextPt;
                        bool reverse = false;

                        // Use the end point furthest away from
                        // prevPt as we assume the other end to be ON prevPt or
                        // very close to it.

                        if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
                            nextPt = graphic->GetEnd();
                        else
                        {
                            nextPt = graphic->GetStart();
                            reverse = true;
                        }

                        if( reverse )
                        {
                            for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
                                aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
                        }
                        else
                        {
                            for( size_t jj = 0; jj < graphic->GetBezierPoints().size(); jj++ )
                                aPolygons.Append( graphic->GetBezierPoints()[jj], -1, hole );
                        }

                        prevPt = nextPt;
                    }
                    break;

                default:
                    if( aErrorText )
                    {
                        msg.Printf( "Unsupported DRAWSEGMENT type %s.",
                                    BOARD_ITEM::ShowShape( graphic->GetShape() ) );

                        *aErrorText << msg << "\n";
                    }

                    if( aErrorLocation )
                        *aErrorLocation = graphic->GetPosition();

                    return false;
                }

                // Get next closest segment.

                graphic = findPoint( prevPt, segList, aTolerance );

                // If there are no more close segments, check if polygon
                // can be closed.

                if( !graphic )
                {
                    if( close_enough( startPt, prevPt, aTolerance ) )
                    {
                        // Close the polygon back to start point
                        // aPolygons.Append( startPt, -1, hole );   // not needed
                    }
                    else
                    {
                        if( aErrorText )
                        {
                            msg.Printf( _( "Unable to find segment with an endpoint of (%s, %s)." ),
                                        StringFromValue( MILLIMETRES, prevPt.x, true ),
                                        StringFromValue( MILLIMETRES, prevPt.y, true ) );

                            *aErrorText << msg << "\n";
                        }

                        if( aErrorLocation )
                            *aErrorLocation = prevPt;

                        return false;
                    }
                    break;
                }
            }
        }
    }

    return true;
}
示例#13
0
int testPoint() {
	int numErr = 0;

	logMessage(_T("TESTING  -  class GM_3dPoint ...\n\n"));

	// Default constructor, point must be invalid
	GM_3dPoint pt;
	if (pt.isValid()) {
		logMessage(_T("\tERROR - Default constructor creates valid points\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Default constructor creates invalid points\n"));
	}

	// Get/Set points coordinates
	double x = getRandomDouble();
	double y = getRandomDouble();
	double z = getRandomDouble();
	pt.x(x); pt.y(y); pt.z(z);
	if (pt.x() != x || pt.y() != y || pt.z() != z) {
		logMessage(_T("\tERROR - Get/Set not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Get/Set working\n"));
	}

	// Copy constructor
	GM_3dPoint pt1(pt);
	if (pt.isValid() != pt1.isValid() || pt1.x() != pt.x() || pt1.y() != pt.y() || pt1.z() != pt.z()) {
		logMessage(_T("\tERROR - Copy constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Copy constructor working\n"));
	}

	// Constructor (coordinates)
	x = getRandomDouble();
	y = getRandomDouble();
	z = getRandomDouble();
	GM_3dPoint pt2(x, y, z);
	if (!pt2.isValid() || pt2.x() != x || pt2.y() != y || pt2.z() != z) {
		logMessage(_T("\tERROR - Coordinate constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Coordinate constructor working\n"));
	}

	// Constructor (angle)
	double ang = getRandomAngle();
	GM_3dPoint pt3(ang);
	if (!pt2.isValid() || pt3.x() != cos(ang) || pt3.y() != sin(ang) || pt3.z() != 0.0) {
		logMessage(_T("\tERROR - XY angle constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - XY angle constructor working\n"));
	}
	
	// Invalidation
	pt.invalidate();
	if (pt.isValid()) {
		logMessage(_T("\tERROR - Invalidation not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Invalidation working\n"));
	}

	// Inversion
	GM_3dPoint invPt(pt2);
	invPt.xyInvert();
	if (invPt.isValid() != pt2.isValid() || invPt.x() != -pt2.x() || invPt.y() != -pt2.y() || invPt.z() != pt2.z()) {
		logMessage(_T("\tERROR - Inversion not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Inversion working\n"));
	}

	// Origin check
	GM_3dPoint origPt(GM_NULL_TOLERANCE / 2.0, -GM_NULL_TOLERANCE / 2.0, 0.0);
	if (pt2.isOrigin() || !origPt.isOrigin()) {
		logMessage(_T("\tERROR - Origin check not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Origin check working\n"));
	}

	// Distance
	GM_3dPoint startPt(getRandomDouble(), getRandomDouble(), getRandomDouble());
	GM_3dPoint endPt(getRandomDouble(), getRandomDouble(), getRandomDouble());
	double dx = startPt.x() - endPt.x();
	double dy = startPt.y() - endPt.y();
	double dz = startPt.z() - endPt.z();
	double dist = sqrt(dx*dx + dy*dy + dz*dz);
	if (!startPt.isValid() || !endPt.isValid() || startPt.distFrom(endPt) != dist) {
		logMessage(_T("\tERROR - Distance computation not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Distance computation working\n"));
	}

	// Equality
	GM_3dPoint ptEq1(getRandomDouble(), getRandomDouble(), getRandomDouble());
	GM_3dPoint ptEq2(ptEq1);
	GM_3dPoint ptEq3(ptEq1.x() + getRandomDouble(), ptEq1.y() + getRandomDouble(), ptEq1.z() + getRandomDouble());
	if (ptEq1 != ptEq2 || ptEq1 == ptEq3) {
		logMessage(_T("\tERROR - Equality check not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Equality check working\n"));
	}

	return numErr;
}
示例#14
0
int testLine() {
	int numErr = 0;

	logMessage(_T("TESTING  -  class GM_3dLine ...\n\n"));

	// Default constructor, line must be invalid
	GM_3dLine ln;
	if (ln.isValid()) {
		logMessage(_T("\tERROR - Default constructor creates valid line\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Default constructor creates invalid line\n"));
	}

	// Get/Set line coordinates
	double xStart = getRandomDouble();
	double yStart = getRandomDouble();
	double zStart = getRandomDouble();
	double xEnd = getRandomDouble();
	double yEnd = getRandomDouble();
	double zEnd = getRandomDouble();
	ln.begin().x(xStart);
	ln.begin().y(yStart);
	ln.begin().z(zStart);
	ln.end().x(xEnd);
	ln.end().y(yEnd);
	ln.end().z(zEnd);
	if (!ln.isValid() || ln.begin().x() != xStart || ln.begin().y() != yStart || ln.begin().z() != zStart ||
				ln.end().x() != xEnd || ln.end().y() != yEnd || ln.end().z() != zEnd) {
		logMessage(_T("\tERROR - Get/Set not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Get/Set working\n"));
	}

	// Copy constructor
	GM_3dLine ln1(ln);
	if (ln1.isValid() != ln.isValid() || ln1.begin().x() != ln.begin().x() || ln1.begin().y() != ln.begin().y() || ln1.begin().z() != ln.begin().z() ||
				ln1.end().x() != ln.end().x() || ln1.end().y() != ln.end().y() || ln1.end().z() != ln.end().z()) {
		logMessage(_T("\tERROR - Copy constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Copy constructor working\n"));
	}

	// Constructor (points)
	GM_3dPoint startPt(getRandomDouble(), getRandomDouble(), getRandomDouble());
	GM_3dPoint endPt(getRandomDouble(), getRandomDouble(), getRandomDouble());
	GM_3dLine ln2(startPt, endPt);
	if (!ln2.isValid() || ln2.begin().x() != startPt.x() || ln2.begin().y() != startPt.y() || ln2.begin().z() != startPt.z() ||
			ln2.end().x() != endPt.x() || ln2.end().y() != endPt.y() || ln2.end().z() != endPt.z()) {
		logMessage(_T("\tERROR - Points constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Points constructor working\n"));
	}

	// Constructor (coordinates)
	xStart = getRandomDouble();
	yStart = getRandomDouble();
	zStart = getRandomDouble();
	xEnd = getRandomDouble();
	yEnd = getRandomDouble();
	zEnd = getRandomDouble();
	GM_3dLine ln3(xStart, yStart, zStart, xEnd, yEnd, zEnd);
	if (!ln3.isValid() || ln3.begin().x() != xStart || ln3.begin().y() != yStart || ln3.begin().z() != zStart ||
			ln3.end().x() != xEnd || ln3.end().y() != yEnd || ln3.end().z() != zEnd) {
		logMessage(_T("\tERROR - Coordinate constructor not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Coordinate constructor working\n"));
	}

	// dx, dy, dz
	double dx = ln2.dx();
	double dy = ln2.dy();
	double dz = ln2.dz();
	if (dx != ln2.end().x()-ln2.begin().x() || dy != ln2.end().y()-ln2.begin().y() || dz != ln2.end().z()-ln2.begin().z()) {
		logMessage(_T("\tERROR - dx, dy or dz not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - dx, dy or dz working\n"));
	}

	// Dot product
	double dotProduct = ln2 * ln3;
	double dxLn2 = ln2.dx();
	double dyLn2 = ln2.dy();
	double dzLn2 = ln2.dz();
	double dxLn3 = ln3.dx();
	double dyLn3 = ln3.dy();
	double dzLn3 = ln3.dz();
	double checkDotProduct = dxLn2*dxLn3 + dyLn2*dyLn3 + dzLn2*dzLn3;
	if (dotProduct != checkDotProduct) {
		logMessage(_T("\tERROR - Dot product not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Dot product working\n"));
	}

	// Cross product
	GM_3dLine crossProdLn = ln2 ^ ln3;
	double checkCrossProdX = ln2.begin().x() + (dyLn2*dzLn3 - dzLn2*dyLn3);
	double checkCrossProdY = ln2.begin().y() + (dzLn2*dxLn3 - dxLn2*dzLn3);
	double checkCrossProdZ = ln2.begin().z() + (dxLn2*dyLn3 - dyLn2*dxLn3);
	if (!crossProdLn.isValid() || crossProdLn.end().x() != checkCrossProdX || crossProdLn.end().y() != checkCrossProdY || crossProdLn.end().z() != checkCrossProdZ) {
		logMessage(_T("\tERROR - Cross product not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Cross product working\n"));
	}

	// Center
	GM_3dPoint ln2Center = ln2.center();
	if (!ln2Center.isValid() || ln2Center.x() != ln2.begin().x() + (ln2.end().x()-ln2.begin().x())/2.0 ||
								ln2Center.y() != ln2.begin().y() + (ln2.end().y()-ln2.begin().y())/2.0 ||
								ln2Center.z() != ln2.begin().z() + (ln2.end().z()-ln2.begin().z())/2.0) {
		logMessage(_T("\tERROR - Center point computation not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Center point computation working\n"));
	}

	// Invert
	GM_3dLine ln2Copy(ln2);
	ln2.invert();
	if (!ln2Copy.isValid() || ln2Copy.begin().x() != ln2.end().x() || ln2Copy.begin().y() != ln2.end().y() || ln2Copy.begin().z() != ln2.end().z() ||
			ln2Copy.end().x() != ln2.begin().x() || ln2Copy.end().y() != ln2.begin().y() || ln2Copy.end().z() != ln2.begin().z()) {
		logMessage(_T("\tERROR - Inversion not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Inversion working\n"));
	}

	// Length
	double checkLen = sqrt(ln2.dx()*ln2.dx() + ln2.dy()*ln2.dy() + ln2.dz()*ln2.dz());
	if (ln2.length() != checkLen) {
		logMessage(_T("\tERROR - Length computation not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Length computation working\n"));
	}

	// Null check
	GM_3dLine nullLn(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
	bool checkNull1 = nullLn.isNull();
	nullLn.begin().x(10.0);
	bool checkNull2 = nullLn.isNull();
	if (!nullLn.isValid() || !checkNull1 || checkNull2) {
		logMessage(_T("\tERROR - Null line check not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Null line check working\n"));
	}

	// Vertical line check
	double xCoord = getRandomDouble();
	double yCoord = getRandomDouble();
	GM_3dLine vertLn(xCoord, yCoord, getRandomDouble(), xCoord, yCoord, getRandomDouble());
	bool checkVert1 = vertLn.isVertical();
	vertLn.begin().x(vertLn.begin().x() + 10.0);
	bool checkVert2 = vertLn.isVertical();
	if (!vertLn.isValid() || !checkVert1 || checkVert2) {
		logMessage(_T("\tERROR - Vertical line check not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Vertical line check working\n"));
	}

	// Horizontal line check
	double zCoord = getRandomDouble();
	GM_3dLine horLn(getRandomDouble(), getRandomDouble(), zCoord, getRandomDouble(), getRandomDouble(), zCoord);
	bool checkHor1 = horLn.isHorizontal();
	horLn.begin().z(horLn.begin().z() + 10.0);
	bool checkHor2 = horLn.isHorizontal();
	if (!horLn.isValid() || !checkHor1 || checkVert2) {
		logMessage(_T("\tERROR - Horizontal line check not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Horizontal line check working\n"));
	}

	// Z min/max
	double minZ = ln2.minZ();
	double maxZ = ln2.maxZ();
	double checkMin = ln2.begin().z() < ln2.end().z() ? ln2.begin().z() : ln2.end().z();
	double checkMax = ln2.begin().z() > ln2.end().z() ? ln2.begin().z() : ln2.end().z();
	if (minZ != checkMin || maxZ != checkMax) {
		logMessage(_T("\tERROR - min/max Z not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - min/max Z working\n"));
	}

	// Point on line at Z
	double sec = getRandom01Double();
	double dX = ln2.dx();
	double dY = ln2.dy();
	double dZ = ln2.dz();
	double xCheck = ln2.begin().x() + (sec * dX);
	double yCheck = ln2.begin().y() + (sec * dY);
	double zCheck = ln2.begin().z() + (sec * dZ);
	GM_3dPoint pointAtZ = ln2.pointAtZ(zCheck);
	if (!pointAtZ.isValid() || fabs(pointAtZ.x()-xCheck) > GM_NULL_TOLERANCE || fabs(pointAtZ.y()-yCheck) > GM_NULL_TOLERANCE) {
		logMessage(_T("\tERROR - Point on line at Z not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Point on line at Z working\n"));
	}

	// Nomal vector on XY
	GM_3dVector normalVectorR = ln2.normalXYVector(true);
	GM_3dVector normalVectorL = ln2.normalXYVector(false);
	GM_3dVector ln2Dir(ln2);
	double dotPR = normalVectorR * ln2Dir;
	double dotPL = normalVectorL * ln2Dir;
	bool RSide = ln2Dir.isAtLeftOnXY(normalVectorR);
	bool LSide = ln2Dir.isAtLeftOnXY(normalVectorL);
	if (!normalVectorR.isValid() || !normalVectorL.isValid() || fabs(dotPR) > GM_NULL_TOLERANCE || fabs(dotPL) > GM_NULL_TOLERANCE || !RSide || LSide) {
		logMessage(_T("\tERROR - XY normal vector computation not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - XY normal vector computation working\n"));
	}

	// Point from section
	double section = getRandom01Double();
	GM_3dPoint sectionPoint = ln2.pointFromSection(section);
	double ln2Len = ln2.length();
	double pointSectionLen = ln2.begin().distFrom(sectionPoint);
	if (fabs((pointSectionLen / ln2Len) - section) > GM_NULL_TOLERANCE) {
		logMessage(_T("\tERROR - Point from section not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Point from section working\n"));
	}

	// Section from point
	double checkSection = ln2.sectionFromPoint(sectionPoint);
	if (fabs(checkSection - section) > GM_NULL_TOLERANCE) {
		logMessage(_T("\tERROR - Section from point not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Section from point working\n"));
	}

	// Point distance
	ln2Dir.normalize();
	GM_3dVector ln2NormDir(ln2Dir);
	section = getRandom01Double();
	sectionPoint = ln2.pointFromSection(section);
	if (fabs(ln2Dir.x()) > GM_NULL_TOLERANCE) {
		ln2NormDir.x(getRandomDouble());
		ln2NormDir.y(getRandomDouble());
		ln2NormDir.z(getRandomDouble());
		ln2NormDir.normalize();
		ln2NormDir.x(-(ln2Dir.y()*ln2NormDir.y() + ln2Dir.z()*ln2NormDir.z()) / ln2Dir.x());
	}
	else if (fabs(ln2Dir.y()) > GM_NULL_TOLERANCE) {
		ln2NormDir.x(getRandomDouble());
		ln2NormDir.y(getRandomDouble());
		ln2NormDir.z(getRandomDouble());
		ln2NormDir.normalize();
		ln2NormDir.y(-(ln2Dir.x()*ln2NormDir.x() + ln2Dir.z()*ln2NormDir.z()) / ln2Dir.y());
	}
	else if (fabs(ln2Dir.z()) > GM_NULL_TOLERANCE) {
		ln2NormDir.x(getRandomDouble());
		ln2NormDir.y(getRandomDouble());
		ln2NormDir.z(getRandomDouble());
		ln2NormDir.normalize();
		ln2NormDir.z(-(ln2Dir.x()*ln2NormDir.x() + ln2Dir.y()*ln2NormDir.y()) / ln2Dir.z());
	}
	else {
		ln2NormDir.invalidate();
	}
	double dist = 0.0;
	double checkDist = 0.0;
	GM_3dPoint pointOnLine;
	if (ln2NormDir.isValid()) {
		ln2NormDir.normalize();

		double dotProd = ln2NormDir * ln2Dir;

		dist = fabs(getRandomDouble());
		GM_3dPoint externPoint(sectionPoint);
		externPoint = (GM_3dVector)externPoint + (ln2NormDir * dist);
		checkDist = ln2.pointDistance(externPoint, pointOnLine);
	}
	if (!pointOnLine.isValid() || fabs(dist - checkDist) > GM_NULL_TOLERANCE) {
		logMessage(_T("\tERROR - Point distance not working\n"));
		numErr++;
	}
	else {
		logMessage(_T("\tOK - Point distance working\n"));
	}


	return numErr;
}