Browse Source

BLOCKS: Added topological position and rotation information to the Block class

tags/2021-05-28
jules 7 years ago
parent
commit
a210d0bc4f
2 changed files with 155 additions and 0 deletions
  1. +11
    -0
      modules/juce_blocks_basics/blocks/juce_Block.h
  2. +144
    -0
      modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp

+ 11
- 0
modules/juce_blocks_basics/blocks/juce_Block.h View File

@@ -108,6 +108,9 @@ public:
*/ */
virtual bool isMasterBlock() const = 0; virtual bool isMasterBlock() const = 0;
/** Returns the UID of the master block this block is connected to. */
virtual UID getConnectedMasterUID() const = 0;
//============================================================================== //==============================================================================
/** Returns the width of the device in logical device units. */ /** Returns the width of the device in logical device units. */
virtual int getWidth() const = 0; virtual int getWidth() const = 0;
@@ -121,6 +124,14 @@ public:
/** Returns the length of one logical device unit as physical millimeters. */ /** Returns the length of one logical device unit as physical millimeters. */
virtual float getMillimetersPerUnit() const = 0; virtual float getMillimetersPerUnit() const = 0;
/** Returns the area that this block covers within the layout of the group as a whole.
The coordinates are in logical block units, and are relative to the origin, which is the master block's top-left corner.
*/
virtual Rectangle<int> getBlockAreaWithinLayout() const = 0;
/** Returns the rotation of this block relative to the master block in 90 degree steps clockwise. */
virtual int getRotation() const = 0;
//============================================================================== //==============================================================================
/** If this block has a grid of LEDs, this will return an object to control it. /** If this block has a grid of LEDs, this will return an object to control it.
Note that the pointer that is returned belongs to this object, and the caller must Note that the pointer that is returned belongs to this object, and the caller must


+ 144
- 0
modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp View File

@@ -1275,6 +1275,9 @@ struct PhysicalTopologySource::Internal
{ {
lastTopology = detector->currentTopology; lastTopology = detector->currentTopology;
BlocksTraverser traverser;
traverser.traverseBlockArray (detector->currentTopology);
for (auto* d : detector->activeTopologySources) for (auto* d : detector->activeTopologySources)
d->listeners.call ([] (TopologySource::Listener& l) { l.topologyChanged(); }); d->listeners.call ([] (TopologySource::Listener& l) { l.topologyChanged(); });
@@ -1295,6 +1298,131 @@ struct PhysicalTopologySource::Internal
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Detector) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Detector)
}; };
//==============================================================================
/** This is a friend of the BlocksImplementation that will scan and set the
physical positions of the blocks */
struct BlocksTraverser
{
void traverseBlockArray (const BlockTopology& topology)
{
juce::Array<Block::UID> visited;
for (auto& block : topology.blocks)
{
if (block->isMasterBlock() && ! visited.contains (block->uid))
{
if (auto* bi = dynamic_cast<BlockImplementation*> (block))
{
bi->masterUID = {};
bi->position = {};
bi->rotation = 0;
}
layoutNeighbours (block, topology, block->uid, visited);
}
}
}
Block::Ptr findBlockWithUid (const BlockTopology& topology, Block::UID uid)
{
for (auto& block : topology.blocks)
if (block->uid == uid)
return block;
return {};
}
// returns the distance from corner clockwise
int getUnitForIndex (Block::Ptr block, Block::ConnectionPort::DeviceEdge edge, int index)
{
if (block->getType() == Block::seaboardBlock)
{
if (edge == Block::ConnectionPort::DeviceEdge::north)
{
if (index == 0) return 1;
if (index == 1) return 4;
}
else if (edge == Block::ConnectionPort::DeviceEdge::east
|| edge == Block::ConnectionPort::DeviceEdge::west)
{
return 1;
}
}
if (edge == Block::ConnectionPort::DeviceEdge::south)
return block->getWidth() - (index + 1);
if (edge == Block::ConnectionPort::DeviceEdge::west)
return block->getHeight() - (index + 1);
return index;
}
// returns how often north needs to rotate by 90 degrees
int getRotationForEdge (Block::ConnectionPort::DeviceEdge edge)
{
switch (edge)
{
case Block::ConnectionPort::DeviceEdge::north: return 0;
case Block::ConnectionPort::DeviceEdge::east: return 1;
case Block::ConnectionPort::DeviceEdge::south: return 2;
case Block::ConnectionPort::DeviceEdge::west: return 3;
}
}
void layoutNeighbours (Block::Ptr block, const BlockTopology& topology,
Block::UID masterUid, juce::Array<Block::UID>& visited)
{
visited.add (block->uid);
for (auto& connection : topology.connections)
{
if ((connection.device1 == block->uid && ! visited.contains (connection.device2))
|| (connection.device2 == block->uid && ! visited.contains (connection.device1)))
{
const auto theirUid = connection.device1 == block->uid ? connection.device2 : connection.device1;
const auto neighbourPtr = findBlockWithUid (topology, theirUid);
if (auto* neighbour = dynamic_cast<BlockImplementation*> (neighbourPtr.get()))
{
const auto myBounds = block->getBlockAreaWithinLayout();
const auto& myPort = connection.device1 == block->uid ? connection.connectionPortOnDevice1 : connection.connectionPortOnDevice2;
const auto& theirPort = connection.device1 == block->uid ? connection.connectionPortOnDevice2 : connection.connectionPortOnDevice1;
const auto myOffset = getUnitForIndex (block, myPort.edge, myPort.index);
const auto theirOffset = getUnitForIndex (neighbourPtr, theirPort.edge, theirPort.index);
neighbour->rotation = (2 + block->getRotation()
+ getRotationForEdge (myPort.edge)
- getRotationForEdge (theirPort.edge)) % 4;
Point<int> delta;
const auto theirBounds = neighbour->getBlockAreaWithinLayout();
switch ((block->getRotation() + getRotationForEdge (myPort.edge)) % 4)
{
case 0: // over me
delta = { myOffset - (theirBounds.getWidth() - (theirOffset + 1)), -theirBounds.getHeight() };
break;
case 1: // right of me
delta = { myBounds.getWidth(), myOffset - (theirBounds.getHeight() - (theirOffset + 1)) };
break;
case 2: // under me
delta = { (myBounds.getWidth() - (myOffset + 1)) - theirOffset, myBounds.getHeight() };
break;
case 3: // left of me
delta = { -theirBounds.getWidth(), (myBounds.getHeight() - (myOffset + 1)) - theirOffset };
break;
}
neighbour->position = myBounds.getPosition() + delta;
}
layoutNeighbours (neighbourPtr, topology, masterUid, visited);
}
}
}
};
//============================================================================== //==============================================================================
struct BlockImplementation : public Block, struct BlockImplementation : public Block,
private MIDIDeviceConnection::Listener, private MIDIDeviceConnection::Listener,
@@ -1315,6 +1443,7 @@ struct PhysicalTopologySource::Internal
touchSurface.reset (new TouchSurfaceImplementation (*this)); touchSurface.reset (new TouchSurfaceImplementation (*this));
int i = 0; int i = 0;
for (auto&& b : modelData.buttons) for (auto&& b : modelData.buttons)
controlButtons.add (new ControlButtonImplementation (*this, i++, b)); controlButtons.add (new ControlButtonImplementation (*this, i++, b));
@@ -1371,6 +1500,16 @@ struct PhysicalTopologySource::Internal
juce::Array<Block::ConnectionPort> getPorts() const override { return modelData.ports; } juce::Array<Block::ConnectionPort> getPorts() const override { return modelData.ports; }
bool isConnected() const override { return isStillConnected && detector.isConnected (uid); } bool isConnected() const override { return isStillConnected && detector.isConnected (uid); }
bool isMasterBlock() const override { return isMaster; } bool isMasterBlock() const override { return isMaster; }
Block::UID getConnectedMasterUID() const override { return masterUID; }
int getRotation() const override { return rotation; }
Rectangle<int> getBlockAreaWithinLayout() const override
{
if (rotation % 2 == 0)
return { position.getX(), position.getY(), modelData.widthUnits, modelData.heightUnits };
return { position.getX(), position.getY(), modelData.heightUnits, modelData.widthUnits };
}
TouchSurface* getTouchSurface() const override { return touchSurface.get(); } TouchSurface* getTouchSurface() const override { return touchSurface.get(); }
LEDGrid* getLEDGrid() const override { return ledGrid.get(); } LEDGrid* getLEDGrid() const override { return ledGrid.get(); }
@@ -1876,6 +2015,11 @@ struct PhysicalTopologySource::Internal
uint32 resetMessagesSent = 0; uint32 resetMessagesSent = 0;
bool isStillConnected = true; bool isStillConnected = true;
bool isMaster = false; bool isMaster = false;
Block::UID masterUID = {};
Point<int> position;
int rotation = 0;
friend BlocksTraverser;
void initialiseDeviceIndexAndConnection() void initialiseDeviceIndexAndConnection()
{ {


Loading…
Cancel
Save