Good afternoon, I have been working with graphics in Qt relatively recently, I ran into such a problem. For reasons that are unclear to me,
PART of the QGraphicsItem is not drawn under the selection, and after releasing the selection appears only when calling update method, mousePressed does not work in these disappearing zones too (see screen 2), but if you select the same item in a bit other place, everything is OK, moreover, at some locations this error disappears (see screen 3) blue rectangles these are boundingRect, red outline shape, gray rectangles proxyWidget nested in bright green GraphicsItem. thank you in advanceinJust Build
Selection break Same Instance, Just Move widgets a bit, and no error
HPP
#include <QGraphicsLineItem>
#include <QMoveEvent>
class pin;
class customGraphicsview;
class connector;
class Dot;
#include"dot.h"
#include"pin.h"
#include"connector.h"
#include<QGraphicsItem>
#include <QPainter>
#include<QPointF>
#include<QDebug>
#include<QColor>
class Whire : public QGraphicsItem
{
public:
Whire(pin *nitem1, pin *nitem2,customGraphicsview*gv);
void Update(bool OneMore=false);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
pin *pin1,*pin2;
void collisions();
void DotDot(Whire* w);
void collisionfix(Whire* w);
void collisionfix(connector* cn);
void mousePressEvent(QGraphicsSceneMouseEvent *e) override;
void colChange(QColor co);
QColor color();
QPointF NeartoPindot(pin* p,bool bl);
QPointF NeartoPin(pin* p);
~Whire();
private:
QColor col;
bool selected=false;
QVector<Dot*>points;
void drawLine(Dot* p1, Dot* p2, Dot* p3, int& r, QPainter* p,bool last=false);
void drawLine(Dot* p1, Dot* p2,QPainter* p);
QRectF boundingRect() const override;
QPainterPath shape() const override;
customGraphicsview* gview;
bool p2c=false,p3c=false;
};
CPP
#include "whire.h"
#include"customviewmap.h"
#include<qgraphicsitem.h>
Whire::Whire(pin *nitem1, pin *nitem2,customGraphicsview* gv): QGraphicsItem()
{
pin1=nitem1;
pin2=nitem2;
gview=gv;
if(dynamic_cast<customviewMap*>(gview->view)!=nullptr)
{
dynamic_cast<customviewMap*>(gview->view)->Add(this);
}
gview->scene()->addItem(this);
col=Qt::darkGray;
points=QVector<Dot*>();
pin1->addWhire(this);
pin2->addWhire(this);
points.clear();
Dot* p = new Dot(pin1->whirepos(pin2), 0,gview->scene());
points.append(p);
p = new Dot(pin2->whirepos(pin1), 1, gview->scene());
points.append(p);
p = new Dot(((float)(points[0]->pos().x() + points.last()->pos().x()) / 2), points[0]->pos().y(), 1, gview->scene());
points.insert(1, p);
p = new Dot(((float)(points[0]->pos().x() + points.last()->pos().x()) / 2), points.last()->pos().y(), 0, gview->scene());
points.insert(2, p);
collisions();
}
void Whire::Update(bool colfix)
{
prepareGeometryChange();
Dot* p = new Dot(pin1->whirepos(pin2), 0,scene());
delete points[0];
points[0] = p;
p = new Dot(pin2->whirepos(pin1), 1, scene());
delete points.last();
points.last() = p;
p = new Dot(((float)(points[0]->pos().x() + points.last()->pos().x()) / 2), points[0]->pos().y(), 1, scene());
delete points[1];
points[1] = p;
p = new Dot(((float)(points[0]->pos().x() + points.last()->pos().x()) / 2), points.last()->pos().y(), 0, scene());
delete points[points.count() - 2];
points[points.count() - 2] = p;
for (int i = 2; i < points.count()-2; i++)
{
delete points[i];
points.remove(i);
}
this->update();
if(colfix)
{
collisions();
}
}
void Whire::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//qDebug()<<points.count();
/*
int radius=0;
painter->setPen(QPen(col,8));
for(int i=0;i<points.count()-3;i++)
{
drawLine(points[i],points[i+1],points[i+2],radius,painter);
}
if(points.count()>2)
drawLine(points[points.count()-3],points[points.count()-2],points[points.count()-1],radius,painter,true);
*/
for (int i = 0; i < points.count()-1; i++)
drawLine(points[i], points[i + 1],painter);
painter->setPen(QPen(Qt::red,Qt::DashDotDotLine));
painter->setBrush(QBrush(Qt::transparent));
painter->drawPath(shape());
painter->setPen(QPen(Qt::darkBlue, Qt::DashLine));
painter->drawRect(boundingRect());
}
void Whire::collisions()
{
QList<Whire*>colWhires=QList<Whire*>();
QList<connector*>colConn=QList<connector*>();
Whire* wr;
connector* cn;
RefreshWGraphicsRectItem* RGI;
QList<QGraphicsItem *> items = collidingItems();
foreach (QGraphicsItem *item, items)
{
RGI=dynamic_cast<RefreshWGraphicsRectItem*>(item);
if(RGI!=nullptr)
{
break;
}
wr = dynamic_cast<Whire*>(item);
if(wr != nullptr)
{
colWhires.append(wr);
break;
}
cn = dynamic_cast<connector*>((dynamic_cast<QGraphicsProxyWidget*>(item))->widget());
if( cn != nullptr)
{
if(cn!=pin1->connectr()&&cn!=pin2->connectr())
{
colConn.append(cn);
}
}
}
foreach(Whire* wr, colWhires)
{
collisionfix(wr);
}
foreach(connector* cn,colConn)
{
//collisionfix(cn);
}
if(abs(pin1->whirepos().x()-pin2->whirepos().x())<pin1->connectr()->size().width())
{
if(pin1->connectr()->pos().x()<=pin2->connectr()->pos().x())
{
points[0]= new Dot(QPointF(pin1->whirepos(QPointF(pin1->connectr()->pos().x()-pin1->connectr()->size().width(),pin1->connectr()->pos().y()))),points[0]->inH, scene());
}
else
{
points[0]= new Dot(QPointF(pin1->whirepos(QPointF(pin1->connectr()->pos().x()+2*pin1->connectr()->size().width(),pin1->connectr()->pos().y()))),points[0]->inH, scene());
}
}
}
void Whire::DotDot(Whire* w)
{
enum doupin
{
pin1_pin1,
pin1_pin2,
pin2_pin1,
pin2_pin2
};
QPointF p2, wp2, doublepin;
doupin dpin;
if (pin1 == w->pin1)
{
dpin = pin1_pin1;
p2 = this->pin2->whirepos(pin1);
wp2 = w->pin2->whirepos(w->pin1);
doublepin = pin1->whirepos(pin2);
points.first()->setPos(pin1->whirepos(pin2));
points[1]->setY(points.first()->y());
w->points.first()->setPos(points.first()->pos());
w->points[1]->setY(w->points.first()->y());
}
if (pin1 == w->pin2)
{
dpin = pin1_pin2;
p2 = this->pin2->whirepos(pin1);
wp2 = w->pin1->whirepos(w->pin2);
doublepin = pin1->whirepos(pin2);
points.first()->setPos(pin1->whirepos(pin2));
points[1]->setY(points.first()->y());
w->points.last()->setPos(points.first()->pos());
w->points[w->points.size()-2]->setY(w->points.last()->y());
}
if (pin2 == w->pin1)
{
dpin = pin2_pin1;
p2 = this->pin1->whirepos(pin2);
wp2 = w->pin2->whirepos(w->pin1);
doublepin = pin2->whirepos(pin1);;
points.last()->setPos(pin2->whirepos(pin1));
points[points.size()-2]->setY(points.last()->y());
w->points.first()->setPos(points.first()->pos());
w->points[1]->setY(w->points.first()->y());
}
if (pin2 == w->pin2)
{
dpin = pin2_pin2;
p2 = this->pin1->whirepos(pin2);
wp2 = w->pin1->whirepos(w->pin2);
doublepin = pin2->whirepos(pin1);
points.last()->setPos(pin2->whirepos(pin1));
points[points.size() - 2]->setY(points.last()->y());
w->points.last()->setPos(points.first()->pos());
w->points[w->points.size() - 2]->setY(w->points.last()->y());
}
w->scene()->update();
return;
}
void Whire::collisionfix(Whire *w)
{
for (int j = 0; j < w->points.count() - 1; j++)
{
for (int i = 0; i < points.count() - 1; i++)
{
if (true);
{
if (points[i]->inH)
{
if (w->points[j]->inH)
{
if (abs(points[i]->pos().x() - w->points[j]->pos().x()) <= 40)
{
if (points[i - 1]->pos().x() <= points[i]->pos().x())
{
if (w->points[j - 1]->pos().x() <= w->points[j]->pos().x())
{
if (abs(points[i]->pos().y() - points[i + 1]->pos().y()) < abs(w->points[j]->pos().y() - w->points[j + 1]->pos().y()))
{
points[i]->setPos(points[i]->pos().x() - 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() + 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() - 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() + 25, w->points[j + 1]->pos().y());
w->Update();
}
else
{
points[i]->setPos(points[i]->pos().x() + 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() - 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() + 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() - 25, w->points[j + 1]->pos().y());
//w->Update();
}
}
else
{
points[i]->setPos(points[i]->pos().x() - 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() + 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() - 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() + 25, w->points[j + 1]->pos().y());
w->Update();
}
}
else
{
if (w->points[j - 1]->pos().x() >= w->points[j]->pos().x())
{
if (abs(points[i]->pos().y() - points[i + 1]->pos().y()) < abs(w->points[j]->pos().y() - w->points[j + 1]->pos().y()))
{
points[i]->setPos(points[i]->pos().x() - 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() + 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() - 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() + 25, w->points[j + 1]->pos().y());
w->Update();
}
else
{
points[i]->setPos(points[i]->pos().x() + 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() - 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() + 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() - 25, w->points[j + 1]->pos().y());
//w->Update();
}
}
else
{
points[i]->setPos(points[i]->pos().x() - 35, points[i]->pos().y());
w->points[j]->setPos(w->points[j]->pos().x() + 25, w->points[j]->pos().y());
points[i + 1]->setPos(points[i + 1]->pos().x() - 35, points[i + 1]->pos().y());
w->points[j + 1]->setPos(w->points[j + 1]->pos().x() + 25, w->points[j + 1]->pos().y());
w->Update();
}
}
}
}
else
{
//Bridge;
}
}
else
{
if (!w->points[j]->inH)
{
if (abs(points[i]->pos().y() - w->points[j]->pos().y()) <= 40)
{
if (points[i]->pos().y() > w->points[j]->pos().y())
{
points[i]->setPos(points[i]->pos().x(), points[i]->pos().y() + 35);
w->points[j]->setPos(w->points[j]->pos().x(), w->points[j]->pos().y() - 25);
points[i + 1]->setPos(points[i + 1]->pos().x(), points[i + 1]->pos().y() + 35);
w->points[j + 1]->setPos(w->points[j + 1]->pos().x(), w->points[j + 1]->pos().y() - 25);
}
else
{
points[i]->setPos(points[i]->pos().x(), points[i]->pos().y() - 25);
w->points[j]->setPos(w->points[j]->pos().x(), w->points[j]->pos().y() + 35);
points[i + 1]->setPos(points[i + 1]->pos().x(), points[i + 1]->pos().y() - 25);
w->points[j + 1]->setPos(w->points[j + 1]->pos().x(), w->points[j + 1]->pos().y() + 35);
}
}
}
else
{
//Bridge;
}
}
}
}
}
w->pin1->addDot(true);
w->pin2->addDot(true);
}
void Whire::collisionfix(connector *cn)
{
}
void Whire::colChange(QColor co)
{
col=co;
pin1->ColorChange(col);
pin2->ColorChange(col);
}
QColor Whire::color()
{
return col;
}
QPointF Whire::NeartoPindot(pin *p,bool bl)
{
if(pin1==p)
{
return points[1]->pos();
}
else if(pin2==p)
{
return points[points.count() - 2]->pos();
}
}
QPointF Whire::NeartoPin(pin *p)
{
if(pin1==p)
{
return points[1]->pos();
}
else if(pin2==p)
{
return points[points.count()-2]->pos();
}
}
Whire::~Whire()
{
pin1->removeW(this);
pin2->removeW(this);
if(dynamic_cast<customviewMap*>(gview->view)!=nullptr)
{
dynamic_cast<customviewMap*>(gview->view)->Remove(this);
}
}
void Whire::drawLine(Dot* pos1, Dot* pos2, Dot* pos3, int &Radius2, QPainter* painter,bool last)
{
painter->setPen(QPen(col,8));
int Nrad;
if(!pos2->isVisible())
{
if(pos2->inH)
{
Nrad=qMin((double)Radius2,abs(pos2->pos().y()-pos3->pos().y())/10);
if (Nrad==0)
Nrad=abs(pos2->pos().y()-pos3->pos().y())/10;
if(pos1->pos().x()<=pos2->pos().x())
{
if(pos2->pos().y()<=pos3->pos().y())
{
painter->drawLine(pos1->pos().x()+Radius2,pos1->pos().y(),pos2->pos().x()-Nrad,pos2->pos().y());
painter->drawArc(pos2->pos().x()-2*Nrad,pos2->pos().y(),2*Nrad,2*Nrad,0*16,90*16);
}
else
{
painter->drawLine(pos1->pos().x()+Radius2,pos1->pos().y(),pos2->pos().x()-Nrad,pos2->pos().y());
painter->drawArc(pos2->pos().x()-2*Nrad,pos2->pos().y()-2*Nrad,2*Nrad,2*Nrad,270*16,90*16);
}
}
else
{
if(pos2->pos().y()<=pos3->pos().y())
{
painter->drawLine(pos1->pos().x()-Radius2,pos1->pos().y(),pos2->pos().x()+Nrad,pos2->pos().y());
painter->drawArc(pos2->pos().x(),pos2->pos().y(),2*Nrad,2*Nrad,90*16,90*16);
}
else
{
painter->drawLine(pos1->pos().x()-Radius2,pos1->pos().y(),pos2->pos().x()+Nrad,pos2->pos().y());
painter->drawArc(pos2->pos().x(),pos2->pos().y()-2*Nrad,2*Nrad,2*Nrad,180*16,90*16);
}
}
}
else
{
Nrad=qMin((double)Radius2,abs(pos2->pos().x()-pos3->pos().x())/10);
if(pos1->pos().y()<=pos2->pos().y())
{
if(pos2->pos().x()<=pos3->pos().x())
{
painter->drawLine(pos1->pos().x(),pos1->pos().y()+Radius2,pos2->pos().x(),pos2->pos().y()-Nrad);
painter->drawArc(pos2->pos().x(),pos2->pos().y()-2*Nrad,2*Nrad,2*Nrad,180*16,90*16);
if(last)
painter->drawLine(pos2->pos().x()+Nrad,pos2->pos().y(),pos3->pos().x(),pos3->pos().y());
}
else
{
painter->drawLine(pos1->pos().x(),pos1->pos().y()+Radius2,pos2->pos().x(),pos2->pos().y()-Nrad);
painter->drawArc(pos2->pos().x()-2*Nrad,pos2->pos().y()-2*Nrad,2*Nrad,2*Nrad,270*16,90*16);
if(last)
painter->drawLine(pos2->pos().x()-Nrad,pos2->pos().y(),pos3->pos().x(),pos3->pos().y());
}
}
else
{
if(pos2->pos().x()<=pos3->pos().x())
{
painter->drawLine(pos1->pos().x(),pos1->pos().y()-Radius2,pos2->pos().x(),pos2->pos().y()+Nrad);
painter->drawArc(pos2->pos().x(),pos2->pos().y(),2*Nrad,2*Nrad,90*16,90*16);
if(last)
painter->drawLine(pos2->pos().x()+Nrad,pos2->pos().y(),pos3->pos().x(),pos3->pos().y());
}
else
{
painter->drawLine(pos1->pos().x(),pos1->pos().y()-Radius2,pos2->pos().x(),pos2->pos().y()+Nrad);
painter->drawArc(pos2->pos().x()-2*Nrad,pos2->pos().y(),2*Nrad,2*Nrad,0*16,90*16);
if(last)
painter->drawLine(pos2->pos().x()-Nrad,pos2->pos().y(),pos3->pos().x(),pos3->pos().y());
}
}
}
Radius2=Nrad;
}
else
{
painter->drawLine(pos1->pos(),pos2->pos());
painter->drawLine(pos1->pos(),pos2->pos());
painter->drawEllipse(pos2->pos(),5,5);
}
}
void Whire::drawLine(Dot* p1, Dot* p2, QPainter* p)
{
p->setPen(QPen(col, 8));
p->drawLine(p1->pos(), p2->pos());
}
QRectF Whire::boundingRect() const
{
QRectF rect= shape().boundingRect();
rect.setRect(rect.x() - 10, rect.y() - 10, rect.width() + 10, rect.height() + 10);
return rect;
}
QPainterPath Whire::shape() const
{
QPainterPath p=QPainterPath();
int x,y,w,h;
for(int i=0;i<points.count()-1;i++)
{
x=qMin(points[i]->pos().x(),points[i+1]->pos().x());
x-=5;
y=qMin(points[i]->pos().y(),points[i+1]->pos().y());
y-=5;
w=abs(points[i]->pos().x()-points[i+1]->pos().x());
w+=10;
h=abs(points[i]->pos().y()-points[i+1]->pos().y());
h+=10;
p.addRect(x,y,w,h);
}
return p;
}
void Whire::mousePressEvent(QGraphicsSceneMouseEvent *e)
{
if(e->modifiers()&Qt::SHIFT)
{
delete this;
}
else
{
if(col!=Qt::red)
col=Qt::red;
else
col=Qt::darkGray;
Update();
}
}
Related
I am working on a Xamarin.Forms map screen and i need to implement an overlay that contains circle around a pin on the map, as shown on the screenshot.
The problem is on the IOS version. I cannot move the map inside the circle. The android version works just fine.
Repo for the project: https://github.com/CrossGeeks/OverlaySample
Any help with the custom renderer would be appreciated!!!
using System;
using System.ComponentModel;
using CoreGraphics;
using OverlaySample.Controls;
using OverlaySample.iOS.Renderers;
using OverlaySample.iOS.Views;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(OverlayView), typeof(OverlayViewRenderer))]
namespace OverlaySample.iOS.Renderers
{
public class OverlayViewRenderer : ViewRenderer<OverlayView, NativeOverlayView>
{
protected override void OnElementChanged(ElementChangedEventArgs<OverlayView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
SetNativeControl(new NativeOverlayView()
{
ContentMode= UIViewContentMode.ScaleToFill
});
}
if (e.NewElement != null)
{
Control.Opacity = (float)Element.OverlayOpacity;
Control.ShowOverlay = Element.ShowOverlay;
Control.OverlayBackgroundColor = Element.OverlayBackgroundColor.ToUIColor();
Control.OverlayShape = Element.Shape;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == OverlayView.OverlayOpacityProperty.PropertyName)
{
Control.Opacity = (float)Element.OverlayOpacity;
Control.UpdateOpacity();
}
else if (e.PropertyName == OverlayView.OverlayBackgroundColorProperty.PropertyName)
{
Control.OverlayBackgroundColor = Element.OverlayBackgroundColor.ToUIColor();
Control.UpdateFillColor();
}
else if (e.PropertyName == OverlayView.ShapeProperty.PropertyName)
{
Control.OverlayShape = Element.Shape;
Control.UpdatePath();
}
else if (e.PropertyName == OverlayView.ShowOverlayProperty.PropertyName)
{
Control.ShowOverlay = Element.ShowOverlay;
}
}
bool rendered = false;
public override void LayoutSubviews()
{
base.LayoutSubviews();
if(!rendered && Control.ShowOverlay)
{
Control.AddOverlayLayer();
rendered = true;
}
}
}
}
And the OverlaySample.iOS.Views:
namespace OverlaySample.iOS.Views
{
public class NativeOverlayView : UIView
{
bool showOverlay = true;
public bool ShowOverlay
{
get { return showOverlay; }
set
{
showOverlay = value;
if (showOverlay)
AddOverlayLayer();
else
RemoveOverlayLayer();
}
}
CAShapeLayer overlayLayer = null;
public float Opacity { get; set; } = 0.5f;
public UIColor OverlayBackgroundColor { get; set; } = UIColor.Clear;
public OverlayShape OverlayShape { get; set; } = OverlayShape.Circle;
UIBezierPath GetHeartOverlayPath(CGRect originalRect, float scale)
{
var scaledWidth = (originalRect.Size.Width * scale);
var scaledXValue = ((originalRect.Size.Width) - scaledWidth) / 2;
var scaledHeight = (originalRect.Size.Height * scale);
var scaledYValue = ((originalRect.Size.Height) - scaledHeight) / 2;
var scaledRect = new CGRect(x: scaledXValue, y: scaledYValue, width: scaledWidth, height: scaledHeight);
UIBezierPath path = new UIBezierPath();
path.MoveTo(new CGPoint(x: originalRect.Size.Width / 2, y: scaledRect.Y + scaledRect.Size.Height));
path.AddCurveToPoint(new CGPoint(x: scaledRect.X, y: scaledRect.Y + (scaledRect.Size.Height / 4)),
controlPoint1: new CGPoint(x: scaledRect.X + (scaledRect.Size.Width / 2), y: scaledRect.Y + (scaledRect.Size.Height * 3 / 4)),
controlPoint2: new CGPoint(x: scaledRect.X, y: scaledRect.Y + (scaledRect.Size.Height / 2)));
path.AddArc(new CGPoint(scaledRect.X + (scaledRect.Size.Width / 4), scaledRect.Y + (scaledRect.Size.Height / 4)),
(scaledRect.Size.Width / 4),
(nfloat)Math.PI,
0,
true);
path.AddArc(new CGPoint(scaledRect.X + (scaledRect.Size.Width * 3 / 4), scaledRect.Y + (scaledRect.Size.Height / 4)),
(scaledRect.Size.Width / 4),
(nfloat)Math.PI,
0,
true);
path.AddCurveToPoint(new CGPoint(x: originalRect.Size.Width / 2, y: scaledRect.Y + scaledRect.Size.Height),
controlPoint1: new CGPoint(x: scaledRect.X + scaledRect.Size.Width, y: scaledRect.Y + (scaledRect.Size.Height / 2)),
controlPoint2: new CGPoint(x: scaledRect.X + (scaledRect.Size.Width / 2), y: scaledRect.Y + (scaledRect.Size.Height * 3 / 4)));
path.ClosePath();
return path;
}
UIBezierPath GetCircularOverlayPath()
{
int radius = (int)(Bounds.Width / 2) - 20;
UIBezierPath circlePath = UIBezierPath.FromRoundedRect(new CGRect(Bounds.GetMidX() - radius, Bounds.GetMidY() - radius, 2.0 * radius, 2.0 * radius), radius);
circlePath.ClosePath();
return circlePath;
}
public void AddOverlayLayer()
{
UIBezierPath path = UIBezierPath.FromRoundedRect(new CGRect(Frame.X, Frame.Y, this.Frame.Width, this.Frame.Height), 0);
path.AppendPath(OverlayShape == OverlayShape.Circle ? GetCircularOverlayPath() : GetHeartOverlayPath(path.Bounds, 0.95f));
path.UsesEvenOddFillRule = true;
CAShapeLayer fillLayer = new CAShapeLayer();
fillLayer.Path = path.CGPath;
fillLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
fillLayer.FillColor = OverlayBackgroundColor.CGColor;
fillLayer.Opacity = Opacity;
overlayLayer = fillLayer;
Layer.AddSublayer(fillLayer);
}
public void UpdatePath()
{
UIBezierPath path = UIBezierPath.FromRoundedRect(new CGRect(Frame.X, Frame.Y, this.Frame.Width, this.Frame.Height), 0);
path.AppendPath(OverlayShape == OverlayShape.Circle ? GetCircularOverlayPath() : GetHeartOverlayPath(path.Bounds, 0.95f));
overlayLayer.Path = path.CGPath;
}
public void UpdateOpacity()
{
if(overlayLayer!=null)
overlayLayer.Opacity = Opacity;
}
public void UpdateFillColor()
{
if (overlayLayer != null)
overlayLayer.FillColor = OverlayBackgroundColor.CGColor;
}
public void RemoveOverlayLayer()
{
//if(Layer.Sublayers!=null)
//foreach (var l in Layer.Sublayers)
//{
// l.RemoveFromSuperLayer();
//}
overlayLayer?.RemoveFromSuperLayer();
}
}
}
I have a question about the math involved to copy a path.
Let's say I have this path:
http://imgur.com/a/42l0t
I want an exact copy of this path besides the black one. I wrote a small C# program that calculates the angle between two points. Depending on the angle, an offset to the X or Y value is added.
It kind of works, this is the result:
http://imgur.com/bJQDCgq
As you can see, it's not that pretty.
Now, my real question is: What is the proper math to use for this?
Hopefully someone knwos an answer, because I'm kinda stuck on this one.
Regards,
Sascha
Code:
void Plot(List<Point> points)
{
Graphics g = pictureBox.CreateGraphics();
g.Clear(Color.White);
for (int i = 0; i < points.Count - 1; i++)
{
g.DrawLine(Pens.Black, points[i], points[i + 1]);
}
List<Point> points2 = new List<Point>();
for (int i = 0; i < points.Count - 1; i++)
{
var angle = getAngleFromPoint(points[i], points[i + 1]);
Debug.WriteLine(angle);
if (angle < 180 && angle >= 135)
{
points2.Add(new Point(points[i].X - OFFSET, points[i].Y));
}
if (angle < 135 && angle >= 90)
{
if (points[i].Y < points[i + 1].Y)
{
points2.Add(new Point(points[i].X - OFFSET / 2, points[i].Y + OFFSET));
}
else
{
}
}
if (angle < 90 && angle >= 45)
{
if (points[i].Y < points[i + 1].Y)
{
points2.Add(new Point(points[i].X - OFFSET, points[i].Y));
}
else
{
points2.Add(new Point(points[i].X + OFFSET, points[i].Y));
}
}
if (angle < 45 && angle >= 0)
{
if (points[i].Y < points[i + 1].Y)
{
points2.Add(new Point(points[i].X - OFFSET, points[i].Y));
}
else
{
points2.Add(new Point(points[i].X + OFFSET, points[i].Y));
}
}
if (angle < 360 && angle >= 315)
{
if (points[i].Y < points[i + 1].Y)
{
points2.Add(new Point(points[i].X + OFFSET, points[i].Y));
}
else
{
points2.Add(new Point(points[i].X + 10, points[i].Y - OFFSET));
}
}
if (angle < 315 && angle >= 270)
{
points2.Add(new Point(points[i].X, points[i].Y - OFFSET));
}
if (angle < 270 && angle >= 225)
{
if (points[i].Y < points[i + 1].Y)
{
points2.Add(new Point(points[i].X - OFFSET / 2, points[i].Y - OFFSET));
}
else
{
}
}
if (angle < 225 && angle >= 180)
{
if (points[i].X < points[i + 1].X)
{
points2.Add(new Point(points[i].X, points[i].Y - OFFSET));
}
else
{
if (points[i].Y < points[i + 1].Y) // \
{
points2.Add(new Point(points[i].X - OFFSET, points[i].Y));
}
else
{
}
}
}
}
for (int i = 0; i < points2.Count - 1; i++)
{
g.DrawLine(Pens.Red, points2[i], points2[i + 1]);
}
}
I think if i decrease the angles (from 45 degree steps to maybe 30 degrees) I could imnprove the result, but there must be a better solution.
I suppose one way to tackle this is to split it into line-pairs (ie: three points)
Find the parallel line (at distance d) for each line in the pair. Then find where these parallel lines intersect to give you the location of a point on the new line.
In very rough psuedo-code:
points a, b, c
distance d
lineab = findLineParallelTo(line(a,b), d)
linebc = findLineParallelTo(line(b,c), d)
return intersect(lineab, linebc)
I implemented the solution from #Jack and it works great:
public class Line
{
public PointF P { get; private set; }
public PointF Q { get; private set; }
public float Pitch
{
get; private set;
}
public Line()
{
}
public Line(float px, float py, float qx, float qy) : this(new PointF(px, py), new PointF(qx, qy))
{
}
public Line(PointF p, PointF q)
{
P = p;
Q = q;
}
#region Methods
/// <summary>
/// http://stackoverflow.com/questions/2825412/draw-a-parallel-line
/// </summary>
public Line FindParallelLine(float distance)
{
float length = (float)Math.Sqrt((P.X - Q.X) * (P.X - Q.X) + (P.Y - Q.Y) * (P.Y - Q.Y));
// This is the second line
float px = P.X + distance * (Q.Y - P.Y) / length;
float qx = Q.X + distance * (Q.Y - P.Y) / length;
float py = P.Y + distance * (P.X - Q.X) / length;
float qy = Q.Y + distance * (P.X - Q.X) / length;
return new Line(px, py, qx, qy);
}
public override string ToString()
{
return string.Format("P({0}|{1}), Q({2}|{3}) - Pitch: {4}", P.X, P.Y, Q.X, Q.Y, Pitch);
}
#endregion
}
private PointF FindIntersection(Line a, Line b)
{
PointF A = a.P;
PointF B = a.Q;
PointF C = b.P;
PointF D = b.Q;
float dy1 = B.Y - A.Y;
float dx1 = B.X - A.X;
float dy2 = D.Y - C.Y;
float dx2 = D.X - C.X;
// Check whether the two line parallel.
if (dy1 * dx2 == dy2 * dx1)
{
return PointF.Empty;
}
else
{
float x = ((C.Y - A.Y) * dx1 * dx2 + dy1 * dx2 * A.X - dy2 * dx1 * C.X) / (dy1 * dx2 - dy2 * dx1);
float y = A.Y + (dy1 / dx1) * (x - A.X);
return new PointF(x, y);
}
}
private PointF FindIntersection(PointF a, PointF b, PointF c, float distance)
{
Line line1 = new Line(a, b);
Line line2 = new Line(b, c);
Line parallel = line1.FindParallelLine(distance);
Line parallel2 = line2.FindParallelLine(distance);
return FindIntersection(parallel, parallel2);
}
private List<PointF> FindIntersections(PointF[] points, float distance)
{
List<PointF> intersections = new List<PointF>();
for (int i = 0; i < points.Length - 2; i++)
{
PointF intersection = FindIntersection(points[i], points[i + 1], points[i + 2], distance);
if (!intersection.IsEmpty && !double.IsNaN(intersection.X) && !double.IsNaN(intersection.Y))
{
intersections.Add(intersection);
}
}
return intersections;
}
private PointF GetFirstPoint(PointF[] points, float distance)
{
Line parallel = new Line(points[0], points[1]).FindParallelLine(distance);
return parallel.P;
}
private PointF GetLastPoint(PointF[] points, float distance)
{
Line parallel = new Line(points[points.Length - 2], points[points.Length - 1]).FindParallelLine(distance);
return parallel.Q;
}
Example call:
OFFSET = float.Parse(textBox1.Text);
List<PointF> points = new List<PointF>();
points.Add(new PointF(200, 180));
points.Add(new PointF(160, 160));
points.Add(new PointF(100, 160));
points.Add(new PointF(60, 140));
points.Add(new PointF(40, 100));
points.Add(new PointF(80, 60));
points.Add(new PointF(140, 100));
points.Add(new PointF(180, 140));
points.Add(new PointF(220, 80));
List<PointF> intersections = FindIntersections(points.ToArray(), OFFSET);
intersections.Insert(0, GetFirstPoint(points.ToArray(), OFFSET));
intersections.Add(GetLastPoint(points.ToArray(), OFFSET));
Graphics g = pictureBox.CreateGraphics();
g.Clear(Color.White);
g.DrawLines(Pens.Black, points.ToArray());
// Connect the intersection points.
g.DrawLines(Pens.Red, intersections.ToArray());
Example image:
http://imgur.com/onUstGT
Thanks again #Jack !
I'm having problems with sending data from Arduino to Processing. I can receive the data OK in the draw loop, but it was very slow, so I included a serialEvent() function to try and eliminate some of the lagginess, but now it doesn't seem to be reading the data in the serialEvent function, and I can't figure out why!
import themidibus.*;
import processing.serial.*;
int end = 10;
String serial;
Serial port;
MidiBus myBus;
// Incoming data
int c;
int d;
int e;
int f;
int g;
int a;
int b;
int C;
int pitchPot;
int tonalityPot;
int noteVol;
int pan;
int reverb;
int dlay;
int distort;
int octave;
// Ellipse parameters
int noteOn = 0;
int col1 = 0;
int col2 = 0;
int col3 = 0;
int passTime;
int saveTime;
int expand = 0;
String[] A = new String[18];
String[] B = new String[18];
boolean cPress = false;
boolean dPress = false;
boolean ePress = false;
boolean fPress = false;
boolean gPress = false;
boolean aPress = false;
boolean bPress = false;
boolean CPress = false;
void setup() {
size(600, 600, P3D);
frameRate(10);
smooth();
port = new Serial(this, Serial.list()[6], 115200);
port.clear();
serial = port.readStringUntil(end);
serial = null; // Initially, the string will be null (empty)
myBus = new MidiBus(this, -1, "Java Sound Synthesizer");
}
void draw() {
if ((c == 1) && (cPress == false)) {
col1 = 255;
col2 = 0;
col3 = 0;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (60 + pitchPot + octave), noteVol);
cPress = true;
}
if ((c == 0) && (cPress == true)) {
myBus.sendNoteOff(1, (60 + pitchPot + octave), noteVol);
cPress = false;
}
// D
if ((d == 1) && (dPress == false)) {
col1 = 0;
col2 = 0;
col3 = 255;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (62 + pitchPot + octave), noteVol);
dPress = true;
}
if ((d == 0) && (dPress == true)) {
myBus.sendNoteOff(1, (62 + pitchPot + octave), noteVol);
dPress = false;
}
if ((e == 1) && (ePress == false)){
col1 = 0;
col2 = 255;
col3 = 0;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (64 + pitchPot + tonalityPot + octave), noteVol);
ePress = true;
}
if ((e == 0) && (ePress == true)){
myBus.sendNoteOff(1, (64 + pitchPot + tonalityPot + octave), noteVol);
ePress = false;
}
if ((f == 1) && (fPress == false)) {
col1 = 255;
col2 = 0;
col3 = 255;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (65 + pitchPot + octave), noteVol);
fPress = true;
}
if ((f == 0) && (fPress == true)) {
myBus.sendNoteOff(1, (65 + pitchPot + octave), noteVol);
fPress = false;
}
if ((g == 1) && (gPress == false)) {
col1 = 255;
col2 = 255;
col3 = 0;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (67 + pitchPot + octave), noteVol);
gPress = true;
}
if ((g == 0) && (gPress == true)) {
myBus.sendNoteOff(1, (67 + pitchPot + octave), noteVol);
gPress = false;
}
if ((a == 1) && (aPress == false)) {
col1 = 0;
col2 = 255;
col3 = 255;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (69 + pitchPot + tonalityPot + octave), noteVol);
aPress = true;
}
if ((a == 0) && (aPress == true)) {
myBus.sendNoteOff(1, (69 + pitchPot + tonalityPot + octave), noteVol);
aPress = false;
}
if ((b == 1) && (bPress == false)) {
col1 = 50;
col2 = 250;
col3 = 130;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (71 + pitchPot + octave), noteVol);
bPress = true;
}
if ((b == 0) && (bPress == true)) {
myBus.sendNoteOff(1, (71 + pitchPot + octave), noteVol);
bPress = false;
}
if ((C == 1) && (CPress == false)) {
col1 = 200;
col2 = 90;
col3 = 75;
myBus.sendControllerChange(1, 10, pan);
myBus.sendNoteOn(1, (72 + pitchPot + octave), noteVol);
CPress = true;
}
if ((C == 0) && (CPress == true)) {
myBus.sendNoteOff(1, (72 + pitchPot + octave), noteVol);
CPress = false;
}
if(c == 1 || d == 1 || e == 1 || f == 1 ||
g == 1 || a == 1 || b == 1 || C == 1) {
noteOn = 1;
}
else {
noteOn = 0;
}
if (dlay == 1) {
if (noteOn == 1) {
passTime = millis() - saveTime;
if (passTime > 1) {
expand += 15;
saveTime = millis();
}
strokeWeight(10);
stroke(col1, col2, col3);
noFill();
ellipse((300+pan), 300 , expand, expand);
}
else {
expand = noteVol*2;
noteOn = 0;
}
fill(0, 0, 0, 100);
rect(0, 0, 600, 600);
fill(col1, col2, col3);
lights();
pushMatrix();
translate(300+pan, 300);
noStroke();
sphere(noteOn*noteVol);
popMatrix();
}
else if (reverb == 1) {
fill(0, 0, 0, 100);
rect(0, 0, 600, 600);
fill(col1, col2, col3);
lights();
pushMatrix();
translate(300, 300);
rotate(frameCount / 50.0);
star(0, 0, (noteOn*noteVol* 20), ((noteOn*noteVol)/20), 40);
popMatrix();
}
else {
fill(0, 0, 0, 100);
rect(0,0, 600,600);
fill(col1,col2, col3);
lights();
pushMatrix();
translate(300+pan, 300);
noStroke();
sphere(noteOn*noteVol);
popMatrix();
}
}
void serialEvent(Serial port) {
while (port.available() > 0) {
serial = port.readStringUntil(end);
}
if (serial != null) {
A = split(serial, ',');
B = trim(A);
c = Integer.parseInt(B[1]);
d = Integer.parseInt(B[1]);
e = Integer.parseInt(B[2]);
f = Integer.parseInt(B[3]);
g = Integer.parseInt(B[4]);
a = Integer.parseInt(B[5]);
b = Integer.parseInt(B[6]);
C = Integer.parseInt(B[7]);
pitchPot = Integer.parseInt(B[9]);
tonalityPot = Integer.parseInt(B[10]);
noteVol = Integer.parseInt(B[11]);
pan = Integer.parseInt(B[12]);
dlay = Integer.parseInt(B[13]);
reverb = Integer.parseInt(B[14]);
distort = Integer.parseInt(B[15]);
octave = Integer.parseInt(B[16]);
}
}
serialEvent() does not seem to called by a serial event like the documentation says, at least on the Arduino platforms I am using. It may work on some. If it doesn't work, try just calling serialEvent in your main loop. I think that is equivalent anyway as there really are not interrupts for serial data. You just have to read it and the idea was that the serialEvent function would be called every loop but it doesn't seem to work that way.
The SerialEvent Arduino documentation says:
"NB : Currently, serialEvent() is not compatible with the Esplora, Leonardo, or Micro", but I suspect the list should be longer.
I am writing a small program in Processing to display the values of a speed trap and elapsed time(like a drag strip, but for a waterslide for Australia Day) coming from a microcontroller over serial.
I have had the Processing sketch running and have done most of the development with just a mouse click to imitate new data and run the program, I also have set up the hardware and had it running with the microcontroller sending the serial data and the program displaying it.
I have done some further development, and now when it runs I am getting some strange things happening, boxes sometimes come through in the wrong color, some artifacts in the displayed numbers, and a lot of wrong colors for only some of the graph(the graph is made with a for loop and the color is set outside of it).
I have tried adding in some delays to make sure its getting a full string of data and I have also tried moving around the sub routines but nothing works.
The faults only appeared after I added in the elapsed time code to the serial data, before it was just one string, now it is two numbers separated by a colon.
I have put my code in here as well, its pretty straight forward, I am only new to programming, please excuse(and point out!) any errors.
import processing.serial.*;
Serial myPort;
float inString;
float inFloat0, inFloat1;
float[] list = new float[0];
float[] etlist = new float[0];
PFont f1, f2, f3, f4, f5, f6;
int index;
float rank;
float percentage;
int trapDistance = 1000;
int SgraphH = 38; //Speed graph scale
int ETgraphH = 15; //ET graph scale
int valueX = 0;
int valueY = 0;
boolean graph30 = false, graph690 = false;
color c1, c2, c3 = color(220, 0, 0), c4 = color(220, 0, 0);
int boxX = 295, boxY = 430, boxSize = 15; //Graph 30 box
void setup () {
size(1280, 700);
index = 0;
//Load list from textfile
String loadlist[] = loadStrings("list.txt");
for (int i = 0; i < loadlist.length; i++) {
String[] split = split(loadlist[i], ',');
list = append(list, float(split[0]));
etlist = append(etlist, float(split[1]));
index++;
}
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
//Create fonts
f1 = createFont("Arial Unicode MS", 20);
f2 = createFont("Arial Unicode MS", 240);
f3 = createFont("Arial Unicode MS", 35);
f4 = createFont("Arial Unicode MS", 15);
f5 = createFont("Arial Unicode MS", 15);
f6 = createFont("Arial Unicode MS", 12);
}
void draw () {
stroke(225);
fill(225);
rectMode(CORNER);
rect(0, 0, 500, 20);
fill(0);
text(mouseX, 20, 20);
text(mouseY, 50, 20);
text(mouseX - valueX, 80, 20);
text(mouseY - valueY, 110, 20);
}
void mousePressed() {
//Check if Mouse is over button and toggle Graph on
if (mouseX > boxX && mouseX < boxX+boxSize && mouseY >boxY && mouseY < boxY+boxSize) {
if (graph30) {
graph30 = false;
c3 = color(220, 0, 0);
}
else {
graph30 = true;
c3 = color(0, 220, 0);
}
create();
graphCheck();
graph();
}
//Check if Mouse is over button and toggle Graph on
if (mouseX > boxX+100 && mouseX < boxX+100+boxSize && mouseY >boxY && mouseY < boxY+boxSize) {
if (graph690) {
graph690 = false;
c4 = color(220, 0, 0);
}
else {
graph690 = true;
c4 = color(0, 220, 0);
}
create();
graphCheck();
graph();
}
}
void serialEvent (Serial myPort) {
delay(100);
String inString = myPort.readStringUntil('\n');
delay(100);
if (inString != null) {
inString = trim(inString);
String[] split = split(inString, ',');
inFloat0 = float(split[0]);
inFloat1 = float(split[1]);
index++;
float speed = trapDistance / inFloat0 * 3.6;
list = append(list, speed);
float et = inFloat1;
etlist = append(etlist, et);
//Clear screen
background(225);
//Run sub routines
create();
graphCheck();
graph();
}
}
void delay(int delay)
{
int time = millis();
while(millis() - time <= delay);
}
void create() {
//Clear screen
background(225);
//Sorting
float[] sortlist = new float[index+1];
sortlist = sort(list);
float[] sortetlist = new float[index+1];
sortetlist = sort(etlist);
//Calculate rank
int pos = 1;
while (list[index-1] > sortlist[pos - 1]) {
pos++;
}
if (pos == 1) {
rank = 0;
}
else {
rank = (pos / float(sortlist.length));
}
//Calculate Percentage of Speed
percentage = list[index-1] / sortlist[sortlist.length -1];
//Speed colour for fastest and slowest
if (index != 0) {
if (list[index-1] < sortlist[1]) {
c1 = color(240, 0, 0);
}
else if (list[index-1] > sortlist[index-1]) {
c1 = color(0, 240, 0);
}
else {
c1 = color(255);
}
}
else {
c1 = color(255);
}
//ET colour for fastest and slowest
if (index != 0) {
if (etlist[index-1] < sortetlist[1]) {
c2 = color(240, 0, 0);
}
else if (etlist[index-1] > sortetlist[index-1]) {
c2 = color(0, 240, 0);
}
else {
c2 = color(255);
}
}
else {
c2 = color(255);
}
//Boxes
rectMode(CORNER);
stroke(0);
fill(c1);
rect(15, 15, width-30, 200); //Speed
fill(c2);
rect(15, 230, width-30, 200); //ET
fill(255);
rect(15, height - 255, 125, 240); //Left
rect(155, height -255, 125, 240); //Left
rect(width - 140, height - 255, 125, 240); //Right
rect(width - 280, height - 255, 125, 240); //Right
//Text
fill(0);
textFont(f3);
textAlign(CENTER);
text("Speed", 78, height - 220);
text("ET", width - 78, height - 220);
text("ET", 218, height - 220);
text("Speed", width - 218, height - 220);
textFont(f4);
textAlign(LEFT);
text("Trap Distance: " + trapDistance + "mm", 2, height - 2);
//Big Numbers
textAlign(CENTER);
textFont(f2);
text(String.format("%.2f", list[index-1])+"km/h", width/2, 200); //Speed
text(String.format("%.2f", etlist[index-1])+"sec", width/2, 415); //ET
//Last 10
for (int i = 0; i <= index-1 && i < 10; i++) {
textAlign(LEFT);
textFont(f5);
text((index-1 - i + 1)+". "+String.format("%.3f", list[index-1 - i])+"km/h", 23, (height - 200 + (i * 20)));
}
//Last 10 ET
for (int i = 0; i <= index-1 && i < 10; i++) {
textAlign(LEFT);
textFont(f5);
text((index-1 - i + 1)+". "+String.format("%.3f", etlist[index-1 - i])+"sec", 163, (height - 200 + (i * 20)));
}
//Fastest
for (int i = 0; i <= index-1 && i < 10; i++) {
textAlign(CENTER);
textFont(f5);
text((i+1)+". "+String.format("%.3f", sortlist[sortlist.length - (i+1)])+"km/h", width - 220, (height - 200 + (i * 20)));
}
//Fastest ET
for (int i = 0; i <= index-1 && i < 10; i++) {
textAlign(CENTER);
textFont(f5);
text((i+1)+". "+String.format("%.3f", sortetlist[i])+"sec", width - 80, (height - 200 + (i * 20)));
}
//Create string for saving to text file
String[] listString = new String[index-1+1];
for (int i = 0; i < index-1+1; i++) {
listString[i] = (Float.toString(list[i]) + ',' + Float.toString(etlist[i]));
}
//Save to text file
saveStrings("list.txt", listString);
//Graph with curves
// beginShape();
// stroke(125, 125, 255);
// for (int i = 1; i <= index && i < 34; i++) {
// float y = map(list[index - (i - 1)], 0, SgraphH, 150, 0);
// curveVertex((width + 25 - (i * 25)), 25 + y);
// }
// endShape();
}
void graph() {
//Create graph area
fill(255);
rectMode(CENTER);
rect(width/2, height - 135, 690, 240);
stroke(192);
for (int i = 1; i < 30.; i++) {
line((((width - 690)/2) + (i * (690/30))), 446, ((((width - 690)/2) + (i * (690/30)))), 684);
}
for (int i = 1; i < 10; i++) {
line(((width - 690)/2)+1, (445 + (i * 24)), (width - (width - 690)/2)-1, (445 + (i * 24)));
}
//Graph last 690
if (graph690) {
stroke(0, 170, 0);
for (int i = 1; i <= index-1 && i < 690; i++) {
float start = map(list[index-1 - (i - 1)], 0, SgraphH, 240, 0);
float end = map(list[index-1 - i], 0, SgraphH, 240, 0);
line(((width - (width - 690)/2) + 1 - (i)), 445 + start, ((width- (width - 690)/2) + 1 - ((i + 1))), 445 + end);
}
}
//Graph last 690
if (graph690) {
stroke(120, 0, 120);
for (int i = 1; i <= index-1 && i < 690; i++) {
float start = map(etlist[index-1 - (i - 1)], 0, ETgraphH, 240, 0);
float end = map(etlist[index-1 - i], 0, ETgraphH, 240, 0);
line(((width - (width - 690)/2) + 1 - (i)), 445 + start, ((width- (width - 690)/2) + 1 - ((i + 1))), 445 + end);
}
}
//Graph last 30 speeds
if (graph30) {
stroke(0, 0, 240);
for (int i = 1; i <= index-1 && i < 31; i++) {
float start = map(list[index-1 - (i - 1)], 0, SgraphH, 240, 0);
float end = map(list[index-1 - i], 0, SgraphH, 240, 0);
line(((width - (width - 690)/2) + 23 - (i * 23)), 445 + start, ((width- (width - 690)/2) + 23 - ((i + 1) * 23)), 445 + end);
}
}
//Graph last 30 ETs
if (graph30) {
stroke(240, 0, 0);
for (int i = 1; i <= index-1 && i < 31; i++) {
float start = map(etlist[index-1 - (i - 1)], 0, ETgraphH, 240, 0);
float end = map(etlist[index-1 - i], 0, ETgraphH, 240, 0);
line(((width - (width - 690)/2) + 23 - (i * 23)), 445 + start, ((width- (width - 690)/2) + 23 - ((i + 1) * 23)), 445 + end);
}
}
fill(0);
textAlign(LEFT);
text("0", width / 2 - 345, height - 15);
text(SgraphH, width / 2 - 345, height - 243);
}
void graphCheck() {
//Draw box and text for graph selection
rectMode(CORNER);
textFont(f6);
textAlign(LEFT);
stroke(0);
fill(0);
text("Graph last 30", boxX+20, boxY+13);
fill(c3);
rect(boxX, boxY, boxSize, boxSize);
stroke(0);
fill(0);
text("Graph last 690", boxX+120, boxY+13);
fill(c4);
rect(boxX+100, boxY, boxSize, boxSize);
}
void keyPressed() {
valueX = mouseX;
valueY = mouseY;
}
Also, when triggered from a mouse click (turning on the graph's) it works fine.
Cheers,
Matt
I fixed it.
When the subroutines were being called by the serial trigger, it some how still allowed the looped code in the draw() function to still run, which was causing the issues.
I just put noLoop() and loop() in before and after the calls for the subroutines.
All good now.
I'm having a dilemma with this code and have no clue what to do. I'm pretty new to processing. This is a project from this link...
http://blog.makezine.com/2012/08/10/build-a-touchless-3d-tracking-interface-with-everyday-materials/
any help is massively appreciated... Thanks in advance
import processing.serial.*;
import processing.opengl.*;
Serial serial;
int serialPort = 1;
int sen = 3; // sensors
int div = 3; // board sub divisions
Normalize n[] = new Normalize[sen];
MomentumAverage cama[] = new MomentumAverage[sen];
MomentumAverage axyz[] = new MomentumAverage[sen];
float[] nxyz = new float[sen];
int[] ixyz = new int[sen];
float w = 256; // board size
boolean[] flip = {
false, true, false};
int player = 0;
boolean moves[][][][];
PFont font;
void setup() {
size(800, 600, P3D);
frameRate(25);
font = loadFont("TrebuchetMS-Italic-20.vlw");
textFont(font);
textMode(SCREEN);
println(Serial.list());
serial = new Serial(this, Serial.list()[serialPort], 115200);
for(int i = 0; i < sen; i++) {
n[i] = new Normalize();
cama[i] = new MomentumAverage(.01);
axyz[i] = new MomentumAverage(.15);
}
reset();
}
void draw() {
updateSerial();
drawBoard();
}
void updateSerial() {
String cur = serial.readStringUntil('\n');
if(cur != null) {
String[] parts = split(cur, " ");
if(parts.length == sensors) {
float[] xyz = new float[sen];
for(int i = 0; i < sen; i++)
xyz[i] = float(parts[i]);
if(mousePressed && mouseButton == LEFT)
for(int i = 0; i < sen; i++)
n[i].note(xyz[i]);
nxyz = new float[sen];
for(int i = 0; i < sen; i++) {
float raw = n[i].choose(xyz[i]);
nxyz[i] = flip[i] ? 1 - raw : raw;
cama[i].note(nxyz[i]);
axyz[i].note(nxyz[i]);
ixyz[i] = getPosition(axyz[i].avg);
}
}
}
}
float cutoff = .2;
int getPosition(float x) {
if(div == 3) {
if(x < cutoff)
return 0;
if(x < 1 - cutoff)
return 1;
else
return 2;
}
else {
return x == 1 ? div - 1 : (int) x * div;
}
}
void drawBoard() {
background(255);
float h = w / 2;
camera(
h + (cama[0].avg - cama[2].avg) * h,
h + (cama[1].avg - 1) * height / 2,
w * 2,
h, h, h,
0, 1, 0);
pushMatrix();
noStroke();
fill(0, 40);
translate(w/2, w/2, w/2);
rotateY(-HALF_PI/2);
box(w);
popMatrix();
float sw = w / div;
translate(h, sw / 2, 0);
rotateY(-HALF_PI/2);
pushMatrix();
float sd = sw * (div - 1);
translate(
axyz[0].avg * sd,
axyz[1].avg * sd,
axyz[2].avg * sd);
fill(255, 160, 0);
noStroke();
sphere(18);
popMatrix();
for(int z = 0; z < div; z++) {
for(int y = 0; y < div; y++) {
for(int x = 0; x < div; x++) {
pushMatrix();
translate(x * sw, y * sw, z * sw);
noStroke();
if(moves[0][x][y][z])
fill(255, 0, 0, 200);
else if(moves[1][x][y][z])
fill(0, 0, 255, 200);
else if(
x == ixyz[0] &&
y == ixyz[1] &&
z == ixyz[2])
if(player == 0)
fill(255, 0, 0, 200);
else
fill(0, 0, 255, 200);
else
fill(0, 100);
box(sw / 3);
popMatrix();
}
}
}
fill(0);
if(mousePressed && mouseButton == LEFT)
msg("defining boundaries");
}
void keyPressed() {
if(key == TAB) {
moves[player][ixyz[0]][ixyz[1]][ixyz[2]] = true;
player = player == 0 ? 1 : 0;
}
}
void mousePressed() {
if(mouseButton == RIGHT)
reset();
}
void reset() {
moves = new boolean[2][div][div][div];
for(int i = 0; i < sen; i++) {
n[i].reset();
cama[i].reset();
axyz[i].reset();
}
}
void msg(String msg) {
text(msg, 10, height - 10);
}
You are missing a class, in fact, more than one. Go back to the github and download, or copy and paste, all three codes, placing each one in a new tab named same name of the class (well this is not required, but is a good practice). The TicTacToe3D.pde is the main code. To make a new tab choose "new tab" from the arrow menu in Processing IDE (just below the standard button at the right). The code should run. WIll need an Arduino though to really get it working.