/** * \return List of RLines and RArcs describing this polyline. */ QList<QSharedPointer<RShape> > RPolyline::getExploded(int segments) const { Q_UNUSED(segments); QList<QSharedPointer<RShape> > ret; if (vertices.size()<=1) { return ret; } //qDebug() << "shapes: "; for (int i=0; i<vertices.size(); i++) { //qDebug() << "vertex[" << i << "]: " << vertices.at(i) << ", bulge: " << bulges.at(i); if (!closed && i==vertices.size()-1) { break; } QSharedPointer<RShape> subShape = getSegmentAt(i); if (subShape.isNull()) { continue; } ret.append(subShape); //qDebug() << "shape: " << *getSubShapeAt(i); } return ret; }
bool RPolylineData::moveReferencePoint(const RVector& referencePoint, const RVector& targetPoint) { bool ret = false; QList<RVector>::iterator it; for (it=vertices.begin(); it!=vertices.end(); ++it) { if (referencePoint.equalsFuzzy(*it)) { (*it) = targetPoint; ret = true; } } for (int i=0; i<countSegments(); i++) { if (isArcSegmentAt(i)) { QSharedPointer<RArc> arc = getSegmentAt(i).dynamicCast<RArc>(); if (!arc.isNull()) { if (referencePoint.equalsFuzzy(arc->getMiddlePoint())) { RArc a = RArc::createFrom3Points(arc->getStartPoint(), targetPoint, arc->getEndPoint()); setBulgeAt(i, a.getBulge()); ret = true; } } } } return ret; }
bool RPolyline::simplify(double angleTolerance) { bool ret = false; RPolyline newPolyline; //ret.appendVertex(getStartPoint()); RS::EntityType type = RS::EntityUnknown; double angle = RMAXDOUBLE; //double radius = 0; //RVector center; //RVector vertex; for (int i=0; i<countSegments(); i++) { QSharedPointer<RShape> seg = getSegmentAt(i); QSharedPointer<RLine> line = seg.dynamicCast<RLine>(); if (!line.isNull()) { double angleDiff = qAbs(RMath::getAngleDifference180(line->getAngle(), angle)); // qDebug() << "angle diff: " << angleDiff; // qDebug() << "tol: " << angleTolerance; if (type==RS::EntityLine && angleDiff<angleTolerance) { //vertex = line->getEndPoint(); ret = true; } else { //qDebug() << "start: " << line->getStartPoint(); newPolyline.appendVertex(line->getStartPoint()); angle = line->getAngle(); type = RS::EntityLine; } } QSharedPointer<RArc> arc = seg.dynamicCast<RArc>(); if (!arc.isNull()) { // TODO newPolyline.appendVertex(arc->getStartPoint(), arc->getBulge()); } } if (isClosed()) { newPolyline.setClosed(true); } else { newPolyline.appendVertex(getEndPoint()); } // qDebug() << "old polyline: " << *this; // qDebug() << "new polyline: " << newPolyline; //*this = newPolyline; //clear(); vertices = newPolyline.vertices; bulges = newPolyline.bulges; closed = newPolyline.closed; return ret; }
QSharedPointer<RShape> RPolyline::getTransformed(const QTransform& transform) const { QSharedPointer<RPolyline> ret = QSharedPointer<RPolyline>(new RPolyline()); for (int i=0; i<countSegments(); i++) { QSharedPointer<RShape> s = getSegmentAt(i); QSharedPointer<RShape> st = s->getTransformed(transform); ret->appendShape(*st); } return ret; }
double RPolyline::getDirection1() const { if (vertices.size()==0) { return RNANDOUBLE; } QSharedPointer<RShape> shape = getSegmentAt(0); QSharedPointer<RDirected> dirShape = shape.dynamicCast<RDirected>(); if (dirShape.isNull()) { return RNANDOUBLE; } return dirShape->getDirection1(); }
/** * \return true if this leader can have an arrow head (i.e. first * segment is >= DIMASZ * DIMSCALE * 2. */ bool RLeaderData::canHaveArrowHead() const { if (countSegments()==0) { return false; } QSharedPointer<RShape> firstSegment = getSegmentAt(0); if (firstSegment.isNull()) { return false; } if (firstSegment->getLength() < getDimasz() * 2) { return false; } return true; }
QList<RRefPoint> RPolylineData::getReferencePoints(RS::ProjectionRenderingHint hint) const { Q_UNUSED(hint) QList<RRefPoint> ret = RRefPoint::toRefPointList(getVertices()); if (!ret.isEmpty()) { // mark start and end points: ret.first().setStart(true); ret.last().setEnd(true); } for (int i=0; i<countSegments(); i++) { if (isArcSegmentAt(i)) { QSharedPointer<RArc> arc = getSegmentAt(i).dynamicCast<RArc>(); if (!arc.isNull()) { ret.append(RRefPoint(arc->getMiddlePoint(), RRefPoint::Secondary)); } } } return ret; }
/** * \return A QPainterPath object that represents this polyline. */ RPainterPath RPolyline::toPainterPath() const { RPainterPath ret; if (vertices.size()<=1) { return ret; } ret.moveTo(vertices.at(0)); for (int i=0; i<vertices.size(); i++) { if (!closed && i==vertices.size()-1) { break; } QSharedPointer<RShape> shape = getSegmentAt(i); ret.addShape(shape); } return ret; }
/** * \return List of RLines and RArcs describing this polyline. */ QList<QSharedPointer<RShape> > RPolyline::getExploded(int segments) const { Q_UNUSED(segments); QList<QSharedPointer<RShape> > ret; if (vertices.size()<=1) { return ret; } for (int i=0; i<vertices.size(); i++) { if (!closed && i==vertices.size()-1) { break; } QSharedPointer<RShape> subShape = getSegmentAt(i); if (subShape.isNull()) { continue; } ret.append(subShape); } return ret; }
/* * Function to Compile MIPS code at 'address' and then return the ARM_PC counter to jump to */ size_t branchUnknown(code_seg_t* code_seg, size_t* address) { //volatile code_seg_t* code_seg = segmentData.dbgCurrentSegment; Instruction_t* ins = newEmptyInstr(); size_t ARMAddress; uint32_t MIPSaddress; Instruction_e op; // find out it the end of the segment is a JUMP or BRANCH op = ops_type(code_seg->MIPScode[code_seg->MIPScodeLen - 1]); //Get MIPS condition code and link mips_decode(code_seg->MIPScode[code_seg->MIPScodeLen - 1], ins); ins->outputAddress = &code_seg->MIPScode[code_seg->MIPScodeLen - 1]; if (op & OPS_BRANCH){ MIPSaddress = (uint32_t)(code_seg->MIPScode + code_seg->MIPScodeLen - 1) + 4*ops_BranchOffset(code_seg->MIPScode + code_seg->MIPScodeLen - 1); } else if (op == MIPS_J || op == MIPS_JAL) { MIPSaddress = (((size_t)code_seg->MIPScode + code_seg->MIPScodeLen * 4)&0xF0000000U) + ops_JumpAddress(&code_seg->MIPScode[code_seg->MIPScodeLen - 1]); } else if (op == MIPS_JR || op == MIPS_JALR) { MIPSaddress = address; } #if SHOW_BRANCHUNKNOWN_STEPS printf("branchUnknown(0x%08x) called from Segment 0x%08x\n", MIPSaddress, (uint32_t)code_seg); printf_Intermediate(ins,1); #endif code_seg_t* tgtSeg = getSegmentAt(MIPSaddress); #if SHOW_BRANCHUNKNOWN_STEPS printf("tgtSeg = 0x%08x\n", (uint32_t)tgtSeg); #endif // 1. Need to generate the ARM assembler for target code_segment. Use 'addr' and code Seg map. // 2. Then we need to patch the code_segment branch we came from. Do we need it to be a link? // 3. return the address to branch to. // 1. if (NULL != tgtSeg) { if (NULL == tgtSeg->ARMEntryPoint) { #if SHOW_BRANCHUNKNOWN_STEPS printf("Translating pre-existing CodeSegment\n"); #endif Translate(tgtSeg); } else { #if SHOW_BRANCHUNKNOWN_STEPS printf("Patch pre-existing CodeSegment\n"); #endif } ARMAddress = (size_t)tgtSeg->ARMEntryPoint; } else { #if SHOW_BRANCHUNKNOWN_STEPS printf("Creating new CodeSegment for 0x%08x\n", MIPSaddress); #endif tgtSeg = CompileCodeAt((uint32_t*)MIPSaddress); ARMAddress = (size_t)tgtSeg->ARMEntryPoint; } code_seg->pBranchNext = tgtSeg; // 2. if (((op & OPS_BRANCH) == OPS_BRANCH) || (op == MIPS_J) || (op == MIPS_JAL)) { #if USE_HOST_MANAGED_BRANCHING if ((op & OPS_LINK) == OPS_LINK) { if ((op & OPS_LIKELY) == OPS_LIKELY) { //Set instruction to ARM_BRANCH for new target InstrBL(ins, AL, ARMAddress, 1); } else { //Set instruction to ARM_BRANCH for new target InstrBL(ins, ins->cond, ARMAddress, 1); } } else #endif { //Set instruction to ARM_BRANCH for new target InstrB(ins, ins->cond, ARMAddress, 1); } addToCallers(code_seg, tgtSeg); ins->outputAddress = (size_t)address; #if SHOW_BRANCHUNKNOWN_STEPS printf_Intermediate(ins,1); #endif uint32_t* out = address; *out = arm_encode(ins, (size_t)out); __clear_cache(out, &out[1]); } #if USE_HOST_MANAGED_BRANCHING == 0 else if (op == MIPS_JR) { ins = tgtSeg->Intermcode; Instruction_t branchIns = ins; while (ins != NULL) { if (ins == ARM_B) { branchIns = ins; } ins = ins->nextInstruction; } ARMAddress = (size_t)branchIns->outputAddress + 4U; } #endif // 3. return ARMAddress; }
/* * Description: Function to malloc a newSegment and zero initialize it. * * Parameters: none * * Returns: code_seg_t* */ code_seg_t* newSegment() { code_seg_t* newSeg = malloc(sizeof(code_seg_t)); memset(newSeg, 0,sizeof(code_seg_t)); #if SHOW_PRINT_SEGMENT_DELETE == 2 { #elif SHOW_PRINT_SEGMENT_DELETE == 1 if (showPrintSegmentDelete) { #else if (0) { #endif printf("new Segment 0x%08x\n", (uint32_t)newSeg); } return newSeg; } /* * Description: Function to free a segment and its associated data. * * Function will also invalidate the branches of code segments that branch to this one * and delete segments that 'continue' execution to this one. * * Parameters: none * * Returns: code_seg_t* */ uint32_t delSegment(code_seg_t* codeSegment) { uint32_t ret = 0; #if SHOW_PRINT_SEGMENT_DELETE == 2 { #elif SHOW_PRINT_SEGMENT_DELETE == 1 if (showPrintSegmentDelete) { #else if (0) { #endif printf("deleting Segment 0x%08x for mips code at 0x%08x\n", (uint32_t)codeSegment, (uint32_t)codeSegment->MIPScode); } freeIntermediateInstructions(codeSegment); // free memory used for Intermediate Instructions freeLiterals(codeSegment); // free memory used by literals // Clean up all segments that branch or continue to this segment if (codeSegment->callers != NULL) { caller_t* caller = codeSegment->callers; // loop through all the callers while (caller != NULL) { if (caller->codeSeg != NULL) { // if the found caller branches to this segment then remove the reference if (caller->codeSeg->pBranchNext == codeSegment) { caller->codeSeg->pBranchNext = NULL; } // if the found caller continues to this segment then it MUST also be deleted else if (caller->codeSeg->pContinueNext == codeSegment) { delSegment(caller->codeSeg); } } caller = caller->next; } // Invalidate any segments that branch to this segment and free the caller_t objects freeCallers(codeSegment); } // update the codeSegment mapping setMemState((size_t)codeSegment->MIPScode, codeSegment->MIPScodeLen, NULL); free(codeSegment); return ret; } /* * Description: Function to Compile the code starting at 'address'. * * This function will scan the code until an unconditional Jump is found. Referred to as a super block * * It may detect multiple segments in which case these will all 'continue' execution into the next segment. * * It also detects internal loops and separates these into their own segment, for better register optimization. * * * Parameters: const uint32_t* const address The address to start compiling from. * * Returns: code_seg_t* The first generated code Segment. */ code_seg_t* CompileCodeAt(const uint32_t const address[]) { uint32_t x; Instruction_e op; uint32_t uiMIPScodeLen = 0U; code_seg_t* newSeg; code_seg_t* prevSeg = NULL; // Find the shortest length of contiguous blocks (super block) of MIPS code at 'address' // Contiguous blocks should end with an OPS_JUMP && !OPS_LINK for (;;) // (index + uiMIPScodeLen < upperAddress/sizeof(code_seg_t*)) { op = ops_type(address[uiMIPScodeLen]); if (DR_INVALID == op) { uiMIPScodeLen = 0U; break; } uiMIPScodeLen++; if ((op & OPS_JUMP) == OPS_JUMP && (op & OPS_LINK) != OPS_LINK) //unconditional jump or function return { break; } } #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - found %u potential instructions\n", address, uiMIPScodeLen); #endif //Now expire the segments within the super block and remove the segments for (x = 0U; x < uiMIPScodeLen; x++) { code_seg_t* toDelete; toDelete = getSegmentAt((size_t)(address + x)); if (toDelete) { setMemState((size_t)toDelete->MIPScode, toDelete->MIPScodeLen, NULL); delSegment(toDelete); //we can skip next few words as we have already cleared them. x += toDelete->MIPScodeLen - 1U; } } uint32_t segmentStartIndex = 0U; // Create new segments for (x = 0U; x < uiMIPScodeLen; x++) { op = ops_type(address[x]); if ((op & OPS_JUMP) == OPS_JUMP) { //uint32_t uiAddress = ops_JumpAddress(&address[x]); newSeg = newSegment(); newSeg->MIPScode = (uint32_t*)(address + segmentStartIndex); newSeg->MIPScodeLen = x - segmentStartIndex + 1U; #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - new external jump segment 0x%x at address 0x%x\n", address + x * 4U, newSeg, newSeg->MIPScode); #endif if (op == MIPS_JR) //only JR can set PC to the Link Register (or other register!) { newSeg->MIPSReturnRegister = (*address>>21U)&0x1fU; } if (prevSeg) { prevSeg->pContinueNext = newSeg; addToCallers(prevSeg, newSeg); } prevSeg = newSeg; if (!segmentStartIndex) { newSeg->Type = SEG_START; } else { newSeg->Type = SEG_END; } setMemState((size_t)(address + segmentStartIndex), newSeg->MIPScodeLen, newSeg); segmentStartIndex = x + 1U; // we should have got to the end of the super block if (!(op & OPS_LINK)) { break; } } else if((op & OPS_BRANCH) == OPS_BRANCH) //MIPS does not have an unconditional branch { int32_t offset = ops_BranchOffset(&address[x]); //Is this an internal branch - need to create two segments // if use x<= y + offset then may throw SIGSEGV if offset is -1! if (offset < 0 && x + offset >= segmentStartIndex ) { newSeg = newSegment(); newSeg->MIPScode = (uint32_t*)(address + segmentStartIndex); newSeg->MIPScodeLen = x + offset - segmentStartIndex + 1U; #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - new internal branching, pre-loop segment 0x%x to address 0x%x\n", address, newSeg, newSeg->MIPScode); #endif if (prevSeg != NULL) { prevSeg->pContinueNext = newSeg; addToCallers(prevSeg, newSeg); } prevSeg = newSeg; if (segmentStartIndex == 0U) { newSeg->Type = SEG_START; } else { newSeg->Type = SEG_SANDWICH; } setMemState((size_t)(address + segmentStartIndex), newSeg->MIPScodeLen, newSeg); segmentStartIndex = x + 1U; newSeg = newSegment(); newSeg->MIPScode = (uint32_t*)(address + segmentStartIndex + offset); newSeg->MIPScodeLen = -offset; newSeg->Type = SEG_SANDWICH; #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - new internal branching self-looping segment 0x%x to address 0x%x\n", address, newSeg, newSeg->MIPScode); #endif prevSeg->pContinueNext = newSeg; addToCallers(prevSeg, newSeg); prevSeg = newSeg; setMemState((size_t)(address + segmentStartIndex + offset), newSeg->MIPScodeLen, newSeg); segmentStartIndex = x + 1U; } else // if we are branching external to the block? { newSeg = newSegment(); newSeg->MIPScode = (uint32_t*)(address + segmentStartIndex); newSeg->MIPScodeLen = x - segmentStartIndex + 1U; #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - new external branching segment 0x%x to address 0x%x\n", address, newSeg, newSeg->MIPScode); #endif setMemState((size_t)(address + segmentStartIndex), newSeg->MIPScodeLen, newSeg); // if (prevSeg != NULL) { prevSeg->pContinueNext = newSeg; addToCallers(prevSeg, newSeg); } #if 1 code_seg_t* externalSegment = getSegmentAt((uint32_t)(address + segmentStartIndex + offset)); if (externalSegment != NULL) { #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - segment 0x%x branches to segment 0x%x to address \n", address, newSeg, externalSegment, externalSegment->MIPScode); #endif newSeg->pBranchNext = externalSegment; // addToCallers() will be done when compiling code within C_Interface.c:branchUnknown() } #endif prevSeg = newSeg; if (segmentStartIndex == 0U) { newSeg->Type = SEG_START; } else { newSeg->Type = SEG_SANDWICH; } segmentStartIndex = x + 1U; } } } // for (x = 0; x < uiMIPScodeLen; x++)
if (segmentStartIndex == 0U) { newSeg->Type = SEG_START; } else { newSeg->Type = SEG_SANDWICH; } segmentStartIndex = x + 1U; } } } // for (x = 0; x < uiMIPScodeLen; x++) newSeg = getSegmentAt((size_t)address); if (newSeg) { // Now we can translate and emit code to the next 'break' in instructions while (newSeg->pContinueNext) { segmentData.dbgCurrentSegment = newSeg; Translate(newSeg); #if SHOW_COMPILEAT_STEPS printf("CompiltCodeAt(0x%x) - Translating segment 0x%x\n", address, newSeg); #endif newSeg = newSeg->pContinueNext; } segmentData.dbgCurrentSegment = newSeg;
RS::Orientation RPolyline::getOrientation() const { if (!isGeometricallyClosed()) { return RS::Any; } RVector minV = RVector::invalid; QSharedPointer<RDirected> shapeBefore; QSharedPointer<RDirected> shapeAfter; QSharedPointer<RShape> shape; QSharedPointer<RDirected> previousShape = getSegmentAt(countSegments()-1).dynamicCast<RDirected>(); // find minimum vertex (lower left corner): QList<QSharedPointer<RShape> > segments = getExploded(); for (int i=0; i<segments.length(); i++) { shape = getSegmentAt(i); if (shape.isNull()) { continue; } QSharedPointer<RDirected> directed = shape.dynamicCast<RDirected>(); if (directed.isNull()) { continue; } RVector v = directed->getStartPoint(); if (!minV.isValid() || v.x<minV.x || (v.x==minV.x && v.y<minV.y)) { minV = v; shapeBefore = previousShape; shapeAfter = directed; } previousShape = directed; } double l; RVector p; QSharedPointer<RArc> arcBefore = shapeBefore.dynamicCast<RArc>(); if (!arcBefore.isNull()) { l = arcBefore->getLength(); p = arcBefore->getPointsWithDistanceToEnd(l/10, RS::FromStart)[0]; shapeBefore = QSharedPointer<RLine>(new RLine(p, arcBefore->getEndPoint())); } QSharedPointer<RArc> arcAfter = shapeAfter.dynamicCast<RArc>(); if (!arcAfter.isNull()) { l = arcAfter->getLength(); p = arcAfter->getPointsWithDistanceToEnd(l/10, RS::FromEnd)[0]; shapeAfter = QSharedPointer<RLine>(new RLine(arcAfter->getStartPoint(), p)); } double xa = shapeBefore->getStartPoint().x; double ya = shapeBefore->getStartPoint().y; double xb = shapeAfter->getStartPoint().x; double yb = shapeAfter->getStartPoint().y; double xc = shapeAfter->getEndPoint().x; double yc = shapeAfter->getEndPoint().y; double det = (xb-xa) * (yc-ya) - (xc-xa) * (yb-ya); if (det<0.0) { // clockwise: return RS::CW; } else { // counter-clockwise: return RS::CCW; } }