/** * Insert a vertex before a vertex identified by identifier * * This is why the vertices having identifiers really matter. * This capability is why you'd use this structure in the first * place... mostly. * * So, what do we got? * * You start with this - * * v1 v2 v3 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / * null -- e1 - e2 - e3 -- null (getNextEdge(), getPreviousEdge()) * * And end with this (insert new vertex v5 before v3) - * * v1 v2 v5 v3 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / \ / * null -- e1 - e2 - e4 - e3 -- null (getNextEdge(), getPreviousEdge()) * * First we build a new edge e4 pointing to v5 (new) - v3 (old) * Then we insert the edge: * e2 [next] = v5 now, not v3 * e2 [nextEdge] = e4, not e3 * e3 [prevEdge] = e4, not e2 * * OR! * * You start with this - * * v1 v2 v3 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / * null -- e1 - e2 - e3 -- null (getNextEdge(), getPreviousEdge()) * * And end with this (insert new vertex v5 before v1) - * * v5 v1 v2 v3 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / \ / * null -- e4 - e1 - e2 - e3 -- null (getNextEdge(), getPreviousEdge()) * * OR! * * You must take those provisions into account as well, as each requires * different steps. The steps are outlined below, but they are all a * derivation of the above steps. * * Yeah, I had to figure that out all on paper. * * Let's do this beeyatch! * * @param Falcraft\Data\Types\Node\VertexInterface &$vertex The new vertex to insert * @param mixed $identifier The identifier (v3 for instance) to insert after * * @return bool If the operation was successful * */ public function insertBefore(TypesResource\VertexInterface &$vertex, $identifier) { // Get the first edge $currentEdge = $this->getFirstEdge(); if ($currentEdge->getNextEdge() == null && ($currentEdge->getNext() == null || $currentEdge->getPrevious() == null)) { /* currentEdge is the first, the last, the alpha and the omega * AND one of its vertices is null * * ? ? * \ / * CE */ if ($currentEdge->getPrevious() == null) { /* null ? * \ / * CE */ // we're empty bro return false; } else { if ($currentEdge->getNext() == null && $currentEdge->getPrevious()->getIdentifier() == $identifier) { /* *v1* null * \ / * CE */ $currentEdge->setNext($currentEdge->getPrevious()); $currentEdge->setPrevious($vertex); /* NV *v1* * \ / * CE */ return true; } else { /* Only prev set and it's not the target, next code will access next which is NOT set damn you, please return your ticket */ return false; } } } // Else currentEdge is the first edge, and is full if ($currentEdge->getPrevious()->getIdentifier() == $identifier) { /* v5 v1 v2 v3 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / \ / * null -- e4 - e1 - e2 - e3 -- null (getNextEdge(), getPreviousEdge()) */ // Make e4 linking to v5 (new) and v1 (old) $newEdge = new OrderedEdge($vertex, $currentEdge->getPrevious()); // link e4 <- e1 done $currentEdge->setPreviousEdge($newEdge); $newEdge->setNextEdge($currentEdge); // IMPORTANT! Add edge to collection of edges $this->edges->add($newEdge); return true; } // Look through the rest of the vertices for a match while ($currentEdge && $currentEdge->getNext()->getIdentifier() != $identifier) { $currentEdge =& $currentEdge->getNextEdge(); } if ($currentEdge == null) { /* We exhausted the list, with no match Return, a disappointment to your mother */ return false; } if ($currentEdge->getPreviousEdge() == null) { /* We're still at the beginning of the list so we're going to start with this: * * v1 *v2* v3 * \ / \ / * null -- (e1) - e2 - ... * * And end with this: * * v1 v4 *v2* v3 * \ / \ / \ / * null -- (e1) - e3 - e2 -- null * * new edge e3 = nv, e1's next * e1 next = nv * e1 nextEdge = e3 * e2 prevEdge = e3 * e3 nextedge = e2 * e3 prevedge = e1 */ $newEdge = new OrderedEdge($vertex, $currentEdge->getNext()); $currentEdge->setNext($vertex); //$nextEdge->setPreviousEdge($currentEdge); $newEdge->setPreviousEdge($currentEdge); //$nextEdge->setNextEdge($currentEdge->getNextEdge()); if ($e = $currentEdge->getNextEdge()) { $newEdge->setNextEdge($e->getNextEdge()); $e->getNextEdge()->setPreviousEdge($newEdge); } $currentEdge->setNextEdge($newEdge); } else { /* Otherwise we have this: * * ? *v* (v4) * \ / * ? - CE - ? () * * v1 v2 v3 v5 v4 (edge->getPrev(), edge->getNext()) * \ / \ / \ / \ / * null -- e1 - e2 - e4 - (e3) -- null (getNextEdge(), getPreviousEdge()) * * new edge e4 - e3's prev, nv * e3 prev = nv * e2 nextEdge = e4 * e3 prevEdge = e4 */ // Create e4 with v3 (e3->prev) as prev, new vertex on next $newEdge = new OrderedEdge($currentEdge->getPrevious(), $vertex); $currentEdge->setPrevious($vertex); $newEdge->setPreviousEdge($currentEdge->getPreviousEdge()); $newEdge->setNextEdge($currentEdge); $currentEdge->getPreviousEdge()->setNextEdge($newEdge); $currentEdge->setPreviousEdge($newEdge); } // IMPORTANT! Add edge to collection of edges $this->edges->add($newEdge); return true; }
/** * Utility function to connect to edges together in a given list * * @static * * @param Falcraft\Data\Types\Resource\OrderedEdge &$left The left object * @param Falcraft\Data\Types\Resource\OrderedEdge &$right The right object * */ public static function connect(OrderedEdge &$left, OrderedEdge &$right) { $left->setNextEdge($right); $right->setPreviousEdge($left); }