qsstv_8.2.12/qsstv/drmtx/common/FAC/FAC.cpp000664 001750 001750 00000032453 12440612574 020276 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos PA0MBO * * Description: * FAC * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "FAC.h" /* Implementation *************************************************************/ /******************************************************************************\ * CFACTransmit * \******************************************************************************/ void CFACTransmit::FACParam(CVector<_BINARY>* pbiFACData, CParameter& Parameter) { /* Reset enqueue function */ (*pbiFACData).ResetBitAccess(); /* Put FAC parameters on stream */ /* Channel parameters --------------------------------------------------- */ /* Identity m 2 bits */ /* Manage index of FAC block in super-frame */ switch (Parameter.iFrameIDTransm) { case 0: /* Assuming AFS is valid (AFS not used here), if AFS is not valid, the parameter must be 3 (11) */ (*pbiFACData).Enqueue(3 /* 11 */, 2); break; case 1: (*pbiFACData).Enqueue(1 /* 01 */, 2); break; case 2: (*pbiFACData).Enqueue(2 /* 10 */, 2); break; } /* Spectrum occupancy for ham use only 1 bit */ switch (Parameter.GetSpectrumOccup()) { case SO_0: (*pbiFACData).Enqueue(0 /* 0 */, 1); break; case SO_1: (*pbiFACData).Enqueue(1 /* 1 */, 1); break; default: (*pbiFACData).Enqueue(0 /* 0 */, 1); break; } /* Interleaver depth flag ham situation 1 bit */ switch (Parameter.eSymbolInterlMode) { case CParameter::SI_LONG: (*pbiFACData).Enqueue(0 /* 0 */, 1); break; case CParameter::SI_SHORT: (*pbiFACData).Enqueue(1 /* 1 */, 1); break; } /* MSC mode */ switch (Parameter.eMSCCodingScheme) { case CS_3_SM: (*pbiFACData).Enqueue(0 /* 0 */, 1); break; case CS_1_SM: (*pbiFACData).Enqueue(1 /* 1 */, 1); break; case CS_2_SM: (*pbiFACData).Enqueue(1 /* 1 */, 1); break; default: break; } /* Prot Level 1 bit */ switch (Parameter.MSCPrLe.iPartB) { case 0: (*pbiFACData).Enqueue(0 /* 0 */, 1); break; case 1: (*pbiFACData).Enqueue(1 /* 1 */, 1); break; } /* Audio/Data flag */ switch (Parameter.Service[0].eAudDataFlag) { case CService::SF_AUDIO: (*pbiFACData).Enqueue(0 /* 0 */, 1); (*pbiFACData).Enqueue(3 /* 11 */, 2); // pa0mbo dummy bits SSTV (*pbiFACData).Enqueue(0 /* 0 */, 1); // pa0mbo no text break; case CService::SF_DATA: (*pbiFACData).Enqueue(1 /* 1 */, 1); /* Packet Id */ (*pbiFACData).Enqueue( (uint32_t) Parameter.Service[0].DataParam.iPacketID, 2); /* Extended MSC mode 1 bit */ if (Parameter.eMSCCodingScheme == CS_1_SM) (*pbiFACData).Enqueue(1 /* 1 */, 1); // QAM 4 else (*pbiFACData).Enqueue(0 /* 0 */, 1); // others break; } { int iLenLabel; int iframet = Parameter.iFrameIDTransm; const int iLenLabelTmp = Parameter.Service[0].strLabel.length(); if (iLenLabelTmp > 9) iLenLabel = 9; else iLenLabel = iLenLabelTmp; /* Set all characters of label string */ for (int i = 3*iframet; i < 3*iframet+3; i++) { char cNewChar; if (i >= iLenLabel) cNewChar = 0; else cNewChar = Parameter.Service[0].strLabel[i]; cNewChar &= 127; /* Set character */ (*pbiFACData).Enqueue((uint32_t) cNewChar, 7); } } /* CRC ------------------------------------------------------------------ */ /* Calculate the CRC and put at the end of the stream */ CRCObject.Reset(8); (*pbiFACData).ResetBitAccess(); for (int i = 0; i < NUM_FAC_BITS_PER_BLOCK / SIZEOF__BYTE - 1; i++) CRCObject.AddByte((_BYTE) (*pbiFACData).Separate(SIZEOF__BYTE)); /* Now, pointer in "enqueue"-function is back at the same place, add CRC */ (*pbiFACData).Enqueue(CRCObject.GetCRC(), 8); } void CFACTransmit::Init(CParameter& Parameter) { set actServ; /* Get active services */ Parameter.GetActiveServices(actServ); const size_t iTotNumServices = actServ.size(); /* Check how many audio and data services present */ vector veciAudioServ; vector veciDataServ; size_t iNumAudio = 0; size_t iNumData = 0; for (set::iterator i = actServ.begin(); i!=actServ.end(); i++) { if (Parameter.Service[*i].eAudDataFlag == CService::SF_AUDIO) { veciAudioServ.push_back(*i); iNumAudio++; } else { veciDataServ.push_back(*i); iNumData++; } } /* Now check special cases which are defined in 6.3.6-------------------- */ /* If we have only data or only audio services. When all services are of the same type (e.g. all audio or all data) then the services shall be signalled sequentially */ if ((iNumAudio == iTotNumServices) || (iNumData == iTotNumServices)) { /* Init repetition vector */ FACNumRep = iTotNumServices; FACRepetition.resize(0); for (set::iterator i = actServ.begin(); i!=actServ.end(); i++) FACRepetition.push_back(*i); } else { /* Special cases according to Table 60 (Service parameter repetition patterns for mixtures of audio and data services) */ if (iNumAudio == 1) { if (iNumData == 1) { /* Init repetion vector */ FACNumRep = 5; FACRepetition.resize(FACNumRep); /* A1A1A1A1D1 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[0]; FACRepetition[2] = veciAudioServ[0]; FACRepetition[3] = veciAudioServ[0]; FACRepetition[4] = veciDataServ[0]; } else if (iNumData == 2) { /* Init repetion vector */ FACNumRep = 10; FACRepetition.resize(FACNumRep); /* A1A1A1A1D1A1A1A1A1D2 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[0]; FACRepetition[2] = veciAudioServ[0]; FACRepetition[3] = veciAudioServ[0]; FACRepetition[4] = veciDataServ[0]; FACRepetition[5] = veciAudioServ[0]; FACRepetition[6] = veciAudioServ[0]; FACRepetition[7] = veciAudioServ[0]; FACRepetition[8] = veciAudioServ[0]; FACRepetition[9] = veciDataServ[1]; } else /* iNumData == 3 */ { /* Init repetion vector */ FACNumRep = 15; FACRepetition.resize(FACNumRep); /* A1A1A1A1D1A1A1A1A1D2A1A1A1A1D3 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[0]; FACRepetition[2] = veciAudioServ[0]; FACRepetition[3] = veciAudioServ[0]; FACRepetition[4] = veciDataServ[0]; FACRepetition[5] = veciAudioServ[0]; FACRepetition[6] = veciAudioServ[0]; FACRepetition[7] = veciAudioServ[0]; FACRepetition[8] = veciAudioServ[0]; FACRepetition[9] = veciDataServ[1]; FACRepetition[10] = veciAudioServ[0]; FACRepetition[11] = veciAudioServ[0]; FACRepetition[12] = veciAudioServ[0]; FACRepetition[13] = veciAudioServ[0]; FACRepetition[14] = veciDataServ[2]; } } else if (iNumAudio == 2) { if (iNumData == 1) { /* Init repetion vector */ FACNumRep = 5; FACRepetition.resize(FACNumRep); /* A1A2A1A2D1 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[1]; FACRepetition[2] = veciAudioServ[0]; FACRepetition[3] = veciAudioServ[1]; FACRepetition[4] = veciDataServ[0]; } else /* iNumData == 2 */ { /* Init repetion vector */ FACNumRep = 10; FACRepetition.resize(FACNumRep); /* A1A2A1A2D1A1A2A1A2D2 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[1]; FACRepetition[2] = veciAudioServ[0]; FACRepetition[3] = veciAudioServ[1]; FACRepetition[4] = veciDataServ[0]; FACRepetition[5] = veciAudioServ[0]; FACRepetition[6] = veciAudioServ[1]; FACRepetition[7] = veciAudioServ[0]; FACRepetition[8] = veciAudioServ[1]; FACRepetition[9] = veciDataServ[1]; } } else /* iNumAudio == 3 */ { /* Init repetion vector */ FACNumRep = 7; FACRepetition.resize(FACNumRep); /* A1A2A3A1A2A3D1 */ FACRepetition[0] = veciAudioServ[0]; FACRepetition[1] = veciAudioServ[1]; FACRepetition[2] = veciAudioServ[2]; FACRepetition[3] = veciAudioServ[0]; FACRepetition[4] = veciAudioServ[1]; FACRepetition[5] = veciAudioServ[2]; FACRepetition[6] = veciDataServ[0]; } } } /******************************************************************************\ * CFACReceive * \******************************************************************************/ _BOOLEAN CFACReceive::FACParam(CVector<_BINARY>* pbiFACData, CParameter& Parameter) { /* First get new data from incoming data stream, then check if the new parameter differs from the old data stored in the receiver. If yes, init the modules to the new parameter */ uint32_t iTempServiceID; int iTempShortID; /* CRC ------------------------------------------------------------------ */ /* Check the CRC of this data block */ CRCObject.Reset(8); (*pbiFACData).ResetBitAccess(); for (int i = 0; i < NUM_FAC_BITS_PER_BLOCK / SIZEOF__BYTE - 1; i++) CRCObject.AddByte((_BYTE) (*pbiFACData).Separate(SIZEOF__BYTE)); if (CRCObject.CheckCRC((*pbiFACData).Separate(8)) == true) { /* CRC-check successful, extract data from FAC-stream */ /* Reset separation function */ (*pbiFACData).ResetBitAccess(); Parameter.Lock(); /* Channel parameters ----------------------------------------------- */ /* Base/Enhancement flag (not used) */ (*pbiFACData).Separate(1); /* Identity */ switch ((*pbiFACData).Separate(2)) { case 0: /* 00 */ Parameter.iFrameIDReceiv = 0; break; case 1: /* 01 */ Parameter.iFrameIDReceiv = 1; break; case 2: /* 10 */ Parameter.iFrameIDReceiv = 2; break; case 3: /* 11 */ Parameter.iFrameIDReceiv = 0; break; } /* Spectrum occupancy */ switch ((*pbiFACData).Separate(4)) { case 0: /* 0000 */ Parameter.SetSpectrumOccup(SO_0); break; case 1: /* 0001 */ Parameter.SetSpectrumOccup(SO_1); break; case 2: /* 0010 */ Parameter.SetSpectrumOccup(SO_2); break; case 3: /* 0011 */ Parameter.SetSpectrumOccup(SO_3); break; case 4: /* 0100 */ Parameter.SetSpectrumOccup(SO_4); break; case 5: /* 0101 */ Parameter.SetSpectrumOccup(SO_5); break; } /* Interleaver depth flag */ switch ((*pbiFACData).Separate(1)) { case 0: /* 0 */ Parameter.SetInterleaverDepth(CParameter::SI_LONG); break; case 1: /* 1 */ Parameter.SetInterleaverDepth(CParameter::SI_SHORT); break; } /* MSC mode */ switch ((*pbiFACData).Separate(2)) { case 0: /* 00 */ Parameter.SetMSCCodingScheme(CS_3_SM); break; case 1: /* 01 */ Parameter.SetMSCCodingScheme(CS_3_HMMIX); break; case 2: /* 10 */ Parameter.SetMSCCodingScheme(CS_3_HMSYM); break; case 3: /* 11 */ Parameter.SetMSCCodingScheme(CS_2_SM); break; } /* SDC mode */ switch ((*pbiFACData).Separate(1)) { case 0: /* 0 */ Parameter.SetSDCCodingScheme(CS_2_SM); break; case 1: /* 1 */ Parameter.SetSDCCodingScheme(CS_1_SM); break; } /* Number of services */ /* Search table for entry */ int iNumServTabEntry = (*pbiFACData).Separate(4); for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) if (iNumServTabEntry == iTableNumOfServices[i][j]) Parameter.SetNumOfServices(i, j); /* Reconfiguration index (not used, yet) */ (*pbiFACData).Separate(3); /* rfu */ /* Do not use rfu */ (*pbiFACData).Separate(2); /* Service parameters ----------------------------------------------- */ /* Service identifier */ iTempServiceID = (*pbiFACData).Separate(24); /* Short ID (the short ID is the index of the service-array) */ iTempShortID = (*pbiFACData).Separate(2); /* Set service identifier */ Parameter.SetServiceID(iTempShortID, iTempServiceID); /* CA indication */ switch ((*pbiFACData).Separate(1)) { case 0: /* 0 */ Parameter.Service[iTempShortID].eCAIndication = CService::CA_NOT_USED; break; case 1: /* 1 */ Parameter.Service[iTempShortID].eCAIndication = CService::CA_USED; break; } /* Language */ Parameter.Service[iTempShortID].iLanguage = (*pbiFACData).Separate(4); /* Audio/Data flag */ switch ((*pbiFACData).Separate(1)) { case 0: /* 0 */ Parameter.SetAudDataFlag(iTempShortID, CService::SF_AUDIO); break; case 1: /* 1 */ Parameter.SetAudDataFlag(iTempShortID, CService::SF_DATA); break; } /* Service descriptor */ Parameter.Service[iTempShortID].iServiceDescr = (*pbiFACData).Separate(5); Parameter.Unlock(); /* Rfa */ /* Do not use Rfa */ (*pbiFACData).Separate(7); /* CRC is ok, return true */ return true; } else { /* Data is corrupted, do not use it. Return failure as false */ return false; } } qsstv_8.2.12/qsstv/drmtx/common/FAC/FAC.h000664 001750 001750 00000004153 12440612574 017737 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See FAC.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(FAC_H__3B0BA660_CA63VEUASDVN89LKVNE877A0D31912__INCLUDED_) #define FAC_H__3B0BA660_CA63VEUASDVN89LKVNE877A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../tables/TableFAC.h" #include "../Parameter.h" #include "../util/CRC.h" #include "utils/vector.h" /* Classes ********************************************************************/ class CFACTransmit { public: CFACTransmit():FACRepetitionCounter(0) {} virtual ~CFACTransmit() {} /* "pbiFACData" contains 72 bits */ void FACParam(CVector<_BINARY>* pbiFACData, CParameter& Parameter); void Init(CParameter& Parameter); protected: CCRC CRCObject; vector FACRepetition; /* See 6.3.6 */ size_t FACNumRep; size_t FACRepetitionCounter; }; class CFACReceive { public: CFACReceive() {} virtual ~CFACReceive() {} /* "pbiFACData" contains 72 bits */ _BOOLEAN FACParam(CVector<_BINARY>* pbiFACData, CParameter& Parameter); protected: CCRC CRCObject; }; #endif // !defined(FAC_H__3B0BA660_CA63VEUASDVN89LKVNE877A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/SDC/SDC.h000664 001750 001750 00000004621 12440612574 017777 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001-2005 * * Author(s): * Volker Fischer, Andrew Murphy * * Description: * See SDC.cpp * * 11/21/2005 Andrew Murphy, BBC Research & Development, 2005 * - AMSS data entity groups (no AFS index), added eSDCType, data type 11 * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(SDC_H__3B0BA660_CA63SDBOJKEWROBNER89NE877A0D312__INCLUDED_) #define SDC_H__3B0BA660_CA63SDBOJKEWROBNER89NE877A0D312__INCLUDED_ #include "../GlobalDefinitions.h" #include "../Parameter.h" #include "../util/CRC.h" #include "utils/vector.h" #include "../util/Utilities.h" /* Definitions ****************************************************************/ /* Number of bits of header of SDC block */ #define NUM_BITS_HEADER_SDC 12 /* Classes ********************************************************************/ class CSDCTransmit { public: CSDCTransmit() {} virtual ~CSDCTransmit() {} void SDCParam(CVector<_BINARY>* pbiData, CParameter& Parameter); protected: void DataEntityType0(CVector<_BINARY>& vecbiData, CParameter& Parameter); void DataEntityType1(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter); // ... void DataEntityType5(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter); // ... void DataEntityType9(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter); CCRC CRCObject; }; #endif // !defined(SDC_H__3B0BA660_CA63SDBOJKEWROBNER89NE877A0D312__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/SDC/SDCTransmit.cpp000664 001750 001750 00000035061 12440612574 022056 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * SDC * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "SDC.h" /* Implementation *************************************************************/ void CSDCTransmit::SDCParam(CVector<_BINARY>* pbiData, CParameter& Parameter) { /* Put SDC parameters on a stream */ int i; int iSize; CVector<_BINARY> vecbiData; /* Calculate length of data field in bytes (consistant to table 61 in (6.4.1)) */ const int iLengthDataFieldBytes = (int) ((_REAL) (Parameter.iNumSDCBitsPerSFrame - 20) / 8); /* 20 bits from AFS index and CRC */ const int iUsefulBitsSDC = 20 + iLengthDataFieldBytes * 8; /* "- 20" for the AFS-index and CRC! */ const int iMaxNumBitsDataBlocks = iUsefulBitsSDC - 20; /* Reset enqueue function */ (*pbiData).ResetBitAccess(); /* SDC Header ----------------------------------------------------------- */ /* AFS index (not used by this application, insert a "1" */ (*pbiData).Enqueue((uint32_t) 1, 4); /* Data Entities -------------------------------------------------------- */ /* Init bit-count */ int iNumUsedBits = 0; // Choose types, TEST. Send only important types for this test! // TODO: test, if SDC block is long enough for all types! /* Type 0 */ DataEntityType0(vecbiData, Parameter); // TODO: nicer solution iSize = vecbiData.Size(); if (iNumUsedBits + iSize < iMaxNumBitsDataBlocks) { iNumUsedBits += iSize; vecbiData.ResetBitAccess(); for (i = 0; i < iSize; i++) (*pbiData).Enqueue(vecbiData.Separate(1), 1); } // Only working for either one audio or data service! if (Parameter.iNumAudioService == 1) { /* Type 9 */ DataEntityType9(vecbiData, 0, Parameter); } else { /* Type 5 */ DataEntityType5(vecbiData, 0, Parameter); } // TODO: nicer solution iSize = vecbiData.Size(); if (iNumUsedBits + iSize < iMaxNumBitsDataBlocks) { iNumUsedBits += iSize; vecbiData.ResetBitAccess(); for (i = 0; i < iSize; i++) (*pbiData).Enqueue(vecbiData.Separate(1), 1); } /* Type 1 */ DataEntityType1(vecbiData, 0, Parameter); // TODO: nicer solution iSize = vecbiData.Size(); if (iNumUsedBits + iSize < iMaxNumBitsDataBlocks) { iNumUsedBits += iSize; vecbiData.ResetBitAccess(); for (i = 0; i < iSize; i++) (*pbiData).Enqueue(vecbiData.Separate(1), 1); } /* Zero-pad the unused bits in this SDC-block */ for (i = 0; i < iMaxNumBitsDataBlocks - iNumUsedBits; i++) (*pbiData).Enqueue((uint32_t) 0, 1); /* CRC ------------------------------------------------------------------ */ /* Calculate the CRC and put it at the end of the stream */ CRCObject.Reset(16); (*pbiData).ResetBitAccess(); /* Special treatment of SDC data stream: The CRC (Cyclic Redundancy Check) field shall contain a 16-bit CRC calculated over the AFS index coded in an 8-bit field (4 msbs are 0) and the data field. 4 MSBs from AFS-index. Insert four "0" in the data-stream */ const _BYTE byFirstByte = (_BYTE) (*pbiData).Separate(4); CRCObject.AddByte(byFirstByte); for (i = 0; i < (iUsefulBitsSDC - 4) / SIZEOF__BYTE - 2; i++) CRCObject.AddByte((_BYTE) (*pbiData).Separate(SIZEOF__BYTE)); /* Now, pointer in "enqueue"-function is back at the same place, add CRC */ (*pbiData).Enqueue(CRCObject.GetCRC(), 16); } /******************************************************************************\ * Data entity Type 0 (Multiplex description data entity) * \******************************************************************************/ void CSDCTransmit::DataEntityType0(CVector<_BINARY>& vecbiData, CParameter& Parameter) { /* 24 bits for each stream description + 4 bits for protection levels */ const int iNumBitsTotal = 4 + Parameter.GetTotNumServices() * 24; /* Init return vector (storing this data block) */ vecbiData.Init(iNumBitsTotal + NUM_BITS_HEADER_SDC); vecbiData.ResetBitAccess(); /* Length of the body, excluding the initial 4 bits ("- 4"), measured in bytes ("/ 8") */ uint32_t iLengthInBytes = (iNumBitsTotal - 4) / 8; vecbiData.Enqueue(iLengthInBytes, 7); /* Version flag (not used in this implementation) */ vecbiData.Enqueue((uint32_t) 0, 1); /* Data entity type */ vecbiData.Enqueue((uint32_t) 00, 4); /* Type 00 */ /* Actual body ---------------------------------------------------------- */ /* Protection level for part A */ vecbiData.Enqueue((uint32_t) Parameter.MSCPrLe.iPartA, 2); /* Protection level for part B */ vecbiData.Enqueue((uint32_t) Parameter.MSCPrLe.iPartB, 2); for (size_t i = 0; i < Parameter.GetTotNumServices(); i++) { /* In case of hirachical modulation stream 0 describes the protection level and length of hirarchical data */ if ((i == 0) && ((Parameter.eMSCCodingScheme == CS_3_HMSYM) || (Parameter.eMSCCodingScheme == CS_3_HMMIX))) { /* Protection level for hierarchical */ vecbiData.Enqueue((uint32_t) Parameter.MSCPrLe.iHierarch, 2); /* rfu */ vecbiData.Enqueue((uint32_t) 0, 10); /* Data length for hierarchical */ vecbiData.Enqueue((uint32_t) Parameter.Stream[i].iLenPartB, 12); } else { /* Data length for part A */ vecbiData.Enqueue((uint32_t) Parameter.Stream[i].iLenPartA, 12); /* Data length for part B */ vecbiData.Enqueue((uint32_t) Parameter.Stream[i].iLenPartB, 12); } } } /******************************************************************************\ * Data entity Type 1 (Label data entity) * \******************************************************************************/ void CSDCTransmit::DataEntityType1(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter) { int iLenLabel; /* Length of label. Label is a variable length field of up to 16 bytes defining the label using UTF-8 coding */ const int iLenLabelTmp = Parameter.Service[ServiceID].strLabel.length(); if (iLenLabelTmp > 16) iLenLabel = 16; else iLenLabel = iLenLabelTmp; /* Number in bits (* 8) plus initial 4 bits (+ 4) */ const int iNumBitsTotal = iLenLabel * 8 + 4; /* Init return vector (storing this data block) */ vecbiData.Init(iNumBitsTotal + NUM_BITS_HEADER_SDC); vecbiData.ResetBitAccess(); /**** Multiplex description data entity - type 1 ****/ /* Length of the body, excluding the initial 4 bits, measured in bytes -> only number bytes of label */ vecbiData.Enqueue((uint32_t) iLenLabel, 7); /* Version flag (not used in this implementation) */ vecbiData.Enqueue((uint32_t) 0, 1); /* Data entity type */ vecbiData.Enqueue((uint32_t) 01, 4); /* Type 01 */ /* Actual body ---------------------------------------------------------- */ /* Short Id */ vecbiData.Enqueue((uint32_t) ServiceID, 2); /* rfu */ vecbiData.Enqueue((uint32_t) 0, 2); /* Set all characters of label string */ for (int i = 0; i < iLenLabel; i++) { const char cNewChar = Parameter.Service[ServiceID].strLabel[i]; /* Set character */ vecbiData.Enqueue((uint32_t) cNewChar, 8); } } /******************************************************************************\ * Data entity Type 5 (Application information data entity) * \******************************************************************************/ void CSDCTransmit::DataEntityType5(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter) { int iNumBitsTotal = 0; /* Set total number of bits */ switch (Parameter.Service[ServiceID].DataParam.ePacketModInd) { case CDataParam::PM_SYNCHRON_STR_MODE: iNumBitsTotal = 12 + 16 /* TEST */ /* + application data TODO! */; break; case CDataParam::PM_PACKET_MODE: iNumBitsTotal = 20 + 16 /* TEST */ /* + application data TODO! */; break; } /* Init return vector (storing this data block) */ vecbiData.Init(iNumBitsTotal + NUM_BITS_HEADER_SDC); vecbiData.ResetBitAccess(); /* Length of the body, excluding the initial 4 bits ("- 4"), measured in bytes ("/ 8") */ vecbiData.Enqueue((uint32_t) (iNumBitsTotal - 4) / 8, 7); /* Version flag (not used in this implementation) */ vecbiData.Enqueue((uint32_t) 0, 1); /* Data entity type */ vecbiData.Enqueue((uint32_t) 05, 4); /* Type 05 */ /* Actual body ---------------------------------------------------------- */ /* Short Id */ vecbiData.Enqueue((uint32_t) ServiceID, 2); /* Stream Id */ vecbiData.Enqueue((uint32_t) Parameter.Service[ServiceID].DataParam. iStreamID, 2); /* Packet mode indicator */ switch (Parameter.Service[ServiceID].DataParam.ePacketModInd) { case CDataParam::PM_SYNCHRON_STR_MODE: vecbiData.Enqueue(0 /* 0 */, 1); /* Descriptor */ vecbiData.Enqueue((uint32_t) 0, 7); break; case CDataParam::PM_PACKET_MODE: vecbiData.Enqueue(1 /* 1 */, 1); /* Descriptor */ /* Data unit indicator */ switch (Parameter.Service[ServiceID].DataParam.eDataUnitInd) { case CDataParam::DU_SINGLE_PACKETS: vecbiData.Enqueue(0 /* 0 */, 1); break; case CDataParam::DU_DATA_UNITS: vecbiData.Enqueue(1 /* 1 */, 1); break; } /* Packet Id */ vecbiData.Enqueue( (uint32_t) Parameter.Service[ServiceID].DataParam.iPacketID, 2); /* Application domain */ switch (Parameter.Service[ServiceID].DataParam.eAppDomain) { case CDataParam::AD_DRM_SPEC_APP: vecbiData.Enqueue(0 /* 0000 */, 4); break; case CDataParam::AD_DAB_SPEC_APP: vecbiData.Enqueue(1 /* 0001 */, 4); break; default: throw CGenErr("bad application domain in SDC preparation"); } /* Packet length */ vecbiData.Enqueue( (uint32_t) Parameter.Service[ServiceID].DataParam.iPacketLen, 8); break; } /* Application data */ // Not used // TEST /* Fixed implementation for MOTSlideshow application which is the one and only supported application right now. TODO */ /* rfu */ vecbiData.Enqueue((uint32_t) 0, 5); /* User application identifier. SlideShow = 2 */ vecbiData.Enqueue((uint32_t) 2, 11); } /******************************************************************************\ * Data entity Type 9 (Audio information data entity) * \******************************************************************************/ void CSDCTransmit::DataEntityType9(CVector<_BINARY>& vecbiData, int ServiceID, CParameter& Parameter) { /* Set total number of bits */ const int iNumBitsTotal = 20; /* Init return vector (storing this data block) */ vecbiData.Init(iNumBitsTotal + NUM_BITS_HEADER_SDC); vecbiData.ResetBitAccess(); /* Length of the body, excluding the initial 4 bits ("- 4"), measured in bytes ("/ 8") */ vecbiData.Enqueue((uint32_t) (iNumBitsTotal - 4) / 8, 7); /* Version flag (not used in this implementation) */ vecbiData.Enqueue((uint32_t) 0, 1); /* Data entity type */ vecbiData.Enqueue((uint32_t) 9, 4); /* Type 09 */ /* Actual body ---------------------------------------------------------- */ /* Short Id */ vecbiData.Enqueue((uint32_t) ServiceID, 2); /* Stream Id */ vecbiData.Enqueue((uint32_t) Parameter.Service[ServiceID].AudioParam. iStreamID, 2); /* Audio coding */ switch (Parameter.Service[ServiceID].AudioParam.eAudioCoding) { case CAudioParam::AC_AAC: vecbiData.Enqueue(0 /* 00 */, 2); break; case CAudioParam::AC_CELP: vecbiData.Enqueue(1 /* 01 */, 2); break; case CAudioParam::AC_HVXC: vecbiData.Enqueue(2 /* 10 */, 2); break; } /* SBR flag */ switch (Parameter.Service[ServiceID].AudioParam.eSBRFlag) { case CAudioParam::SB_NOT_USED: vecbiData.Enqueue(0 /* 0 */, 1); break; case CAudioParam::SB_USED: vecbiData.Enqueue(1 /* 1 */, 1); break; } /* Audio mode */ switch (Parameter.Service[ServiceID].AudioParam.eAudioCoding) { case CAudioParam::AC_AAC: /* Channel type */ switch (Parameter.Service[ServiceID].AudioParam.eAudioMode) { case CAudioParam::AM_MONO: vecbiData.Enqueue(0 /* 00 */, 2); break; case CAudioParam::AM_P_STEREO: vecbiData.Enqueue(1 /* 01 */, 2); break; case CAudioParam::AM_STEREO: vecbiData.Enqueue(2 /* 10 */, 2); break; } break; case CAudioParam::AC_CELP: /* rfa */ vecbiData.Enqueue((uint32_t) 0, 1); /* CELP_CRC */ switch (Parameter.Service[ServiceID].AudioParam.bCELPCRC) { case false: vecbiData.Enqueue(0 /* 0 */, 1); break; case true: vecbiData.Enqueue(1 /* 1 */, 1); break; } break; case CAudioParam::AC_HVXC: /* HVXC_rate */ switch (Parameter.Service[ServiceID].AudioParam.eHVXCRate) { case CAudioParam::HR_2_KBIT: vecbiData.Enqueue(0 /* 0 */, 1); break; case CAudioParam::HR_4_KBIT: vecbiData.Enqueue(1 /* 1 */, 1); break; } /* HVXC CRC */ switch (Parameter.Service[ServiceID].AudioParam.bHVXCCRC) { case false: vecbiData.Enqueue(0 /* 0 */, 1); break; case true: vecbiData.Enqueue(1 /* 1 */, 1); break; } break; } /* Audio sampling rate */ switch (Parameter.Service[ServiceID].AudioParam.eAudioSamplRate) { case CAudioParam::AS_8_KHZ: vecbiData.Enqueue(0 /* 000 */, 3); break; case CAudioParam::AS_12KHZ: vecbiData.Enqueue(1 /* 001 */, 3); break; case CAudioParam::AS_16KHZ: vecbiData.Enqueue(2 /* 010 */, 3); break; case CAudioParam::AS_24KHZ: vecbiData.Enqueue(3 /* 011 */, 3); break; } /* Text flag */ switch (Parameter.Service[ServiceID].AudioParam.bTextflag) { case false: vecbiData.Enqueue(0 /* 0 */, 1); break; case true: vecbiData.Enqueue(1 /* 1 */, 1); break; } /* Enhancement flag */ switch (Parameter.Service[ServiceID].AudioParam.bEnhanceFlag) { case false: vecbiData.Enqueue(0 /* 0 */, 1); break; case true: vecbiData.Enqueue(1 /* 1 */, 1); break; } /* Coder field */ if (Parameter.Service[ServiceID].AudioParam. eAudioCoding == CAudioParam::AC_CELP) { /* CELP index */ vecbiData.Enqueue( (uint32_t) Parameter.Service[ServiceID].AudioParam.iCELPIndex, 5); } else { /* rfa 5 bit */ vecbiData.Enqueue((uint32_t) 0, 5); } /* rfa 1 bit */ vecbiData.Enqueue((uint32_t) 0, 1); } qsstv_8.2.12/qsstv/drmtx/common/datadecoding/DABMOT.cpp000664 001750 001750 00000163025 12440612574 022670 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer, Andrea Russo, Doyle Richard, Julian Cable * * Adapted for ham sstv use Ties Bos PA0MBO * * Description: * DAB MOT interface implementation * * 12/22/2003 Doyle Richard * - Header extension decoding * 10/13/2005 Andrea Russo * - Broadcast WebSite application * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "DABMOT.h" #include "../util/Utilities.h" #include #include #include #include #include "drmtx/drmtransmitter.h" #if HAVE_LIBZ #include #else #ifdef HAVE_LIBFREEIMAGE # include #endif #endif #define RUNINLEN 15 #define RUNOUTLEN 10 static int bsrTransportId=2; using namespace std; /* Implementation *************************************************************/ ostream & operator<<(ostream & out, CDateAndTime & d) { d.dump(out); return out; } ostream & operator<<(ostream & out, CMOTObject & o) { o.dump(out); return out; } ostream & operator<<(ostream & out, CMOTDirectory & o) { o.dump(out); return out; } /******************************************************************************\ * Encoder * \******************************************************************************/ void CMOTDABEnc::SetMOTObject(CMOTObject & NewMOTObject,int bytesAvailable) { size_t i; size_t k; CMOTObjectRaw MOTObjectRaw; unsigned char xorfname , addfname ; /* Get some necessary parameters of object */ const int iPicSizeBits = NewMOTObject.vecbRawData.Size(); const int iPicSizeBytes = iPicSizeBits / SIZEOF__BYTE; const string strFileName = NewMOTObject.strName; /* File name size is restricted (in this implementation) to 128 (2^7) bytes. If file name is longer, cut it. TODO: better solution: set Ext flag in "ContentName" header extension to allow larger file names */ size_t iFileNameSize = strFileName.size(); if (strFileName=="bsr.bin") { bsrTransportId++; bsrTransportId=bsrTransportId%3; txTransportID=bsrTransportId; } else { if (iFileNameSize > 80) // was 128 iFileNameSize = 80; //was 128 // printf("Binnenkomst SetMOTObject file %s \n", strFileName.c_str()); if (iFileNameSize ==0 ) return; /* special hamcode */ xorfname = 0; addfname = 0; for (k=0; k < iFileNameSize ; k++) { xorfname ^= strFileName[k]; addfname += strFileName[k]; addfname ^= (unsigned char) k ; } txTransportID = 256 * (int)addfname + (int) xorfname ; if (txTransportID <= 2) txTransportID += iFileNameSize; } /* end special hamcode */ /* Copy actual raw data of object */ MOTObjectRaw.Body.Init(iPicSizeBits); MOTObjectRaw.Body = NewMOTObject.vecbRawData; /* Get content type and content sub type of object. We use the format string to get these informations about the object */ int iContentType = 2; /* Set default value (general data) was 0 */ int iContentSubType = 1; /* Set default value (jpg) was 0 */ /* Get ending string which declares the type of the file. Make lowercase */ string strFormat; #if defined(_MSC_VER) && (_MSC_VER < 1400) strFormat = _strlwr(_strdup(NewMOTObject.strFormat.c_str())); #else transform(NewMOTObject.strFormat.begin(), NewMOTObject.strFormat.end(), strFormat.begin(), (int (*)(int)) tolower); #endif // printf("DABMOT strFormat is %s \n", strFormat.c_str()); /* gif: 0, image: 2 */ if (strcmp(strFormat.c_str(), "gif") == 0) { iContentType = 2; iContentSubType = 0; } /* jfif: 1, image: 2. Possible endings: jpg, jpeg, jfif jp2 added sep 14 2012 */ if (( strcmp(strFormat.c_str(), "jpg")==0 ) || (strcmp(strFormat.c_str(), "jpeg") == 0) || (strcmp(strFormat.c_str(), "rs1") == 0) || (strcmp(strFormat.c_str(), "rs2") == 0) || (strcmp(strFormat.c_str(), "rs3") == 0) || (strcmp(strFormat.c_str(), "rs4") == 0) || (strcmp(strFormat.c_str(), "jp2") == 0) || (strcmp(strFormat.c_str(), "jfif") == 0)) { iContentType = 2; iContentSubType = 1; } /* bmp: 2, image: 2 */ if (strcmp(strFormat.c_str(),"bmp") == 0) { iContentType = 2; iContentSubType = 2; } /* png: 3, image: 2 */ if (strcmp(strFormat.c_str(),"png") == 0) { iContentType = 2; iContentSubType = 3; } // printf("na de ifs iContentType is %d iContentSubType is %d \n", iContentType, iContentSubType); /* Header --------------------------------------------------------------- */ /* Header size (including header extension) */ const int iHeaderSize = 7 /* Header core */ + 5 /* TriggerTime */ + 3 + iFileNameSize /* ContentName (header + actual name) */ + 2 /* VersionNumber */ ; /* Allocate memory and reset bit access */ MOTObjectRaw.Header.Init(iHeaderSize * SIZEOF__BYTE); MOTObjectRaw.Header.ResetBitAccess(); // printf("DABMOT iHeaderSize %d \n", iHeaderSize); /* BodySize: This 28-bit field, coded as an unsigned binary number, indicates the total size of the body in bytes */ MOTObjectRaw.Header.Enqueue((uint32_t) iPicSizeBytes, 28); /* HeaderSize: This 13-bit field, coded as an unsigned binary number, indicates the total size of the header in bytes */ MOTObjectRaw.Header.Enqueue((uint32_t) iHeaderSize, 13); /* ContentType: This 6-bit field indicates the main category of the body's content */ MOTObjectRaw.Header.Enqueue((uint32_t) iContentType, 6); /* ContentSubType: This 9-bit field indicates the exact type of the body's content depending on the value of the field ContentType */ MOTObjectRaw.Header.Enqueue((uint32_t) iContentSubType, 9); /* Header extension ----------------------------------------------------- */ /* MOT Slideshow application: Only the MOT parameter ContentName is mandatory and must be used for each slide object that will be handled by the MOT decoder and the memory management of the Slide Show terminal */ /* TriggerTime: This parameter specifies the time for when the presentation takes place. The TriggerTime activates the object according to its ContentType. The value of the parameter field is coded in the UTC format */ /* PLI (Parameter Length Indicator): This 2-bit field describes the total length of the associated parameter. In this case: 1 0 total parameter length = 5 bytes; length of DataField is 4 bytes */ MOTObjectRaw.Header.Enqueue((uint32_t) 2, 2); /* ParamId (Parameter Identifier): This 6-bit field identifies the parameter. 1 0 1 (dec: 5) -> TriggerTime */ MOTObjectRaw.Header.Enqueue((uint32_t) 5, 6); /* Validity flag = 0: "Now", MJD and UTC shall be ignored and be set to 0. Set MJD and UTC to zero. UTC flag is also zero -> short form */ MOTObjectRaw.Header.Enqueue((uint32_t) 0, 32); /* VersionNumber: If several versions of an object are transferred, this parameter indicates its VersionNumber. The parameter value is coded as an unsigned binary number, starting at 0 and being incremented by 1 modulo 256 each time the version changes. If the VersionNumber differs, the content of the body was modified */ /* PLI 0 1 total parameter length = 2 bytes, length of DataField is 1 byte */ MOTObjectRaw.Header.Enqueue((uint32_t) 1, 2); /* ParamId (Parameter Identifier): This 6-bit field identifies the parameter. 1 1 0 (dec: 6) -> VersionNumber */ MOTObjectRaw.Header.Enqueue((uint32_t) 6, 6); /* Version number data field */ MOTObjectRaw.Header.Enqueue((uint32_t) 0, 8); /* ContentName: The DataField of this parameter starts with a one byte field, comprising a 4-bit character set indicator (see table 3) and a 4-bit Rfa field. The following character field contains a unique name or identifier for the object. The total number of characters is determined by the DataFieldLength indicator minus one byte */ /* PLI 1 1 total parameter length depends on the DataFieldLength indicator */ MOTObjectRaw.Header.Enqueue((uint32_t) 3, 2); /* ParamId (Parameter Identifier): This 6-bit field identifies the parameter. 1 1 0 0 (dec: 12) -> ContentName */ MOTObjectRaw.Header.Enqueue((uint32_t) 12, 6); /* Ext (ExtensionFlag): This 1-bit field specifies the length of the DataFieldLength Indicator. 0: the total parameter length is derived from the next 7 bits */ MOTObjectRaw.Header.Enqueue((uint32_t) 0, 1); /* DataFieldLength Indicator: This field specifies as an unsigned binary number the length of the parameter's DataField in bytes. The length of this field is either 7 or 15 bits, depending on the setting of the ExtensionFlag */ MOTObjectRaw.Header.Enqueue((uint32_t) (1 /* header */ + iFileNameSize /* actual data */), 7); // printf("iFileNameSize is %d\n", iFileNameSize); // if (iFileNameSize ==0) return ; /* Character set indicator (0 0 0 0 complete EBU Latin based repertoire) */ MOTObjectRaw.Header.Enqueue((uint32_t) 0, 4); /* Rfa 4 bits */ MOTObjectRaw.Header.Enqueue((uint32_t) 0, 4); /* Character field */ for (i = 0; i < iFileNameSize; i++) MOTObjectRaw.Header.Enqueue((uint32_t) strFileName[i], 8); /* Generate segments ---------------------------------------------------- */ /* Header (header should not be partitioned! TODO) */ const int iPartiSizeHeader = 98; /* Bytes */// TEST was 100 pa0mbo // printf("Voor partitioning header \n"); PartitionUnits(MOTObjectRaw.Header, MOTObjSegments.vvbiHeader,iPartiSizeHeader); /* Body */ //ON4QZ change to better fit in NumDecodeBits PartitionUnits(MOTObjectRaw.Body, MOTObjSegments.vvbiBody, bytesAvailable-14); } void CMOTDABEnc::PartitionUnits(CVector < _BINARY > &vecbiSource, CVector < CVector < _BINARY > >&vecbiDest, const int iPartiSize) { int i, j; int iActSegSize; /* Divide the generated units in partitions */ const int iSourceSize = vecbiSource.Size() / SIZEOF__BYTE; const int iNumSeg = (int) ceil((_REAL) iSourceSize / iPartiSize); /* Bytes */ iNumSegStore = iNumSeg; const int iSizeLastSeg = iSourceSize - (int) floor((_REAL) iSourceSize / iPartiSize) * iPartiSize; /* printf("In PartitionUnits iParti %d iSource %d iNumSeg %d iSizlast %d\n", iPartiSize, iSourceSize, iNumSeg, iSizeLastSeg); */ /* Init memory for destination vector, reset bit access of source */ vecbiDest.Init(iNumSeg); vecbiSource.ResetBitAccess(); for (i = 0; i < iNumSeg; i++) { /* All segments except the last one must have the size "iPartSizeHeader". If "iSizeLastSeg" is =, the source data size is a multiple of the partitions size. In this case, all units have the same size (-> "|| (iSizeLastSeg == 0)") */ if ((i < iNumSeg - 1) || (iSizeLastSeg == 0)) iActSegSize = iPartiSize; else iActSegSize = iSizeLastSeg; /* Add segment data ------------------------------------------------- */ /* Header */ /* Allocate memory for body data and segment header bits (16) */ vecbiDest[i].Init(iActSegSize * SIZEOF__BYTE + 16); vecbiDest[i].ResetBitAccess(); /* Segment header */ /* RepetitionCount: This 3-bit field indicates, as an unsigned binary number, the remaining transmission repetitions for the current object. In our current implementation, no repetitions used. TODO */ vecbiDest[i].Enqueue((uint32_t) 0, 3); /* SegmentSize: This 13-bit field, coded as an unsigned binary number, indicates the size of the segment data field in bytes */ vecbiDest[i].Enqueue((uint32_t) iActSegSize, 13); /* Body */ for (j = 0; j < iActSegSize * SIZEOF__BYTE; j++) vecbiDest[i].Enqueue(vecbiSource.Separate(1), 1); } } void CMOTDABEnc::GenMOTObj(CVector < _BINARY > &vecbiData, CVector < _BINARY > &vecbiSeg, const _BOOLEAN bHeader, const int iSegNum, const int iTranspID, const _BOOLEAN bLastSeg) { int i; CCRC CRCObject; // printf("GenMOTObj iTranspID %d SIZEOF__BYTE %d\n", iTranspID, SIZEOF__BYTE); /* Standard settings for this implementation */ const _BOOLEAN bCRCUsed = true; /* CRC */ const _BOOLEAN bSegFieldUsed = true; /* segment field */ const _BOOLEAN bUsAccFieldUsed = true; /* user access field */ const _BOOLEAN bTransIDFieldUsed = true; /* transport ID field */ unsigned char testdata[10000]; double ownchecksum; /* Total length of object in bits */ int iTotLenMOTObj = 16 /* group header */ ; if (bSegFieldUsed == true) iTotLenMOTObj += 16; if (bUsAccFieldUsed == true) { iTotLenMOTObj += 8; if (bTransIDFieldUsed == true) iTotLenMOTObj += 16; } // printf("DABMOT vecbiSrg.size %d\n", vecbiSeg.Size()); iTotLenMOTObj += vecbiSeg.Size(); if (bCRCUsed == true) iTotLenMOTObj += 16; /* Init data vector */ vecbiData.Init(iTotLenMOTObj); vecbiData.ResetBitAccess(); /* MSC data group header ------------------------------------------------ */ /* Extension flag: this 1-bit flag shall indicate whether the extension field is present, or not. Not used right now -> 0 */ vecbiData.Enqueue((uint32_t) 0, 1); /* CRC flag: this 1-bit flag shall indicate whether there is a CRC at the end of the MSC data group */ if (bCRCUsed == true) vecbiData.Enqueue((uint32_t) 1, 1); else vecbiData.Enqueue((uint32_t) 0, 1); /* Segment flag: this 1-bit flag shall indicate whether the segment field is present, or not */ if (bSegFieldUsed == true) vecbiData.Enqueue((uint32_t) 1, 1); else vecbiData.Enqueue((uint32_t) 0, 1); /* User access flag: this 1-bit flag shall indicate whether the user access field is present, or not. We always use this field -> 1 */ if (bUsAccFieldUsed == true) vecbiData.Enqueue((uint32_t) 1, 1); else vecbiData.Enqueue((uint32_t) 0, 1); /* Data group type: this 4-bit field shall define the type of data carried in the data group data field. Data group types: 3: MOT header information 4: MOT data */ if (bHeader == true) vecbiData.Enqueue((uint32_t) 3, 4); else vecbiData.Enqueue((uint32_t) 4, 4); /* Continuity index: the binary value of this 4-bit field shall be incremented each time a MSC data group of a particular type, with a content different from that of the immediately preceding data group of the same type, is transmitted */ if (bHeader == true) { vecbiData.Enqueue((uint32_t) iContIndexHeader, 4); /* Increment modulo 16 */ iContIndexHeader++; if (iContIndexHeader == 16) iContIndexHeader = 0; } else { vecbiData.Enqueue((uint32_t) iContIndexBody, 4); /* Increment modulo 16 */ iContIndexBody++; if (iContIndexBody == 16) iContIndexBody = 0; } /* Repetition index: the binary value of this 4-bit field shall signal the remaining number of repetitions of a MSC data group with the same data content, occurring in successive MSC data groups of the same type. No repetition used in this implementation right now -> 0, TODO */ vecbiData.Enqueue((uint32_t) 0, 4); /* Extension field: this 16-bit field shall be used to carry the Data Group Conditional Access (DGCA) when general data or MOT data uses conditional access (Data group types 0010 and 0101, respectively). The DGCA contains the Initialization Modifier (IM) and additional Conditional Access (CA) information. For other Data group types, the Extension field is reserved for future additions to the Data group header. Extension field is not used in this implementation! */ /* Session header ------------------------------------------------------- */ /* Segment field */ if (bSegFieldUsed == true) { /* Last: this 1-bit flag shall indicate whether the segment number field is the last or whether there are more to be transmitted */ if (bLastSeg == true) vecbiData.Enqueue((uint32_t) 1, 1); else vecbiData.Enqueue((uint32_t) 0, 1); /* Segment number: this 15-bit field, coded as an unsigned binary number (in the range 0 to 32767), shall indicate the segment number. NOTE: The first segment is numbered 0 and the segment number is incremented by one at each new segment */ // printf("GenMOTObj blastSeg %d, iSegNum %d \n", bLastSeg, iSegNum); vecbiData.Enqueue((uint32_t) iSegNum, 15); } /* User access field */ if (bUsAccFieldUsed == true) { /* Rfa (Reserved for future addition): this 3-bit field shall be reserved for future additions */ vecbiData.Enqueue((uint32_t) 0, 3); /* Transport Id flag: this 1-bit flag shall indicate whether the Transport Id field is present, or not */ if (bTransIDFieldUsed == true) vecbiData.Enqueue((uint32_t) 1, 1); else vecbiData.Enqueue((uint32_t) 0, 1); /* Length indicator: this 4-bit field, coded as an unsigned binary number (in the range 0 to 15), shall indicate the length n in bytes of the Transport Id and End user address fields. We do not use end user address field, only transport ID -> 2 */ if (bTransIDFieldUsed == true) vecbiData.Enqueue((uint32_t) 2, 4); else vecbiData.Enqueue((uint32_t) 0, 4); /* Transport Id (Identifier): this 16-bit field shall uniquely identify one data object (file and header information) from a stream of such objects, It may be used to indicate the object to which the information carried in the data group belongs or relates */ if (bTransIDFieldUsed == true) vecbiData.Enqueue((uint32_t) iTranspID, 16); } /* MSC data group data field -------------------------------------------- */ vecbiSeg.ResetBitAccess(); for (i = 0; i < vecbiSeg.Size(); i++) vecbiData.Enqueue(vecbiSeg.Separate(1), 1); /* MSC data group CRC --------------------------------------------------- */ /* The data group CRC shall be a 16-bit CRC word calculated on the data group header, the session header and the data group data field. The generation shall be based on the ITU-T Recommendation X.25. At the beginning of each CRC word calculation, all shift register stage contents shall be initialized to "1". The CRC word shall be complemented (1's complement) prior to transmission */ if (bCRCUsed == true) { /* Reset bit access */ vecbiData.ResetBitAccess(); /* Calculate the CRC and put it at the end of the segment */ CRCObject.Reset(16); // printf("iTotLenMOTObj = %d \n", iTotLenMOTObj); /* "byLengthBody" was defined in the header */ for (i = 0; i < ((iTotLenMOTObj / SIZEOF__BYTE) - 2) /* CRC */ ; i++) CRCObject.AddByte((_BYTE) vecbiData.Separate(SIZEOF__BYTE)); /* Now, pointer in "enqueue"-function is back at the same place, add CRC */ vecbiData.Enqueue(CRCObject.GetCRC(), 16); // printf("sending crc16 from DABMOT %x iSegNum %d \n", CRCObject.GetCRC(), iSegNum); vecbiData.ResetBitAccess(); /* extra debugging code pa0mbo */ vecbiData.ResetBitAccess(); CRCObject.Reset(16); for (i = 0; i < ((iTotLenMOTObj / SIZEOF__BYTE)) ; i++) { testdata[i] = ((_BYTE) vecbiData.Separate(SIZEOF__BYTE)); CRCObject.AddByte(testdata[i]) ; // printf(" %d %x\n", i, testdata[i]); } CRCObject.crc16_bytewise( &ownchecksum, testdata, iTotLenMOTObj/SIZEOF__BYTE); // ON4QZ divided by SIZEOF__BYTE // printf("Own CRC is %x \n", (int)ownchecksum); // printf("crc16 from DABMOT %x iSegNum %d \n", CRCObject.GetCRC(), iSegNum); /* */ vecbiData.ResetBitAccess(); } } void CMOTDABEnc::prepareSegmentList(unsigned int repetition) // ON4QZ { int i,k,m,counter; unsigned int j; int numHeaderSegments=MOTObjSegments.vvbiHeader.Size(); int numBodySegments=MOTObjSegments.vvbiBody.Size(); segmentList.clear(); for(j=0;j &vecbiNewData) { bool bLastSegment; int segmentNumber; int headerNumber; segmentNumber=segmentList.at(segmentListIdx); if(segmentNumber<0) { //its a header headerNumber=-1-segmentNumber; if((headerNumber+1)==MOTObjSegments.vvbiHeader.Size()) bLastSegment=true; else bLastSegment=false; GenMOTObj(vecbiNewData, MOTObjSegments.vvbiHeader[headerNumber],true, headerNumber, txTransportID, bLastSegment); } else { //its a body segment if ((segmentNumber+1) == MOTObjSegments.vvbiBody.Size()) bLastSegment = true; else bLastSegment = false; GenMOTObj(vecbiNewData,MOTObjSegments.vvbiBody[segmentNumber], false,segmentNumber, txTransportID, bLastSegment); } segmentListIdx++; if(segmentListIdx==segmentList.count()) { segmentListIdx=0; return true; } return false; } //_BOOLEAN CMOTDABEnc::GetDataGroup(CVector < _BINARY > &vecbiNewData) //{ // _BOOLEAN bLastSegment; // /* Init return value. Is overwritten in case the object is ready */ // _BOOLEAN bObjectDone = false; // if (bFirstRound == true) // { // if (bCurSegHeader == true) // { // /* Check if this is last segment */ // if (iSegmCntHeader == MOTObjSegments.vvbiHeader.Size() - 1) bLastSegment = true; // else bLastSegment = false; // /* Generate MOT object for header */ // GenMOTObj(vecbiNewData, MOTObjSegments.vvbiHeader[iSegmCntHeader],true, iSegmCntHeader, txTransportID, bLastSegment); // addToLog(QString("FirstRound iSegmCntheader %1 blastseg %2 transportID %3").arg(iSegmCntHeader).arg(bLastSegment).arg(txTransportID),LOGDRMTXMOT); // iSegmCntHeader++; // if (iSegmCntHeader == MOTObjSegments.vvbiHeader.Size()) // { // iSegmCntBody = 0; // Reset counter for body // bCurSegHeader = false; // Header is ready, transmit body now // } // } // else // { // /* Check that body size is not zero */ // if (iSegmCntBody < MOTObjSegments.vvbiBody.Size()) // { // /* Check if this is last segment */ // if (iSegmCntBody == RUNINLEN ) bLastSegment = true; // else bLastSegment = false; // if (bLastSegment) // { // /* Generate MOT object for Body */ // GenMOTObj(vecbiNewData,MOTObjSegments.vvbiBody[iNumSegStore-1], false,iNumSegStore-1, txTransportID, bLastSegment); // addToLog(QString("FirstRound Generated MOTObj for seg %1 pseudolast").arg(iNumSegStore-1),LOGDRMTXMOT); // iSegmCntBody= 0; // iSegmCntHeader =0; // bCurSegHeader = true; // bFirstRound = false ; // } // else // { // /* Generate MOT object for Body */ // GenMOTObj(vecbiNewData,MOTObjSegments.vvbiBody[iSegmCntBody], false,iSegmCntBody, txTransportID, bLastSegment); // addToLog(QString("FirstRound Generated MOTObj for seg %1 ").arg(iSegmCntBody),LOGDRMTXMOT); // } // iSegmCntBody++; // } // if (iSegmCntBody == MOTObjSegments.vvbiBody.Size()) // { // iSegmCntHeader = 0; // Reset counter for header // bCurSegHeader = true; // Body is ready, transmit header from next object // bFirstRound = false ; // } // runInCnt++; // } // } // else // not first run // { // if (bCurSegHeader == true) // { // if (iSegmCntHeader == MOTObjSegments.vvbiHeader.Size() - 1) // { // bLastSegment = true; // Check if this is last segment // } // else bLastSegment = false; // /* Generate MOT object for header */ // GenMOTObj(vecbiNewData, MOTObjSegments.vvbiHeader[iSegmCntHeader], true, iSegmCntHeader, txTransportID, bLastSegment); // addToLog(QString("iSegmCntheader %1 blastseg %2").arg(iSegmCntHeader).arg(bLastSegment),LOGDRMTXMOT); // iSegmCntHeader++; // if (iSegmCntHeader == MOTObjSegments.vvbiHeader.Size()) // { // iSegmCntBody = 0; // Reset counter for body // bCurSegHeader = false; // Header is ready, transmit body now // } // } // else // { // if (iSegmCntBody < MOTObjSegments.vvbiBody.Size()) // Check that body size is not zero // { // if (iSegmCntBody == MOTObjSegments.vvbiBody.Size() - 1) // { // bLastSegment = true; // Check if this is last segment // } // else bLastSegment = false; // if (bLastSegment) // { // /* Generate MOT object for Body */ // GenMOTObj(vecbiNewData, MOTObjSegments.vvbiBody[iSegmCntBody], false, iNumSegStore-1, txTransportID, bLastSegment); // addToLog(QString("Generated MOTObj for seg %1 last").arg(iNumSegStore-1),LOGDRMTXMOT); // } // else // { // /* Generate MOT object for Body */ // GenMOTObj(vecbiNewData, MOTObjSegments.vvbiBody[iSegmCntBody], false, iSegmCntBody, txTransportID, bLastSegment); // addToLog(QString("Generated MOTObj for seg %1 of %2").arg(iSegmCntBody).arg( iNumSegStore),LOGDRMTXMOT); // } //// printf("GetDataGroup body situation 2nd iSegmCntBody %d iSegNumStore %d blastseg %d\n", iSegmCntBody, iNumSegStore, bLastSegment); // iSegmCntBody++; // } // if (iSegmCntBody == MOTObjSegments.vvbiBody.Size()) // { // iSegmCntHeader = 0; // Reset counter for header // bCurSegHeader = true; // Body is ready, transmit header from next object //// txTransportID++; // /* Signal that old object is done */ // bObjectDone = true; // } // } // } // /* Return status of object transmission */ // return bObjectDone; //} _REAL CMOTDABEnc::GetProgPerc() const { // Get percentage of processed data of current object. _REAL tussenresult; const int iTotNumSeg = MOTObjSegments.vvbiHeader.Size() + MOTObjSegments.vvbiBody.Size(); tussenresult = ((_REAL) iSegmCntBody + (_REAL) iSegmCntHeader) / iTotNumSeg; return tussenresult; } void CMOTDABEnc::Reset() { bFirstRound = true ; runInCnt=0; /* Reset continuity indices */ iContIndexHeader = 0; iContIndexBody = 0; txTransportID = 0; /* Init counter for segments */ iSegmCntHeader = 0; iSegmCntBody = 0; /* Init flag which shows what is currently generated, header or body */ bCurSegHeader = true; /* Start with header */ /* Add a "null object" so that at least one valid object can be processed */ CMOTObject NullObject; SetMOTObject(NullObject,154); } /******************************************************************************\ * Decoder * \******************************************************************************/ _BOOLEAN CMOTDABDec::NewObjectAvailable() { return qiNewObjects.empty() == false; } void CMOTDABDec::GetNextObject(CMOTObject & NewMOTObject) { if (!qiNewObjects.empty()) { TTransportID firstNew = qiNewObjects.front(); qiNewObjects.pop(); NewMOTObject = MOTCarousel[firstNew]; } else { fprintf(stderr, "GetObject called when queue empty\n"); fflush(stderr); } } void CMOTDABDec::DeliverIfReady(TTransportID TransportID) { CMOTObject & o = MOTCarousel[TransportID]; if ((!o.bComplete) && o.bHasHeader && o.Body.Ready()) { o.bComplete = true; if (o.Body.IsZipped()) { if (o.Body.uncompress() == false) /* Can't unzip so change the filename */ o.strName = string(o.strName.c_str()) + ".gz"; } //cerr << o << endl;; qiNewObjects.push(TransportID); } } void CMOTDABDec::AddDataUnit(CVector < _BINARY > &vecbiNewData) { int iLenGroupDataField; CCRC CRCObject; _BOOLEAN bCRCOk; int iSegmentNum; _BINARY biLastFlag; _BINARY btxTransportIDFlag = 0; int iLenIndicat; int iSegmentSize; TTransportID TransportID = -1; /* Get length of data unit */ iLenGroupDataField = vecbiNewData.Size(); /* CRC check ------------------------------------------------------------ */ /* We do the CRC check at the beginning no matter if it is used or not since we have to reset bit access for that */ /* Reset bit extraction access */ vecbiNewData.ResetBitAccess(); /* Check the CRC of this packet */ CRCObject.Reset(16); /* "- 2": 16 bits for CRC at the end */ for (size_t i = 0; i < size_t(iLenGroupDataField / SIZEOF__BYTE) - 2; i++) CRCObject.AddByte((_BYTE) vecbiNewData.Separate(SIZEOF__BYTE)); bCRCOk = CRCObject.CheckCRC(vecbiNewData.Separate(16)); /* MSC data group header ------------------------------------------------ */ /* Reset bit extraction access */ vecbiNewData.ResetBitAccess(); /* Extension flag */ const _BINARY biExtensionFlag = (_BINARY) vecbiNewData.Separate(1); /* CRC flag */ const _BINARY biCRCFlag = (_BINARY) vecbiNewData.Separate(1); /* Segment flag */ const _BINARY biSegmentFlag = (_BINARY) vecbiNewData.Separate(1); /* User access flag */ const _BINARY biUserAccFlag = (_BINARY) vecbiNewData.Separate(1); /* Data group type */ const int iDataGroupType = (int) vecbiNewData.Separate(4); /* Continuity index (not yet used) */ vecbiNewData.Separate(4); /* Repetition index (not yet used) */ vecbiNewData.Separate(4); /* Extension field (not used) */ if (biExtensionFlag == true) vecbiNewData.Separate(16); /* Session header ------------------------------------------------------- */ /* Segment field */ if (biSegmentFlag == true) { /* Last */ biLastFlag = (_BINARY) vecbiNewData.Separate(1); /* Segment number */ iSegmentNum = (int) vecbiNewData.Separate(15); } else { biLastFlag = 0; iSegmentNum = 0; } /* User access field */ if (biUserAccFlag == true) { /* Rfa (Reserved for future addition) */ vecbiNewData.Separate(3); /* Transport Id flag */ btxTransportIDFlag = (_BINARY) vecbiNewData.Separate(1); /* Length indicator */ iLenIndicat = (int) vecbiNewData.Separate(4); /* Transport Id */ if (btxTransportIDFlag == 1) TransportID = (int) vecbiNewData.Separate(16); /* End user address field (not used) */ int iLenEndUserAddress; if (btxTransportIDFlag == 1) iLenEndUserAddress = (iLenIndicat - 2) * SIZEOF__BYTE; else iLenEndUserAddress = iLenIndicat * SIZEOF__BYTE; vecbiNewData.Separate(iLenEndUserAddress); } //cerr << "MOT: new data unit, tid " << TransportID << " CRC " << bCRCOk << " DG" << iDataGroupType << endl; /* MSC data group data field -------------------------------------------- */ /* If CRC is not used enter if-block, if CRC flag is used, it must be ok to enter the if-block */ if ((biCRCFlag == false) || ((biCRCFlag == true) && (bCRCOk == true))) { /* Segmentation header ---------------------------------------------- */ /* Repetition count (not used) */ int repetition_count = vecbiNewData.Separate(3); (void)repetition_count; /* silence warnings */ /* Segment size */ iSegmentSize = (int) vecbiNewData.Separate(13); /* Get MOT data ----------------------------------------------------- */ /* Segment number and user access data is needed */ if ((biSegmentFlag == true) && (biUserAccFlag == true) && (btxTransportIDFlag == 1)) { /* don't make any assumptions about the order or interleaving of Data Groups from the same or different objects. */ /* Distinguish between header and body */ if (iDataGroupType == 3) { /* Header information, i.e. the header core and the header extension, are transferred in Data Group type 3 */ if (MOTmode != headerMode) { /* mode change, throw away any directory */ MOTDirectory.Reset(); //cout << "Reset " << MOTDirectory << endl; } MOTmode = headerMode; /* in theory, there can be only one header at a time, but lets be a bit more tolerant */ if (MOTHeaders.count(TransportID) == 0) { CBitReassembler o; MOTHeaders[TransportID] = o; } CBitReassembler & o = MOTHeaders[TransportID]; o.AddSegment(vecbiNewData, iSegmentSize, iSegmentNum, biLastFlag); /* if the header just got complete, see if the body is complete */ if (o.Ready()) { MOTCarousel[TransportID].AddHeader(o.vecData); DeliverIfReady(TransportID); } } else if (iDataGroupType == 4) { /* Body data segments are transferred in Data Group type 4 */ /* don't worry about modes, just store everything in the carousel defer decisions until the object and either header or directory are complete */ map < TTransportID, CMOTObject >::iterator o = MOTCarousel.find(TransportID); if (o == MOTCarousel.end()) { /* we never saw this before */ MOTCarousel[TransportID].TransportID = TransportID; o = MOTCarousel.find(TransportID); } /* is this an old object we have completed? */ if (o->second.bComplete == false) { o->second.Body.AddSegment(vecbiNewData, iSegmentSize, iSegmentNum, biLastFlag); } else { /* discard the segment */ vecbiNewData.Separate(iSegmentSize * SIZEOF__BYTE); } /* if the body just got complete we can see if its ready to deliver */ DeliverIfReady(TransportID); } else if (iDataGroupType == 6) /* MOT directory */ { //cout << "DG6" << endl; if (MOTmode != directoryMode) { /* mode change, throw away any headers */ MOTHeaders.clear(); MOTDirectory.TransportID = -1; /* forced reset */ MOTmode = directoryMode; //cout << "Reset " << MOTDirectory << endl; } /* The carousel is changing */ if (MOTDirectory.TransportID != TransportID) { /* we never got all the previous directory */ cout << " we never got all the previous directory " << TransportID << ", " << MOTDirectory. TransportID << endl; MOTDirectory.Reset(); MOTDirectory.TransportID = TransportID; MOTDirectoryEntity.Reset(); MOTDirComprEntity.Reset(); } if ((MOTDirectory.TransportID != TransportID) || ((MOTDirectory.TransportID == TransportID) && (!MOTDirectoryEntity.Ready()))) { /* Handle the new segment */ /* rely on the Add routine to check duplicates, set ready, etc. */ MOTDirectoryEntity.AddSegment(vecbiNewData, iSegmentSize, iSegmentNum, biLastFlag); /* have we got the full directory ? */ if (MOTDirectoryEntity.Ready()) { //cout << "Ready " << MOTDirectory << endl; ProcessDirectory(MOTDirectoryEntity); MOTDirectory.TransportID = TransportID; } /* END IF HAVE ALL OF THE NEW DIRECTORY */ } else { vecbiNewData.Separate(iSegmentSize * SIZEOF__BYTE); } } /* of DG type 6 */ #if 0 //Commented until we can test it with a real compressed directory else if (iDataGroupType == 7) /* MOT directory compressed */ { if (MOTmode != directoryMode) { /* mode change, throw away any headers */ MOTHeaders.clear(); MOTDirectory.TransportID = -1; /* forced reset */ MOTmode = directoryMode; } /* The carousel is changing */ if (MOTDirectory.TransportID != TransportID) { /* we never got all the previous directory */ MOTDirectory.Reset(); MOTDirectory.TransportID = TransportID; MOTDirectoryEntity.Reset(); MOTDirComprEntity.Reset(); } if ((MOTDirectory.TransportID != TransportID) || ((MOTDirectory.TransportID == TransportID) && (!MOTDirComprEntity.Ready()))) { /* Handle the new segment */ /* rely on the Add routine to check duplicates, set ready, etc. */ MOTDirComprEntity.AddSegment(vecbiNewData, iSegmentSize, iSegmentNum, biLastFlag); /* have we got the full directory ? */ if (MOTDirComprEntity.Ready()) { /* uncompress data and extract directory */ /* Compression Flag - must be 1 */ const _BOOLEAN bCompressionFlag = MOTDirComprEntity.vecData. Separate(1) ? true : false; /* rfu */ MOTDirComprEntity.vecData.Separate(1); /* EntitySize */ MOTDirComprEntity.vecData.Separate(30); /* CompressionID */ MOTDirComprEntity.vecData.Separate(8); /* rfu */ MOTDirComprEntity.vecData.Separate(2); /* Uncompressed DataLength */ MOTDirComprEntity.vecData.Separate(30); CBitReassembler MOTDirectoryData; MOTDirectoryData.vecData = MOTDirComprEntity.vecData. Separate(MOTDirComprEntity.vecData.Size() - (9 * SIZEOF__BYTE)); if (bCompressionFlag && MOTDirectoryData.IsZipped() && MOTDirectoryData.uncompress()) { ProcessDirectory(MOTDirectoryData); MOTDirectory.TransportID = TransportID; } else { /* reset */ MOTDirComprEntity.Reset(); } } /* END IF HAVE ALL OF THE NEW DIRECTORY */ } else { vecbiNewData.Separate(iSegmentSize * SIZEOF__BYTE); } } /* of DG type 7 */ #endif else { vecbiNewData.Separate(iSegmentSize * SIZEOF__BYTE); } } } } void CMOTDABDec::ProcessDirectory(CBitReassembler & MOTDir) { MOTDirectory.AddHeader(MOTDir.vecData); /* first reset the "I'm in the carousel" flag for all objects and set the "I was in the carousel for the relevant objects then set the "I'm in the carousel" flag for all objects in the new directory. Then delete the objects from the carousel that need deleting leave objects alone that were never in a carousel, they might become valid later. */ /* save bodies of old carousel */ map < TTransportID, CByteReassembler > Body; for (map < TTransportID, CMOTObject >::iterator m = MOTCarousel.begin(); m != MOTCarousel.end(); m++) { Body[m->first] = m->second.Body; } MOTCarousel.erase(MOTCarousel.begin(), MOTCarousel.end()); //cout << "decode directory " << MOTDirectory. iNumberOfObjects << " === " << MOTDirectory.vecObjects.size() << " {"; MOTDirectory.vecObjects.clear(); for (size_t i = 0; i < size_t(MOTDirectory.iNumberOfObjects); i++) { /* add each header to the carousel */ TTransportID tid = (TTransportID) MOTDir.vecData.Separate(16); MOTCarousel[tid].AddHeader(MOTDir.vecData); /* keep any bodies or body fragments previously received */ map < TTransportID, CByteReassembler >::iterator b = Body.find(tid); if (b != Body.end()) MOTCarousel[tid].Body = b->second; /* mark objects which are in the new directory */ MOTDirectory.vecObjects.push_back(tid); //cout << tid << " "; DeliverIfReady(tid); } //cout << "}" << endl; } void CDateAndTime::extract_absolute(CVector < _BINARY > &vecbiData) { vecbiData.Separate(1); /* rfa */ CModJulDate ModJulDate(vecbiData.Separate(17)); day = ModJulDate.GetDay(); month = ModJulDate.GetMonth(); year = ModJulDate.GetYear(); vecbiData.Separate(1); /* rfa */ lto_flag = (int) vecbiData.Separate(1); utc_flag = (int) vecbiData.Separate(1); hours = (int) vecbiData.Separate(5); minutes = (int) vecbiData.Separate(6); if (utc_flag != 0) { seconds = (int) vecbiData.Separate(6); vecbiData.Separate(10); /* rfa */ } else { seconds = 0; } if (lto_flag != 0) { vecbiData.Separate(2); /* rfa */ int sign = (int) vecbiData.Separate(1); half_hours = (int) vecbiData.Separate(5); if (sign == 1) half_hours = 0 - half_hours; } else { half_hours = 0; } } void CDateAndTime::extract_relative(CVector < _BINARY > &vecbiData) { int granularity = (int) vecbiData.Separate(2); int interval = (int) vecbiData.Separate(6); time_t t = time(NULL); switch (granularity) { case 0: t += 2 * 60 * interval; break; case 1: t += 30 * 60 * interval; break; case 2: t += 2 * 60 * 60 * interval; break; case 3: t += 24 * 60 * 60 * interval; break; } struct tm *tmp = gmtime(&t); year = tmp->tm_year; month = tmp->tm_mon; day = tmp->tm_mday; hours = tmp->tm_hour; minutes = tmp->tm_min; seconds = tmp->tm_sec; } void CDateAndTime::dump(ostream & out) { out << year << '/' << uint16_t(month) << '/' << uint16_t(day); out << " " << hours << ':' << minutes << ':' << seconds; out << " flags: " << utc_flag << ':' << lto_flag << ':' << half_hours; } void CMOTObjectBase::decodeExtHeader(_BYTE & bParamId, int &iHeaderFieldLen, int &iDataFieldLen, CVector < _BINARY > &vecbiHeader) const { int iPLI = (int) vecbiHeader.Separate(2); bParamId = (unsigned char) vecbiHeader.Separate(6); iHeaderFieldLen = 1; switch (iPLI) { case 0: /* Total parameter length = 1 byte; no DataField available */ iDataFieldLen = 0; break; case 1: /* Total parameter length = 2 bytes, length of DataField is 1 byte */ iDataFieldLen = 1; break; case 2: /* Total parameter length = 5 bytes; length of DataField is 4 bytes */ iDataFieldLen = 4; break; case 3: /* Total parameter length depends on the DataFieldLength indicator (the maximum parameter length is 32770 bytes) */ /* Ext (ExtensionFlag): This 1-bit field specifies the length of the DataFieldLength Indicator and is coded as follows: - 0: the total parameter length is derived from the next 7 bits; - 1: the total parameter length is derived from the next 15 bits */ _BINARY biExt = (_BINARY) vecbiHeader.Separate(1); /* Get data field length */ if (biExt == 0) { iDataFieldLen = (int) vecbiHeader.Separate(7); iHeaderFieldLen++; } else { iDataFieldLen = (int) vecbiHeader.Separate(15); iHeaderFieldLen += 2; } } } void CReassembler::cachelast(CVector < _BYTE > &vecDataIn, size_t iSegSize) { vecLastSegment.Init(iSegSize); for (size_t i = 0; i < iSegSize; i++) vecLastSegment[i] = vecDataIn.Separate(8); } void CReassembler::copyin(CVector < _BYTE > &vecDataIn, size_t iSegNum, size_t bytes) { size_t offset = iSegNum * iSegmentSize; size_t iNewSize = offset + bytes; if (size_t(vecData.Size()) < iNewSize) vecData.Enlarge(iNewSize - vecData.Size()); for (size_t i = 0; i < bytes; i++) vecData[offset + i] = vecDataIn.Separate(8); } void CReassembler::AddSegment(CVector < _BYTE > &vecDataIn, int iSegSize, int iSegNum, _BOOLEAN bLast) { if (bLast) { if (iLastSegmentNum == -1) { iLastSegmentNum = iSegNum; iLastSegmentSize = iSegSize; /* three cases: 1: single segment - easy! (actually degenerate with case 3) 2: multi-segment and the last segment came first. 3: normal - some segment, not the last, came first, we know the segment size */ if (iSegNum == 0) { /* case 1 */ copyin(vecDataIn, 0, iSegSize); } else if (iSegmentSize == 0) { /* case 2 */ cachelast(vecDataIn, iSegSize); } else { /* case 3 */ copyin(vecDataIn, iSegNum, iSegSize); } } /* otherwise do nothing as we already have the last segment */ } else { iSegmentSize = iSegSize; if (Tracker.HaveSegment(iSegNum) == false) { copyin(vecDataIn, iSegNum, iSegSize); } } Tracker.AddSegment(iSegNum); /* tracking the last segment makes the Ready work! */ if ((iLastSegmentSize != -1) /* we have the last segment */ && (bReady == false) /* we haven't already completed reassembly */ && Tracker.Ready() /* there are no gaps */ ) { if (vecLastSegment.Size() > 0) { /* we have everything, but the last segment came first */ copylast(); } bReady = true; } } void CReassembler::copylast() { size_t offset = iLastSegmentNum * iSegmentSize; vecData.Enlarge(vecLastSegment.Size()); for (size_t i = 0; i < size_t(vecLastSegment.Size()); i++) vecData[offset + i] = vecLastSegment[i]; vecLastSegment.Init(0); } void CBitReassembler::cachelast(CVector < _BYTE > &vecDataIn, size_t iSegSize) { vecLastSegment.Init(8 * iSegSize); vecLastSegment.ResetBitAccess(); for (size_t i = 0; i < 8 * iSegSize; i++) vecLastSegment[i] = vecDataIn.Separate(1); } void CBitReassembler::copyin(CVector < _BYTE > &vecDataIn, size_t iSegNum, size_t bytes) { size_t offset = iSegNum * 8 * iSegmentSize; size_t bits = 8 * bytes; size_t iNewSize = offset + bits; if (size_t(vecData.Size()) < iNewSize) vecData.Enlarge(iNewSize - vecData.Size()); for (size_t i = 0; i < bits; i++) vecData[offset + i] = vecDataIn.Separate(1); } void CBitReassembler::copylast() { size_t offset = iLastSegmentNum * 8 * iSegmentSize; vecData.Enlarge(vecLastSegment.Size()); for (size_t i = 0; i < size_t(vecLastSegment.Size()); i++) vecData[offset + i] = vecLastSegment[i]; vecLastSegment.Init(0); vecLastSegment.ResetBitAccess(); } string CMOTObjectBase::extractString(CVector < _BINARY > &vecbiData, int iLen) const { string strVar; for (size_t i = 0; i < size_t(iLen); i++) { strVar += (char) vecbiData.Separate(SIZEOF__BYTE); } return strVar; } void CMOTDirectory::Reset () { CMOTObjectBase::Reset (); bSortedHeaderInformation = false; DirectoryIndex.clear (); bCompressionFlag = false; iCarouselPeriod = -1; iNumberOfObjects = 0; iSegmentSize = 0; } void CMOTDirectory::AddHeader(CVector < _BINARY > &vecbiHeader) { // int iDirectorySize; /* compression flag - must be zero */ bCompressionFlag = vecbiHeader.Separate(1) ? true : false; /* rfu */ vecbiHeader.Separate(1); /* Directory size: not used */ // iDirectorySize = (int) vecbiHeader.Separate(30); /* Number of objects */ iNumberOfObjects = (int) vecbiHeader.Separate(16); /* Carousel period */ iCarouselPeriod = (int) vecbiHeader.Separate(24); /* rfu */ vecbiHeader.Separate(1); /* Rfa: not used */ vecbiHeader.Separate(2); /* Segment size: not used */ iSegmentSize = (int) vecbiHeader.Separate(13); /* Directory extension length */ int iDirectoryExtensionLength = (int) vecbiHeader.Separate(16); /* Use all header extension data blocks */ int iSizeRec = iDirectoryExtensionLength; /* Use all header extension data blocks */ while (iSizeRec > 0) { _BYTE bParamId; int iHdrFieldLen, iDataFieldLen, iTmp; decodeExtHeader(bParamId, iHdrFieldLen, iDataFieldLen, vecbiHeader); iSizeRec -= (iHdrFieldLen + iDataFieldLen); switch (bParamId) { case 0: /* SortedHeaderInformation */ bSortedHeaderInformation = true; break; case 1: /* DefaultPermitOutdatedVersions */ iTmp = (int) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); if (iTmp == 0) bPermitOutdatedVersions = false; else bPermitOutdatedVersions = true; break; case 9: /* DefaultExpiration */ if (iDataFieldLen == 1) { /* relative */ ExpireTime.extract_relative(vecbiHeader); } else { /* absolute */ ExpireTime.extract_absolute(vecbiHeader); } break; case 34: /* DirectoryIndex */ { _BYTE iProfile = (_BYTE) vecbiHeader.Separate(SIZEOF__BYTE); DirectoryIndex[iProfile] = extractString(vecbiHeader, iDataFieldLen - 1); } break; default: if (iDataFieldLen > 0) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; } } } _BOOLEAN CReassembler::IsZipped() const { /* Check if the header file is a gzip header see GZIP file format specification http://www.ietf.org/rfc/rfc1952.txt */ if(vecData.Size()<3) return false; /* Check for gzip header [31, 139, 8] */ if ((vecData[0] == 31) && (vecData[1] == 139) && (vecData[2] == 8)) return true; else return false; } unsigned int CReassembler::gzGetOriginalSize() const { /* Get the original size from a gzip file last 4 bytes contains the original file size (ISIZE) see GZIP file format specification http://www.ietf.org/rfc/rfc1952.txt */ CVector < _BYTE > byHeader(4); const int iLastByte = vecData.Size() - 1; byHeader[0] = vecData[iLastByte - 3]; byHeader[1] = vecData[iLastByte - 2]; byHeader[2] = vecData[iLastByte - 1]; byHeader[3] = vecData[iLastByte]; return byHeader[0] + (byHeader[1] << 8) + (byHeader[2] << 16) + (byHeader[3] << 24); } _BOOLEAN CReassembler::uncompress() { #if HAVE_LIBZ CVector < _BYTE > vecbRawDataOut; /* Extract the original file size */ unsigned long dest_len = gzGetOriginalSize(); if (dest_len < MAX_DEC_NUM_BYTES_ZIP_DATA) { vecbRawDataOut.Init(dest_len); int zerr; z_stream stream; memset(&stream, 0, sizeof(stream)); if ((zerr = inflateInit2(&stream, -MAX_WBITS)) != Z_OK) return false; /* skip past minimal gzip header */ stream.next_in = &vecData[10]; stream.avail_in = vecData.Size() - 10; stream.next_out = &vecbRawDataOut[0]; stream.avail_out = vecbRawDataOut.Size(); zerr = inflate(&stream, Z_NO_FLUSH); dest_len = vecbRawDataOut.Size() - stream.avail_out; if (zerr != Z_OK && zerr != Z_STREAM_END) return false; inflateEnd(&stream); if (zerr != Z_OK && zerr != Z_STREAM_END) return false; vecData.Init(dest_len); vecData = vecbRawDataOut; return true; } else { vecData.Init(0); return false; } #else # ifdef HAVE_LIBFREEIMAGE CVector < _BYTE > vecbRawDataOut; CVector < _BYTE > &vecbRawDataIn = vecData; /* Extract the original file size */ const unsigned long dest_len = gzGetOriginalSize(); if (dest_len < MAX_DEC_NUM_BYTES_ZIP_DATA) { vecbRawDataOut.Init(dest_len); /* Actual decompression call */ const int zerr = FreeImage_ZLibGUnzip(&vecbRawDataOut[0], dest_len, &vecbRawDataIn[0], vecbRawDataIn.Size()); if (zerr > 0) { /* Copy data */ vecData.Init(zerr); vecData = vecbRawDataOut; return true; } else { vecData.Init(0); return false; } } else { vecData.Init(0); return false; } # else return false; # endif #endif } static const char *txt[] = { "txt", "txt", "html", 0 }; static const char *img[] = { "gif", "jpeg", "bmp", "png", 0 }; static const char *audio[] = { "mpg", "mp2", "mp3", "mpg", "mp2", "mp3", "pcm", "aiff", "atrac", "atrac2", "mp4", 0 }; static const char *video[] = { "mpg", "mp2", "mp4", "h263", 0 }; void CMOTObject::AddHeader(CVector < _BINARY > &vecbiHeader) { /* HeaderSize and BodySize */ iBodySize = (int) vecbiHeader.Separate(28); size_t iHeaderSize = (size_t) vecbiHeader.Separate(13); /* Content type and content sub-type */ iContentType = (int) vecbiHeader.Separate(6); iContentSubType = (int) vecbiHeader.Separate(9); /* 7 bytes for header core */ int iSizeRec = iHeaderSize - 7; /* Use all header extension data blocks */ while (iSizeRec > 0) { _BYTE bParamId; int iHdrFieldLen, iDataFieldLen, iTmp; decodeExtHeader(bParamId, iHdrFieldLen, iDataFieldLen, vecbiHeader); iSizeRec -= (iHdrFieldLen + iDataFieldLen); switch (bParamId) { case 1: /* PermitOutdatedVersions */ iTmp = (int) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); if (iTmp == 0) bPermitOutdatedVersions = false; else bPermitOutdatedVersions = true; break; case 5: /* TriggerTime - OBSOLETE */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 6: /* Version - OBSOLETE */ iVersion = (int) vecbiHeader.Separate(SIZEOF__BYTE); break; case 7: /* RetransmissionDistance */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 9: /* Expiration */ if (iDataFieldLen == 1) { /* relative */ ExpireTime.extract_relative(vecbiHeader); } else { /* absolute */ ExpireTime.extract_absolute(vecbiHeader); } break; case 10: /* Priority */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 11: /* Label */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 12: /* Content Name */ /* TODO - convert characters to UNICODE */ iCharacterSetForName = vecbiHeader.Separate(4); /* rfa */ vecbiHeader.Separate(4); strName = extractString(vecbiHeader, iDataFieldLen - 1); break; case 13: /* UniqueBodyVersion */ iUniqueBodyVersion = (int) vecbiHeader.Separate(32); break; case 15: /* Content Description */ iCharacterSetForDescription = vecbiHeader.Separate(4); /* rfa */ vecbiHeader.Separate(4); strContentDescription = extractString(vecbiHeader, iDataFieldLen - 1); break; case 16: /* Mime Type */ strMimeType = extractString(vecbiHeader, iDataFieldLen); break; case 17: /* Compression Type */ iCompressionType = (int) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 0x21: /* ProfileSubset */ { vecbProfileSubset.clear(); for (size_t i = 0; i < size_t(iDataFieldLen); i++) vecbProfileSubset.push_back((_BYTE) vecbiHeader. Separate(SIZEOF__BYTE)); } break; case 0x23: /* CAInfo */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 0x24: /* CAReplacementObject */ /* not decoded - skip */ (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; case 0x25: /* ScopeStart */ ScopeStart.extract_absolute(vecbiHeader); break; case 0x26: /* ScopeEnd */ ScopeEnd.extract_absolute(vecbiHeader); break; case 0x27: /* ScopeId */ iScopeId = vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; default: /* not decoded - skip */ if (iDataFieldLen > 0) (void) vecbiHeader.Separate(iDataFieldLen * SIZEOF__BYTE); break; } } /* set strFormat */ switch (iContentType) { case 1: strFormat = txt[iContentSubType]; break; case 2: strFormat = img[iContentSubType]; break; case 3: strFormat = audio[iContentSubType]; break; case 4: strFormat = video[iContentSubType]; break; } bHasHeader = true; } void CMOTObject::dump(ostream & out) { out << "MOT(" << TransportID << "):"; out << " Name: " << strName; out << ':' << iCharacterSetForName; out << " Description: " << strContentDescription; out << ':' << iCharacterSetForDescription; out << " mime: " << strMimeType; out << " content: " << iContentType << '/' << iContentSubType; out << " UniqueBodyVersion: " << iUniqueBodyVersion; out << " Expires: " << ExpireTime; out << " PermitOutdatedVersions: " << bPermitOutdatedVersions; out << " Scope: " << hex << iScopeId << dec << " from " << ScopeStart << " to " << ScopeEnd; out << " CompressionType: " << iCompressionType; out << " Version: " << iVersion; out << " Priority: " << iPriority; out << " RetransmissionDistance: " << iRetransmissionDistance; out << " format: " << strFormat; out << " length: " << iBodySize; } void CMOTDirectory::dump(ostream & out) { out << "MOTDIR(" << TransportID << "):"; out << " Expires: " << ExpireTime; out << " PermitOutdatedVersions: " << bPermitOutdatedVersions; out << " CarouselPeriod: " << iCarouselPeriod; out << " SegmentSize: " << iSegmentSize; out << " CompressionFlag: " << bCompressionFlag; out << " SortedHeaderInformation: " << bSortedHeaderInformation; out << " indices { "; for (map < _BYTE, string >::iterator di = DirectoryIndex.begin(); di != DirectoryIndex.end(); di++) { out << hex << di->first << dec << " => " << di->second; out.flush(); } out << " }"; out << " there are " << iNumberOfObjects << " objects {"; for (size_t i = 0; i < vecObjects.size(); i++) out << " " << vecObjects[i]; out << " }"; } qsstv_8.2.12/qsstv/drmtx/common/datadecoding/DABMOT.h000664 001750 001750 00000037063 12440612574 022337 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer, Andrea Russo, Julian Cable * * adapted for ham sstv use Ties Bos - PA0MBO * * * Description: * See DABMOT.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DABMOT_H__3B0UBVE98732KJVEW363E7A0D31912__INCLUDED_) #define DABMOT_H__3B0UBVE98732KJVEW363E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "utils/vector.h" #include "../util/CRC.h" #include #include #include #include #include "qsstvglobal.h" /* Definitions ****************************************************************/ /* Invalid data segment number. Shall be a negative value since the test for invalid data segment number is always "if (iDataSegNum < 0)" */ #define INVALID_DATA_SEG_NUM -1 /* Maximum number of bytes for zip'ed files. We need to specify this number to avoid segmentation faults due to erroneous zip header giving a much too high number of bytes */ #define MAX_DEC_NUM_BYTES_ZIP_DATA 1000000 /* 1 MB */ /* Registrered BWS profiles (ETSI TS 101 498-1) */ #define RESERVED_PROFILE 0x00 #define BASIC_PROFILE 0x01 #define TOP_NEWS_PROFILE 0x02 #define UNRESTRICTED_PC_PROFILE 0xFF /* Classes ********************************************************************/ class CMOTObjectRaw { public: CMOTObjectRaw () { Reset (); } CMOTObjectRaw (const CMOTObjectRaw & nOR) { Header = nOR.Header; Body = nOR.Body; } CMOTObjectRaw & operator= (const CMOTObjectRaw & nOR) { Header = nOR.Header; Body = nOR.Body; return *this; } void Reset () { Header.Init (0); Body.Init (0); } CVector < _BINARY > Header; CVector < _BINARY > Body; }; class CDateAndTime { public: CDateAndTime():utc_flag(0), lto_flag(0), half_hours(0), year(0), month(0), day(0), hours(0), minutes(0), seconds(0) {} void extract_relative (CVector < _BINARY > &vecbiData); void extract_absolute (CVector < _BINARY > &vecbiData); void Reset () { utc_flag = 0; lto_flag = 0; half_hours = 0; year = 0; month = 0; day = 0; hours = 0; minutes = 0; seconds = 0; } void dump(ostream& out); int utc_flag, lto_flag, half_hours; uint16_t year; uint8_t month, day; int hours, minutes, seconds; }; typedef int TTransportID; class CSegmentTracker { public: CSegmentTracker () { Reset (); } void Reset () { vecbHaveSegment.clear (); } size_t size () { return vecbHaveSegment.size (); } _BOOLEAN Ready () { if (vecbHaveSegment.size () == 0) return false; for (size_t i = 0; i < vecbHaveSegment.size (); i++) { if (vecbHaveSegment[i] == false) { return false; } } return true; } void AddSegment (int iSegNum) { if ((iSegNum + 1) > int (vecbHaveSegment.size ())) vecbHaveSegment.resize (iSegNum + 1, false); vecbHaveSegment[iSegNum] = true; } _BOOLEAN HaveSegment (int iSegNum) { if (iSegNum < int (vecbHaveSegment.size ())) return vecbHaveSegment[iSegNum]; return false; } protected: vector < _BOOLEAN > vecbHaveSegment; }; class CReassembler { public: CReassembler(): vecData(), vecLastSegment(), iLastSegmentNum(-1), iLastSegmentSize(-1), iSegmentSize(0), Tracker(), bReady(false) { } CReassembler (const CReassembler & r):iLastSegmentNum (r.iLastSegmentNum), iLastSegmentSize (r.iLastSegmentSize), iSegmentSize (r.iSegmentSize), Tracker (r.Tracker), bReady (r.bReady) { vecData.Init (r.vecData.Size ()); vecData = r.vecData; vecLastSegment.Init (r.vecLastSegment.Size ()); vecLastSegment = r.vecLastSegment; } virtual ~ CReassembler () { } inline CReassembler & operator= (const CReassembler & r) { iLastSegmentNum = r.iLastSegmentNum; iLastSegmentSize = r.iLastSegmentSize; iSegmentSize = r.iSegmentSize; Tracker = r.Tracker; vecData.Init (r.vecData.Size ()); vecData = r.vecData; vecLastSegment.Init (r.vecLastSegment.Size ()); vecLastSegment = r.vecLastSegment; bReady = r.bReady; return *this; } void Reset () { vecData.Init (0); vecData.ResetBitAccess (); vecLastSegment.Init (0); vecLastSegment.ResetBitAccess (); iLastSegmentNum = -1; iLastSegmentSize = -1; iSegmentSize = 0; Tracker.Reset (); bReady = false; } _BOOLEAN Ready () { return bReady; } void AddSegment (CVector < _BYTE > &vecDataIn, int iSegSize, int iSegNum, _BOOLEAN bLast = false); _BOOLEAN IsZipped () const; _BOOLEAN uncompress(); CVector < _BYTE > vecData; protected: virtual void copyin (CVector < _BYTE > &vecDataIn, size_t iSegNum, size_t bytes); virtual void cachelast (CVector < _BYTE > &vecDataIn, size_t iSegSize); virtual void copylast (); unsigned int gzGetOriginalSize () const; CVector < _BYTE > vecLastSegment; int iLastSegmentNum; int iLastSegmentSize; size_t iSegmentSize; CSegmentTracker Tracker; _BOOLEAN bReady; }; class CBitReassembler:public CReassembler { public: CBitReassembler ():CReassembler () { } CBitReassembler (const CBitReassembler & r):CReassembler (r) { } protected: virtual void copyin (CVector < _BYTE > &vecDataIn, size_t iSegNum, size_t bytes); virtual void cachelast (CVector < _BYTE > &vecDataIn, size_t iSegSize); virtual void copylast (); }; typedef CReassembler CByteReassembler; class CMOTObjectBase { public: CMOTObjectBase ():TransportID(-1),ExpireTime(),bPermitOutdatedVersions(false) { Reset (); } virtual ~CMOTObjectBase () { } virtual void Reset () { TransportID = -1; ExpireTime.Reset (); bPermitOutdatedVersions = false; } void decodeExtHeader (_BYTE & bParamId, int &iHeaderFieldLen, int &iDataFieldLen, CVector < _BINARY > &vecbiHeader) const; string extractString (CVector < _BINARY > &vecbiData, int iLen) const; TTransportID TransportID; CDateAndTime ExpireTime; _BOOLEAN bPermitOutdatedVersions; }; class CMOTDirectory:public CMOTObjectBase { public: CMOTDirectory ():CMOTObjectBase(), iCarouselPeriod(0), iNumberOfObjects(0), iSegmentSize(0), bCompressionFlag(false), bSortedHeaderInformation(false), DirectoryIndex(), vecObjects() { } CMOTDirectory (const CMOTDirectory & nD):CMOTObjectBase (nD), iCarouselPeriod (nD.iCarouselPeriod), iNumberOfObjects (nD.iNumberOfObjects), iSegmentSize (nD.iSegmentSize), bCompressionFlag (nD.bCompressionFlag), bSortedHeaderInformation (nD.bSortedHeaderInformation), DirectoryIndex (nD.DirectoryIndex) { } virtual ~CMOTDirectory () { } inline CMOTDirectory & operator= (const CMOTDirectory & nD) { TransportID = nD.TransportID; ExpireTime = nD.ExpireTime; bPermitOutdatedVersions = nD.bPermitOutdatedVersions; bSortedHeaderInformation = nD.bSortedHeaderInformation; bCompressionFlag = nD.bCompressionFlag; iCarouselPeriod = nD.iCarouselPeriod; DirectoryIndex = nD.DirectoryIndex; iNumberOfObjects = nD.iNumberOfObjects; iSegmentSize = nD.iSegmentSize; return *this; } virtual void Reset (); virtual void AddHeader (CVector < _BINARY > &vecbiHeader); void dump(ostream&); int iCarouselPeriod, iNumberOfObjects, iSegmentSize; _BOOLEAN bCompressionFlag, bSortedHeaderInformation; map < _BYTE, string > DirectoryIndex; vector < TTransportID > vecObjects; }; /* we define this to reduce the need for copy constructors and operator= since CReassembler has a good set, the defaults will do for this, but not for classes with CVector members */ class CMOTObject:public CMOTObjectBase { public: CMOTObject ():CMOTObjectBase(), vecbRawData(), bComplete(false), bHasHeader(false), Body(), strName(""), iBodySize(0), iCharacterSetForName(0), iCharacterSetForDescription(0), strFormat(""), strMimeType(""), iCompressionType(0), strContentDescription(""), iVersion(0), iUniqueBodyVersion(0), iContentType(0), iContentSubType(0), iPriority(0), iRetransmissionDistance(0), vecbProfileSubset(), ScopeStart(), ScopeEnd(), iScopeId(0), bReady(false) { } CMOTObject (const CMOTObject & nO):CMOTObjectBase (nO), bComplete (nO.bComplete), bHasHeader (nO.bHasHeader), strName (nO.strName), iBodySize(nO.iBodySize), iCharacterSetForName (nO.iCharacterSetForName), iCharacterSetForDescription (nO.iCharacterSetForDescription), strFormat (nO.strFormat), strMimeType (nO.strMimeType), iCompressionType (nO.iCompressionType), strContentDescription (nO.strContentDescription), iVersion (nO.iVersion), iUniqueBodyVersion (nO.iUniqueBodyVersion), iContentType (nO.iContentType), iContentSubType (nO.iContentSubType), iPriority (nO.iPriority), iRetransmissionDistance (nO.iRetransmissionDistance), vecbProfileSubset (nO.vecbProfileSubset), ScopeStart (nO.ScopeStart), ScopeEnd (nO.ScopeEnd), iScopeId (nO.iScopeId) { Body = nO.Body; vecbRawData.Init (nO.vecbRawData.Size ()); vecbRawData = nO.vecbRawData; } virtual ~ CMOTObject () { } inline CMOTObject & operator= (const CMOTObject & nO) { TransportID = nO.TransportID; ExpireTime = nO.ExpireTime; bPermitOutdatedVersions = nO.bPermitOutdatedVersions; bComplete = nO.bComplete; bHasHeader = nO.bHasHeader; strFormat = nO.strFormat; strName = nO.strName; iBodySize = nO.iBodySize; iCharacterSetForName = nO.iCharacterSetForName; iCharacterSetForDescription = nO.iCharacterSetForDescription; strMimeType = nO.strMimeType; iCompressionType = nO.iCompressionType; strContentDescription = nO.strContentDescription; iVersion = nO.iVersion; iUniqueBodyVersion = nO.iUniqueBodyVersion; iContentType = nO.iContentType; iContentSubType = nO.iContentSubType; iPriority = nO.iPriority; iRetransmissionDistance = nO.iRetransmissionDistance; vecbProfileSubset = nO.vecbProfileSubset; ScopeStart = nO.ScopeStart; ScopeEnd = nO.ScopeEnd; iScopeId = nO.iScopeId; Body = nO.Body; vecbRawData.Init (nO.vecbRawData.Size ()); vecbRawData = nO.vecbRawData; return *this; } void Reset () { vecbRawData.Init (0); bComplete = false; bHasHeader = false; Body.Reset (); strFormat = ""; strName = ""; iBodySize = 0; iCharacterSetForName = 0; iCharacterSetForDescription = 0; strMimeType = ""; iCompressionType = 0; strContentDescription = ""; iVersion = 0; iUniqueBodyVersion = 0; iContentType = 0; iContentSubType = 0; iPriority = 0; iRetransmissionDistance = 0; vecbProfileSubset.clear (); ScopeStart.Reset (); ScopeEnd.Reset (); iScopeId = 0; } void dump(ostream&); void AddHeader (CVector < _BINARY > &header); /* for encoding */ CVector < _BYTE > vecbRawData; _BOOLEAN bComplete, bHasHeader; CByteReassembler Body; string strName; int iBodySize; int iCharacterSetForName; int iCharacterSetForDescription; string strFormat; string strMimeType; int iCompressionType; string strContentDescription; int iVersion, iUniqueBodyVersion; int iContentType, iContentSubType; int iPriority; int iRetransmissionDistance; vector < _BYTE > vecbProfileSubset; /* the following for EPG Objects */ CDateAndTime ScopeStart, ScopeEnd; int iScopeId; protected: _BOOLEAN bReady; }; /* Encoder ------------------------------------------------------------------ */ class CMOTDABEnc { public: CMOTDABEnc ():MOTObject(), MOTObjSegments(), iSegmCntHeader(0), iSegmCntBody(0), bCurSegHeader(false), iContIndexHeader(0), iContIndexBody(0) { txTransportID=0; } virtual ~CMOTDABEnc () { } void Reset (); _BOOLEAN GetDataGroup (CVector < _BINARY > &vecbiNewData); void SetMOTObject (CMOTObject & NewMOTObject, int bytesAvailable); // void SetMOTObjectRunIn (CMOTObject & NewMOTObject); _REAL GetProgPerc () const; int iNumSegStore ; void prepareSegmentList(unsigned int repetition=1); // ON4QZ protected: QList segmentList; int segmentListIdx; class CMOTObjSegm { public: CVector < CVector < _BINARY > >vvbiHeader; CVector < CVector < _BINARY > >vvbiBody; }; void GenMOTSegments (CMOTObjSegm & MOTObjSegm); void PartitionUnits (CVector < _BINARY > &vecbiSource, CVector < CVector < _BINARY > >&vecbiDest, const int iPartiSize); // void PartitionUnitsRunIn (CVector < _BINARY > &vecbiSource, // CVector < CVector < _BINARY > >&vecbiDest, // const int iPartiSize); void GenMOTObj (CVector < _BINARY > &vecbiData, CVector < _BINARY > &vecbiSeg, const _BOOLEAN bHeader, const int iSegNum, const int iTranspID, const _BOOLEAN bLastSeg); CMOTObject MOTObject; CMOTObjSegm MOTObjSegments; int iSegmCntHeader; int iSegmCntBody; int runInCnt; _BOOLEAN bCurSegHeader; int iContIndexHeader; int iContIndexBody; _BOOLEAN bFirstRound; }; /* Decoder ------------------------------------------------------------------ */ class CMOTDABDec { public: CMOTDABDec ():MOTmode (unknown), MOTHeaders(), MOTDirectoryEntity(), MOTDirComprEntity(), MOTDirectory(), MOTCarousel(), qiNewObjects() { } virtual ~ CMOTDABDec () { } /* client methods */ void GetNextObject (CMOTObject & NewMOTObject); void GetObject (CMOTObject & NewMOTObject, TTransportID TransportID) { NewMOTObject = MOTCarousel[TransportID]; } void GetDirectory (CMOTDirectory & MOTDirectoryOut) { MOTDirectoryOut = MOTDirectory; } _BOOLEAN NewObjectAvailable (); /* push from lower level */ void AddDataUnit (CVector < _BINARY > &vecbiNewData); protected: void ProcessDirectory (CBitReassembler &MOTDir); void DeliverIfReady (TTransportID TransportID); /* These fields are the in-progress carousel objects */ enum { unknown, headerMode, directoryMode } MOTmode; /* strictly, there should be only one of these! */ map < TTransportID, CBitReassembler > MOTHeaders; CBitReassembler MOTDirectoryEntity; CBitReassembler MOTDirComprEntity; /* These fields are the cached complete carousel */ CMOTDirectory MOTDirectory; map < TTransportID, CMOTObject > MOTCarousel; queue < TTransportID > qiNewObjects; }; #endif // !defined(DABMOT_H__3B0UBVE98732KJVEW363E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/datadecoding/DataDecoder.cpp000664 001750 001750 00000013153 12440612574 024055 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer, Julian Cable * * Description: * Data module (using multimedia information carried in DRM stream) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "DataDecoder.h" #include /* Implementation *************************************************************/ /******************************************************************************\ * Encoder * \******************************************************************************/ void CDataEncoder::GeneratePacket(CVector < _BINARY > &vecbiPacket) { int i; _BOOLEAN bLastFlag; /* Init size for whole packet, not only body */ vecbiPacket.Init(iTotalPacketSize); vecbiPacket.ResetBitAccess(); /* Calculate remaining data size to be transmitted */ const int iRemainSize = vecbiCurDataUnit.Size() - iCurDataPointer; /* Header --------------------------------------------------------------- */ /* First flag */ if (iCurDataPointer == 0) vecbiPacket.Enqueue((uint32_t) 1, 1); else vecbiPacket.Enqueue((uint32_t) 0, 1); /* Last flag */ if (iRemainSize > iPacketLen) { vecbiPacket.Enqueue((uint32_t) 0, 1); bLastFlag = false; } else { vecbiPacket.Enqueue((uint32_t) 1, 1); bLastFlag = true; } /* Packet Id */ vecbiPacket.Enqueue((uint32_t) iPacketID, 2); /* Padded packet indicator (PPI) */ if (iRemainSize < iPacketLen) vecbiPacket.Enqueue((uint32_t) 1, 1); else vecbiPacket.Enqueue((uint32_t) 0, 1); /* Continuity index (CI) */ vecbiPacket.Enqueue((uint32_t) iContinInd, 3); /* Increment index modulo 8 (1 << 3) */ iContinInd++; if (iContinInd == 8) iContinInd = 0; /* Body ----------------------------------------------------------------- */ if (iRemainSize >= iPacketLen) { if (iRemainSize == iPacketLen) { /* Last packet */ for (i = 0; i < iPacketLen; i++) vecbiPacket.Enqueue(vecbiCurDataUnit.Separate(1), 1); } else { for (i = 0; i < iPacketLen; i++) { vecbiPacket.Enqueue(vecbiCurDataUnit.Separate(1), 1); iCurDataPointer++; } } } else { /* Padded packet. If the PPI is 1 then the first byte shall indicate the number of useful bytes that follow, and the data field is completed with padding bytes of value 0x00 */ vecbiPacket.Enqueue((uint32_t) (iRemainSize / SIZEOF__BYTE), SIZEOF__BYTE); /* Data */ for (i = 0; i < iRemainSize; i++) vecbiPacket.Enqueue(vecbiCurDataUnit.Separate(1), 1); /* Padding */ for (i = 0; i < iPacketLen - iRemainSize; i++) vecbiPacket.Enqueue(vecbiCurDataUnit.Separate(1), 1); } /* If this was the last packet, get data for next data unit */ if (bLastFlag == true) { /* Generate new data unit */ MOTSlideShowEncoder.GetDataUnit(vecbiCurDataUnit); vecbiCurDataUnit.ResetBitAccess(); /* Reset data pointer and continuity index */ iCurDataPointer = 0; } /* CRC ------------------------------------------------------------------ */ CCRC CRCObject; /* Reset bit access */ vecbiPacket.ResetBitAccess(); /* Calculate the CRC and put it at the end of the segment */ CRCObject.Reset(16); /* "byLengthBody" was defined in the header */ for (i = 0; i < (iTotalPacketSize / SIZEOF__BYTE - 2); i++) CRCObject.AddByte(_BYTE(vecbiPacket.Separate(SIZEOF__BYTE))); // printf("adding crc16 to packet iTotalPacketSize is %d\n", iTotalPacketSize); /* Now, pointer in "enqueue"-function is back at the same place, add CRC */ vecbiPacket.Enqueue(CRCObject.GetCRC(), 16); } int CDataEncoder::Init(CParameter & Param) { /* Init packet length and total packet size (the total packet length is three bytes longer as it includes the header and CRC fields) */ // TODO we only use always the first service right now const int iCurSelDataServ = 0; Param.Lock(); // was in werkende afgecommentaard pa0mbo // printf("In CDataEncoder na Param.Lock \n"); iPacketLen = Param.Service[iCurSelDataServ].DataParam.iPacketLen * SIZEOF__BYTE; iTotalPacketSize = iPacketLen + 24 /* CRC + header = 24 bits */ ; iPacketID = Param.Service[iCurSelDataServ].DataParam.iPacketID; Param.Unlock(); // was in werkende afgecommentaard pa0mbo /* printf("in CDataEncoder::Init iPackectLen = %d iTotalPacketSize = %d packetID = %d\n", iPacketLen, iTotalPacketSize, iPacketID ); */ /* Init DAB MOT encoder object */ MOTSlideShowEncoder.Init(Param); /* Generate first data unit */ MOTSlideShowEncoder.GetDataUnit(vecbiCurDataUnit); vecbiCurDataUnit.ResetBitAccess(); /* Reset pointer to current position in data unit and continuity index */ iCurDataPointer = 0; iContinInd = 0; /* Return total packet size */ return iTotalPacketSize; } qsstv_8.2.12/qsstv/drmtx/common/datadecoding/DataDecoder.h000664 001750 001750 00000004524 12440612574 023524 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See DataDecoder.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DATADECODER_H__3B0BA660_CA3452363E7A0D31912__INCLUDED_) #define DATADECODER_H__3B0BA660_CA3452363E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../Parameter.h" #include "../util/Modul.h" #include "../util/CRC.h" #include "utils/vector.h" #include "DABMOT.h" #include "MOTSlideShow.h" class CJournaline; class CNews; /* Definitions ****************************************************************/ /* Maximum number of packets per stream */ #define MAX_NUM_PACK_PER_STREAM 4 /* Classes ********************************************************************/ /* Encoder ------------------------------------------------------------------ */ class CDataEncoder { public: CDataEncoder () { } virtual ~ CDataEncoder () { } int Init (CParameter & Param); void GeneratePacket(CVector < _BINARY > &vecbiPacket); CMOTSlideShowEncoder *GetSliShowEnc () { return &MOTSlideShowEncoder; } protected: CMOTSlideShowEncoder MOTSlideShowEncoder; CVector < _BINARY > vecbiCurDataUnit; int iPacketLen; int iTotalPacketSize; int iCurDataPointer; int iPacketID; int iContinInd; }; #endif // !defined(DATADECODER_H__3B0BA660_CA3452363E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/datadecoding/MOTSlideShow.cpp000664 001750 001750 00000011060 12440612574 024172 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * MOT applications (MOT Slideshow and Broadcast Web Site) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "MOTSlideShow.h" #include #include #include "drmtx/drmtransmitter.h" //#include"utils/supportfunctions.h" /* Implementation *************************************************************/ /******************************************************************************\ * Encoder * \******************************************************************************/ void CMOTSlideShowEncoder::GetDataUnit (CVector < _BINARY > &vecbiNewData) { if (allDataSend) { if(extraBlocks-- <=0) stopDRM=true; } /* Get new data group from MOT encoder. If the last MOT object was completely transmitted, this functions returns true. In this case, put a new picture to the MOT encoder object */ if (MOTDAB.GetDataGroup (vecbiNewData) == true) { allDataSend=true; AddNextPicture (); //basically the same // addToLog("loading raw data",LOGDRMMOT); } // arrayBinDump(QString("slice %1").arg(sliceCounter++),vecbiNewData,32,true); } _BOOLEAN CMOTSlideShowEncoder::GetTransStat (string & strCurPict, _REAL & rCurPerc) const { /* Name and current percentage of transmitted data of current picture. */ strCurPict = strCurObjName; rCurPerc = MOTDAB.GetProgPerc (); if (vecPicFileNames.Size () != 0) return true; else return false; } void CMOTSlideShowEncoder::Init (CParameter &TParam) { bytesToBeUsed=(TParam.iNumDecodedBitsMSC/SIZEOF__BYTE); iPictureCnt = 0; strCurObjName = ""; MOTDAB.Reset (); AddNextPicture (); allDataSend=false; extraBlocks=5; sliceCounter=0; MOTDAB.prepareSegmentList(1); // one repitition addToLog("Init and loading raw data",LOGDRMMOT); } void CMOTSlideShowEncoder::AddNextPicture () { int i; unsigned char byteIn; /* Here at least one picture is in container */ if (vecPicFileNames.Size () > 0) { /* Get current file name */ QString tmp=vecPicFileNames[iPictureCnt].name+"."+vecPicFileNames[iPictureCnt].format; strCurObjName = tmp.toLatin1().data(); CMOTObject MOTPicture; /* Set file name and format string */ MOTPicture.strName = strCurObjName; MOTPicture.strFormat = vecPicFileNames[iPictureCnt].format.toLatin1().data(); MOTPicture.vecbRawData.Init (0); for(i=0;icount();i++) { byteIn=vecPicFileNames[iPictureCnt].arrayPtr->at(i); // byteIn=0; /* Add one byte = SIZEOF__BYTE bits */ MOTPicture.vecbRawData.Enlarge (SIZEOF__BYTE); MOTPicture.vecbRawData.Enqueue ((uint32_t)byteIn,SIZEOF__BYTE); } MOTDAB.SetMOTObject (MOTPicture,bytesToBeUsed); /* Set file counter to next picture, test for wrap around */ iPictureCnt++; if (iPictureCnt == vecPicFileNames.Size ()) iPictureCnt = 0; } } void CMOTSlideShowEncoder::AddArray (QByteArray *ba,const QString name,const QString format) { /* Only ContentSubType "JFIF" (JPEG) and ContentSubType "PNG" are allowed for SlideShow application (not tested here!) */ /* Add file name to the list */ int iOldNumObj = vecPicFileNames.Size (); vecPicFileNames.Enlarge (1); vecPicFileNames[iOldNumObj].arrayPtr = ba; vecPicFileNames[iOldNumObj].name=name; vecPicFileNames[iOldNumObj].format=format; } qsstv_8.2.12/qsstv/drmtx/common/datadecoding/MOTSlideShow.h000664 001750 001750 00000004452 12440612574 023646 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(MOTSLIDESHOW_H__3B0UBVE98732KJVEW363LIHGEW982__INCLUDED_) #define MOTSLIDESHOW_H__3B0UBVE98732KJVEW363LIHGEW982__INCLUDED_ #include "../GlobalDefinitions.h" #include "utils/vector.h" #include "DABMOT.h" #include "../Parameter.h" /* Classes ********************************************************************/ /* Encoder ------------------------------------------------------------------ */ class CMOTSlideShowEncoder { public: CMOTSlideShowEncoder ():vecPicFileNames (0) {strCurObjName="";} virtual ~ CMOTSlideShowEncoder () {} void Init (CParameter &TParam); void GetDataUnit(CVector < _BINARY > &vecbiNewData); void AddArray (QByteArray *ba, const QString name, const QString format); void ClearAllFileNames () {vecPicFileNames.Init (0);} _BOOLEAN GetTransStat (string & strCurPict, _REAL & rCurPerc) const; protected: struct SPicDescr { QByteArray *arrayPtr; QString name; QString format; }; void AddNextPicture (); CMOTDABEnc MOTDAB; CVector < SPicDescr > vecPicFileNames; int iPictureCnt; string strCurObjName; bool allDataSend; int extraBlocks; int sliceCounter; int bytesToBeUsed; }; #endif // !defined(MOTSLIDESHOW_H__3B0UBVE98732KJVEW363LIHGEW982__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/interleaver/BlockInterleaver.cpp000664 001750 001750 00000004570 12440612574 025066 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "BlockInterleaver.h" /* Implementation *************************************************************/ /******************************************************************************\ * Block-interleaver base class * \******************************************************************************/ void CBlockInterleaver::MakeTable(CVector& veciIntTable, int iFrameSize, int it_0) { int i; int iHighestOne; int is, iq; /* The following equations are taken directly from the DRM-standard paper (7.3.3 and 7.6) */ iHighestOne = iFrameSize; /* s = 2 ^ ceil(log2(iFrameSize)), means: find the highest "1" of iFrameSize. The result of the equation is only one "1" at position "highest position of "1" in iFrameSize plus one". Therefore: "1 << (16 + 1)". This implementation: shift bits in iHighestOne to the left until a "1" reaches position 16. Simultaneously the bit in "is" is right-shifted */ is = 1 << (16 + 1); while (!(iHighestOne & (1 << 16))) { iHighestOne <<= 1; is >>= 1; } iq = is / 4 - 1; veciIntTable[0] = 0; for (i = 1; i < iFrameSize; i++) { veciIntTable[i] = (it_0 * veciIntTable[i - 1] + iq) % is; while (veciIntTable[i] >= iFrameSize) veciIntTable[i] = (it_0 * veciIntTable[i] + iq) % is; } } qsstv_8.2.12/qsstv/drmtx/common/interleaver/BlockInterleaver.h000664 001750 001750 00000003242 12440612574 024526 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See Blockinterleaver.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(BLOCK_INTERL_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define BLOCK_INTERL_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "utils/vector.h" /* Classes ********************************************************************/ class CBlockInterleaver { public: CBlockInterleaver() {} virtual ~CBlockInterleaver() {} protected: void MakeTable(CVector& veciIntTable, int iFrameSize, int it_0); }; #endif // !defined(BLOCK_INTERL_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/interleaver/SymbolInterleaver.cpp000664 001750 001750 00000007143 12440612574 025300 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * Symbol interleaver for MSC-symbols * We have to support long and short symbol interleaving. Long interleaving * spans over iD times iN_MUX interleaver blocks. To create a "block-wise * cycle-buffer" we shift the indices (stored in a table) each time a complete * block was written. Thus, we dont need to copy data since we only modify * the indices. * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "SymbolInterleaver.h" /* Implementation *************************************************************/ /******************************************************************************\ * Symbol interleaver * \******************************************************************************/ void CSymbInterleaver::ProcessDataInternal(CParameter&) { int i, j; /* Write data in interleaver-memory (always index "0") */ for (i = 0; i < iInputBlockSize; i++) matcInterlMemory[veciCurIndex[0]][i] = (*pvecInputData)[i]; /* Interleave data according to the interleaver table. Use the the interleaver-blocks described in the DRM-standard (Ro(i) = i (mod D) -> "i % iD") */ for (i = 0; i < iInputBlockSize; i++) (*pvecOutputData)[i] = matcInterlMemory[veciCurIndex[i % iD]][veciIntTable[i]]; /* Set new indices. Move blocks (virtually) forward */ for (j = 0; j < iD; j++) { veciCurIndex[j]--; if (veciCurIndex[j] < 0) veciCurIndex[j] = iD - 1; } } void CSymbInterleaver::InitInternal(CParameter& TransmParam) { int i; TransmParam.Lock(); /* Set internal parameters */ iN_MUX = TransmParam.CellMappingTable.iNumUsefMSCCellsPerFrame; /* Allocate memory for table */ veciIntTable.Init(iN_MUX); /* Make interleaver table */ MakeTable(veciIntTable, iN_MUX, SYMB_INTERL_CONST_T_0); /* Set interleaver depth */ switch (TransmParam.eSymbolInterlMode) { case CParameter::SI_LONG: iD = D_LENGTH_LONG_INTERL; break; case CParameter::SI_SHORT: iD = D_LENGTH_SHORT_INTERL; break; } /* Always allocate memory for long interleaver case (interleaver memory) */ matcInterlMemory.Init(D_LENGTH_LONG_INTERL, iN_MUX); /* Index for addressing the buffers */ veciCurIndex.Init(D_LENGTH_LONG_INTERL); for (i = 0; i < D_LENGTH_LONG_INTERL; i++) veciCurIndex[i] = i; /* Define block-sizes for input and output */ iInputBlockSize = iN_MUX; iOutputBlockSize = iN_MUX; /* Since the MSC logical frames must not end at the end of one symbol (could be somewhere in the middle of the symbol), the output buffer must accept more cells than one logical MSC frame is long */ iMaxOutputBlockSize = 2 * iN_MUX; TransmParam.Unlock(); } qsstv_8.2.12/qsstv/drmtx/common/interleaver/SymbolInterleaver.h000664 001750 001750 00000004333 12440612574 024743 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See SymbolInterleaver.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(CONVINTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define CONVINTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../Parameter.h" #include "../util/Modul.h" #include "BlockInterleaver.h" /* Definitions ****************************************************************/ #define D_LENGTH_SHORT_INTERL 1 #define D_LENGTH_LONG_INTERL 5 /* This constant is defined in DRM-standard for MSC Cell Interleaving */ #define SYMB_INTERL_CONST_T_0 5 /* Classes ********************************************************************/ class CSymbInterleaver : public CTransmitterModul<_COMPLEX, _COMPLEX>, public CBlockInterleaver { public: CSymbInterleaver() {} virtual ~CSymbInterleaver() {} protected: int iN_MUX; CMatrix<_COMPLEX> matcInterlMemory; CVector veciCurIndex; CVector veciIntTable; int iD; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; #endif // !defined(CONVINTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/matlib/Matlib.h000664 001750 001750 00000064700 12440612574 021441 0ustar00jomajoma000000 000000 /******************************************************************************\ * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * c++ Mathematic Library (Matlib) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #ifndef _MATLIB_H_ #define _MATLIB_H_ #include #include #include using namespace std; #include "../GlobalDefinitions.h" /* Definitions ****************************************************************/ /* Two different types: constant and temporary buffer */ enum EVecTy {VTY_CONST, VTY_TEMP}; /* These definitions save a lot of redundant code */ #define _VECOP(TYPE, LENGTH, FCT) const int iL = LENGTH; \ CMatlibVector vecRet(iL, VTY_TEMP); \ for (int i = 0; i < iL; i++) \ vecRet[i] = FCT; \ return vecRet #define _VECOPCL(FCT) for (int i = 0; i < iVectorLength; i++) \ operator[](i) FCT; \ return *this #define _MATOP(TYPE, LENGTHROW, LENGTHCOL, FCT) \ const int iRL = LENGTHROW; \ CMatlibMatrix matRet(iRL, LENGTHCOL, VTY_TEMP); \ for (int i = 0; i < iRL; i++) \ matRet[i] = FCT; \ return matRet #define _MATOPCL(FCT) for (int i = 0; i < iRowSize; i++) \ operator[](i) FCT; \ return *this /* In debug mode, test input parameters */ #ifdef _DEBUG_ #define _TESTRNGR(POS) if ((POS >= iVectorLength) || (POS < 0)) \ DebugError("MatLibrRead", "POS", POS, \ "iVectorLength", iVectorLength) #define _TESTRNGW(POS) if ((POS >= iVectorLength) || (POS < 0)) \ DebugError("MatLibrWrite", "POS", POS, \ "iVectorLength", iVectorLength) #define _TESTSIZE(INP) if (INP != iVectorLength) \ DebugError("SizeCheck", "INP", INP, \ "iVectorLength", iVectorLength) #define _TESTRNGRM(POS) if ((POS >= iRowSize) || (POS < 0)) \ DebugError("MatLibrReadMatrix", "POS", POS, \ "iRowSize", iRowSize) #define _TESTRNGWM(POS) if ((POS >= iRowSize) || (POS < 0)) \ DebugError("MatLibrWriteMatrix", "POS", POS, \ "iRowSize", iRowSize) #define _TESTSIZEM(INP) if (INP != iRowSize) \ DebugError("MatLibOperatorMatrix=()", "INP", INP, \ "iRowSize", iRowSize) #else // On Visual c++ 2005 Express Edition there is a segmentation fault if these macros are empty // TODO: FIX this with a better solution #ifdef _MSC_VER #define _TESTRNGR(POS) if (POS != POS) int idummy=0 #define _TESTRNGW(POS) if (POS != POS) int idummy=0 #define _TESTSIZE(INP) if (INP != INP) int idummy=0 #define _TESTRNGRM(POS) if (POS != POS) int idummy=0 #define _TESTRNGWM(POS) if (POS != POS) int idummy=0 #define _TESTSIZEM(INP) if (INP != INP) int idummy=0 #else #define _TESTRNGR(POS) #define _TESTRNGW(POS) #define _TESTSIZE(INP) #define _TESTRNGRM(POS) #define _TESTRNGWM(POS) #define _TESTSIZEM(INP) #endif #endif /* Classes ********************************************************************/ /* Prototypes */ template class CMatlibVector; template class CMatlibMatrix; /* Here we can choose the precision of the Matlib calculations */ typedef _REAL CReal; typedef complex CComplex; typedef CMatlibVector CRealVector; typedef CMatlibVector CComplexVector; typedef CMatlibMatrix CRealMatrix; typedef CMatlibMatrix CComplexMatrix; /******************************************************************************/ /* CMatlibVector class ********************************************************/ /******************************************************************************/ template class CMatlibVector { public: /* Construction, Destruction -------------------------------------------- */ CMatlibVector() : eVType(VTY_CONST), iVectorLength(0), pData(NULL) {} CMatlibVector(const int iNLen, const EVecTy eNTy = VTY_CONST) : eVType(eNTy), iVectorLength(0), pData(NULL) {Init(iNLen);} CMatlibVector(const int iNLen, const T tIniVal) : eVType(VTY_CONST), iVectorLength(0), pData(NULL) {Init(iNLen, tIniVal);} CMatlibVector(CMatlibVector& vecI); CMatlibVector(const CMatlibVector& vecI); virtual ~CMatlibVector() {if (pData != NULL) delete[] pData;} CMatlibVector(const CMatlibVector& fvReal, const CMatlibVector& fvImag) : eVType(VTY_CONST/*VTY_TEMP*/), iVectorLength(fvReal.GetSize()), pData(NULL) { /* Allocate data block for vector */ pData = new CComplex[iVectorLength]; /* Copy data from real-vectors in complex vector */ for (int i = 0; i < iVectorLength; i++) pData[i] = CComplex(fvReal[i], fvImag[i]); } /* Operator[] (Regular indices!!!) */ inline T& operator[](int const iPos) const {_TESTRNGR(iPos); return pData[iPos];} inline T& operator[](int const iPos) {_TESTRNGW(iPos); return pData[iPos];} // For use as l value /* Operator() */ inline T& operator()(int const iPos) const {_TESTRNGR(iPos - 1); return pData[iPos - 1];} inline T& operator()(int const iPos) {_TESTRNGW(iPos - 1); return pData[iPos - 1];} // For use as l value CMatlibVector operator()(const int iFrom, const int iTo) const; CMatlibVector operator()(const int iFrom, const int iStep, const int iTo) const; inline int GetSize() const {return iVectorLength;} void Init(const int iIniLen, const T tIniVal = 0); inline CMatlibVector& Reset(const T tResVal = 0) {_VECOPCL(= tResVal);} CMatlibVector& PutIn(const int iFrom, const int iTo, CMatlibVector& fvA); CMatlibVector& Merge(const CMatlibVector& vecA, T& tB); CMatlibVector& Merge(const CMatlibVector& vecA, const CMatlibVector& vecB); CMatlibVector& Merge(const CMatlibVector& vecA, const CMatlibVector& vecB, const CMatlibVector& vecC); /* operator= */ inline CMatlibVector& operator=(const CMatlibVector& vecI) { Init(vecI.GetSize()); for (int i = 0; i < iVectorLength; i++) operator[](i) = vecI[i]; return *this; } inline CMatlibVector& operator=(const CMatlibVector& vecI) { Init(vecI.GetSize()); for (int i = 0; i < iVectorLength; i++) operator[](i) = vecI[i]; return *this; } /* operator*= */ inline CMatlibVector& operator*=(const CReal& rI) {_VECOPCL(*= rI);} inline CMatlibVector& operator*=(const CComplex& cI) {_VECOPCL(*= cI);} inline CMatlibVector& operator*=(const CMatlibVector& vecI) {_VECOPCL(*= vecI[i]);} inline CMatlibVector& operator*=(const CMatlibVector& vecI) {_VECOPCL(*= vecI[i]);} /* operator/= */ inline CMatlibVector& operator/=(const CReal& rI) {_VECOPCL(/= rI);} inline CMatlibVector& operator/=(const CComplex& cI) {_VECOPCL(/= cI);} inline CMatlibVector& operator/=(const CMatlibVector& vecI) {_VECOPCL(/= vecI[i]);} inline CMatlibVector& operator/=(const CMatlibVector& vecI) {_VECOPCL(/= vecI[i]);} /* operator+= */ inline CMatlibVector& operator+=(const CReal& rI) {_VECOPCL(+= rI);} inline CMatlibVector& operator+=(const CComplex& cI) {_VECOPCL(+= cI);} inline CMatlibVector& operator+=(const CMatlibVector& vecI) {_VECOPCL(+= vecI[i]);} inline CMatlibVector& operator+=(const CMatlibVector& vecI) {_VECOPCL(+= vecI[i]);} /* operator-= */ inline CMatlibVector& operator-=(const CReal& rI) {_VECOPCL(-= rI);} inline CMatlibVector& operator-=(const CComplex& cI) {_VECOPCL(-= cI);} inline CMatlibVector& operator-=(const CMatlibVector& vecI) {_VECOPCL(-= vecI[i]);} inline CMatlibVector& operator-=(const CMatlibVector& vecI) {_VECOPCL(-= vecI[i]);} protected: EVecTy eVType; int iVectorLength; T* pData; }; /* operator* ---------------------------------------------------------------- */ inline CMatlibVector // cv, cv operator*(const CMatlibVector& cvA, const CMatlibVector& cvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] * cvB[i]);} inline CMatlibVector // rv, rv operator*(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), rvA[i] * rvB[i]);} inline CMatlibVector // cv, rv operator*(const CMatlibVector& cvA, const CMatlibVector& rvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] * rvB[i]);} inline CMatlibVector // rv, cv operator*(const CMatlibVector& rvB, const CMatlibVector& cvA) {_VECOP(CComplex, cvA.GetSize(), cvA[i] * rvB[i]);} template inline CMatlibVector // Tv, r operator*(const CMatlibVector& vecA, const CReal& rB) {_VECOP(T, vecA.GetSize(), vecA[i] * rB);} template inline CMatlibVector // r, Tv operator*(const CReal& rA, const CMatlibVector& vecB) {_VECOP(T, vecB.GetSize(), rA * vecB[i]);} template inline CMatlibVector // Tv, c operator*(const CMatlibVector& vecA, const CComplex& cB) {_VECOP(CComplex, vecA.GetSize(), vecA[i] * cB);} template inline CMatlibVector // c, Tv operator*(const CComplex& cA, const CMatlibVector& vecB) {_VECOP(CComplex, vecB.GetSize(), cA * vecB[i]);} /* operator/ ---------------------------------------------------------------- */ inline CMatlibVector // cv, cv operator/(const CMatlibVector& cvA, const CMatlibVector& cvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] / cvB[i]);} inline CMatlibVector // rv, rv operator/(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), rvA[i] / rvB[i]);} inline CMatlibVector // cv, rv operator/(const CMatlibVector& cvA, const CMatlibVector& rvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] / rvB[i]);} inline CMatlibVector // rv, cv operator/(const CMatlibVector& rvA, const CMatlibVector& cvB) {_VECOP(CComplex, rvA.GetSize(), rvA[i] / cvB[i]);} template inline CMatlibVector // Tv, r operator/(const CMatlibVector& vecA, const CReal& rB) {_VECOP(T, vecA.GetSize(), vecA[i] / rB);} template inline CMatlibVector // r, Tv operator/(const CReal& rA, const CMatlibVector& vecB) {_VECOP(T, vecB.GetSize(), rA / vecB[i]);} template inline CMatlibVector // Tv, c operator/(const CMatlibVector& vecA, const CComplex& cB) {_VECOP(CComplex, vecA.GetSize(), vecA[i] / cB);} template inline CMatlibVector // c, Tv operator/(const CComplex& cA, const CMatlibVector& vecB) {_VECOP(CComplex, vecB.GetSize(), cA / vecB[i]);} /* operator+ ---------------------------------------------------------------- */ inline CMatlibVector // cv, cv operator+(const CMatlibVector& cvA, const CMatlibVector& cvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] + cvB[i]);} inline CMatlibVector // rv, rv operator+(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), rvA[i] + rvB[i]);} inline CMatlibVector // cv, rv operator+(const CMatlibVector& cvA, const CMatlibVector& rvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] + rvB[i]);} inline CMatlibVector // rv, cv operator+(const CMatlibVector& rvA, const CMatlibVector& cvB) {_VECOP(CComplex, rvA.GetSize(), rvA[i] + cvB[i]);} template inline CMatlibVector // Tv, r operator+(const CMatlibVector& vecA, const CReal& rB) {_VECOP(T, vecA.GetSize(), vecA[i] + rB);} template inline CMatlibVector // r, Tv operator+(const CReal& rA, const CMatlibVector& vecB) {_VECOP(T, vecB.GetSize(), rA + vecB[i]);} template inline CMatlibVector // Tv, c operator+(const CMatlibVector& vecA, const CComplex& cB) {_VECOP(CComplex, vecA.GetSize(), vecA[i] + cB);} template inline CMatlibVector // c, Tv operator+(const CComplex& cA, const CMatlibVector& vecB) {_VECOP(CComplex, vecB.GetSize(), cA + vecB[i]);} /* operator- ---------------------------------------------------------------- */ inline CMatlibVector // cv, cv operator-(const CMatlibVector& cvA, const CMatlibVector& cvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] - cvB[i]);} inline CMatlibVector // rv, rv operator-(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), rvA[i] - rvB[i]);} inline CMatlibVector // cv, rv operator-(const CMatlibVector& cvA, const CMatlibVector& rvB) {_VECOP(CComplex, cvA.GetSize(), cvA[i] - rvB[i]);} inline CMatlibVector // rv, cv operator-(const CMatlibVector& rvA, const CMatlibVector& cvB) {_VECOP(CComplex, rvA.GetSize(), rvA[i] - cvB[i]);} template inline CMatlibVector // Tv, r operator-(const CMatlibVector& vecA, const CReal& rB) {_VECOP(T, vecA.GetSize(), vecA[i] - rB);} template inline CMatlibVector // r, Tv operator-(const CReal& rA, const CMatlibVector& vecB) {_VECOP(T, vecB.GetSize(), rA - vecB[i]);} template inline CMatlibVector // Tv, c operator-(const CMatlibVector& vecA, const CComplex& cB) {_VECOP(CComplex, vecA.GetSize(), vecA[i] - cB);} template inline CMatlibVector // c, Tv operator-(const CComplex& cA, const CMatlibVector& vecB) {_VECOP(CComplex, vecB.GetSize(), cA - vecB[i]);} /* Implementation ************************************************************** (the implementation of template classes must be in the header file!) */ template CMatlibVector::CMatlibVector(CMatlibVector& vecI) : eVType(VTY_CONST/*VTY_TEMP*/), iVectorLength(vecI.GetSize()), pData(NULL) { /* The copy constructor for the constant vector is a real copying task. But in the case of a temporary buffer only the pointer of the temporary buffer is used. The buffer of the temporary vector is then destroyed!!! Therefore the usage of "VTY_TEMP" should be done if the vector IS NOT USED IN A FUNCTION CALL, otherwise this vector will be destroyed afterwards (if the function argument is not declared with "&") */ if (iVectorLength > 0) { if (vecI.eVType == VTY_CONST) { /* Allocate data block for vector */ pData = new T[iVectorLength]; /* Copy vector */ for (int i = 0; i < iVectorLength; i++) pData[i] = vecI[i]; } else { /* We can define the copy constructor as a destroying operator of the input vector for performance reasons. This saves us from always copy the entire vector */ /* Take data pointer from input vector (steal it) */ pData = vecI.pData; /* Destroy other vector (temporary vectors only) */ vecI.pData = NULL; } } } /* Copy constructor for constant Matlib vectors */ template CMatlibVector::CMatlibVector(const CMatlibVector& vecI) : eVType(VTY_CONST), iVectorLength(vecI.GetSize()), pData(NULL) { if (iVectorLength > 0) { /* Allocate data block for vector */ pData = new T[iVectorLength]; /* Copy vector */ for (int i = 0; i < iVectorLength; i++) pData[i] = vecI[i]; } } template void CMatlibVector::Init(const int iIniLen, const T tIniVal) { iVectorLength = iIniLen; /* Allocate data block for vector */ if (iVectorLength > 0) { if (pData != NULL) delete[] pData; pData = new T[iVectorLength]; /* Init with init value */ for (int i = 0; i < iVectorLength; i++) pData[i] = tIniVal; } } template inline CMatlibVector CMatlibVector::operator()(const int iFrom, const int iTo) const { /* This is also capable of "wrap around" blocks (if the value in "iFrom" is larger then the "iTo" value) */ int i; const int iStartVal = iFrom - 1; if (iFrom > iTo) { /* Wrap around case */ CMatlibVector vecRet(iVectorLength - iStartVal + iTo, VTY_TEMP); int iCurPos = 0; for (i = iStartVal; i < iVectorLength; i++) vecRet[iCurPos++] = operator[](i); for (i = 0; i < iTo; i++) vecRet[iCurPos++] = operator[](i); return vecRet; } else { CMatlibVector vecRet(iTo - iStartVal, VTY_TEMP); for (i = iStartVal; i < iTo; i++) vecRet[i - iStartVal] = operator[](i); return vecRet; } } template inline CMatlibVector CMatlibVector::operator()(const int iFrom, const int iStep, const int iTo) const { CMatlibVector vecRet(size_t(abs(float(iTo - iFrom)) / abs(float(iStep))) + 1, VTY_TEMP); int iOutPos = 0; int i; if (iFrom > iTo) { const int iEnd = iTo - 2; for (i = iFrom - 1; i > iEnd; i += iStep) { vecRet[iOutPos] = operator[](i); iOutPos++; } } else { for (i = iFrom - 1; i < iTo; i += iStep) { vecRet[iOutPos] = operator[](i); iOutPos++; } } return vecRet; } template inline CMatlibVector& CMatlibVector::PutIn(const int iFrom, const int iTo, CMatlibVector& vecI) { const int iStart = iFrom - 1; const int iEnd = iTo - iStart; for (int i = 0; i < iEnd; i++) operator[](i + iStart) = vecI[i]; return *this; } template inline CMatlibVector& CMatlibVector::Merge(const CMatlibVector& vecA, T& tB) { const int iSizeA = vecA.GetSize(); for (int i = 0; i < iSizeA; i++) operator[](i) = vecA[i]; operator[](iSizeA) = tB; return *this; } template inline CMatlibVector& CMatlibVector::Merge(const CMatlibVector& vecA, const CMatlibVector& vecB) { int i; const int iSizeA = vecA.GetSize(); const int iSizeB = vecB.GetSize(); /* Put first vector */ for (i = 0; i < iSizeA; i++) operator[](i) = vecA[i]; /* Put second vector behind the first one, both together must have length of *this */ for (i = 0; i < iSizeB; i++) operator[](i + iSizeA) = vecB[i]; return *this; } template inline CMatlibVector& CMatlibVector::Merge(const CMatlibVector& vecA, const CMatlibVector& vecB, const CMatlibVector& vecC) { int i; const int iSizeA = vecA.GetSize(); const int iSizeB = vecB.GetSize(); const int iSizeC = vecC.GetSize(); const int iSizeAB = iSizeA + iSizeB; /* Put first vector */ for (i = 0; i < iSizeA; i++) operator[](i) = vecA[i]; /* Put second vector behind the first one */ for (i = 0; i < iSizeB; i++) operator[](i + iSizeA) = vecB[i]; /* Put third vector behind previous put vectors */ for (i = 0; i < iSizeC; i++) operator[](i + iSizeAB) = vecC[i]; return *this; } /******************************************************************************/ /* CMatlibMatrix class ********************************************************/ /******************************************************************************/ /* We define: Matrix[row][column] */ template class CMatlibMatrix { public: /* Construction, Destruction -------------------------------------------- */ CMatlibMatrix() : eVType(VTY_CONST), iRowSize(0), ppData(NULL) {} CMatlibMatrix(const int iNRowLen, const int iNColLen, const EVecTy eNTy = VTY_CONST) : eVType(eNTy), iRowSize(0), ppData(NULL) {Init(iNRowLen, iNColLen);} CMatlibMatrix(const int iNRowLen, const int iNColLen, const T tIniVal) : eVType(VTY_CONST), iRowSize(0), ppData(NULL) {Init(iNRowLen, iNColLen, tIniVal);} CMatlibMatrix(const CMatlibMatrix& matI); virtual ~CMatlibMatrix() {if (ppData != NULL) delete[] ppData;} void Init(const int iNRowLen, const int iNColLen, const T tIniVal = 0); inline int GetRowSize() const {return iRowSize;} inline int GetColSize() const {if (iRowSize > 0) return ppData[0].GetSize(); else return 0;} /* Operator[] (Regular indices!!!) */ inline CMatlibVector& operator[](int const iPos) const {_TESTRNGRM(iPos); return ppData[iPos];} inline CMatlibVector& operator[](int const iPos) {_TESTRNGWM(iPos); return ppData[iPos];} // For use as l value /* Operator() */ inline CMatlibVector& operator()(int const iPos) const {_TESTRNGRM(iPos - 1); return ppData[iPos - 1];} inline CMatlibVector& operator()(int const iPos) {_TESTRNGWM(iPos - 1); return ppData[iPos - 1];} // For use as l value CMatlibMatrix operator()(const int iRowFrom, const int iRowTo, const int iColFrom, const int iColTo) const; /* operator= */ inline CMatlibMatrix& operator=(const CMatlibMatrix& matI) {_TESTSIZEM(matI.GetRowSize()); _MATOPCL(= matI[i]);} inline CMatlibMatrix& operator=(const CMatlibMatrix& matI) {_TESTSIZEM(matI.GetRowSize()); _MATOPCL(= matI[i]);} /* operator+= */ inline CMatlibMatrix& operator+=(const CMatlibMatrix& matI) {_MATOPCL(+= matI[i]);} inline CMatlibMatrix& operator+=(const CMatlibMatrix& matI) {_MATOPCL(+= matI[i]);} /* operator-= */ inline CMatlibMatrix& operator-=(const CMatlibMatrix& matI) {_MATOPCL(-= matI[i]);} inline CMatlibMatrix& operator-=(const CMatlibMatrix& matI) {_MATOPCL(-= matI[i]);} /* operator*= */ inline CMatlibMatrix& operator*=(const CReal& rI) {_MATOPCL(*= rI);} inline CMatlibMatrix& operator*=(const CComplex& cI) {_MATOPCL(*= cI);} /* operator/= */ inline CMatlibMatrix& operator/=(const CReal& rI) {_MATOPCL(/= rI);} inline CMatlibMatrix& operator/=(const CComplex& cI) {_MATOPCL(/= cI);} protected: EVecTy eVType; int iRowSize; CMatlibVector* ppData; }; /* Help functions *************************************************************/ /* operator+ */ inline CMatlibMatrix // cm, cm operator+(const CMatlibMatrix& cmA, const CMatlibMatrix& cmB) { const int iRowSizeA = cmA.GetRowSize(); const int iColSizeA = cmA.GetColSize(); CMatlibMatrix matRet(iRowSizeA, iColSizeA, VTY_TEMP); for (int j = 0; j < iRowSizeA; j++) { for (int i = 0; i < iColSizeA; i++) matRet[j][i] = cmA[j][i] + cmB[j][i]; } return matRet; } /* operator- */ inline CMatlibMatrix // cm, cm operator-(const CMatlibMatrix& cmA, const CMatlibMatrix& cmB) { const int iRowSizeA = cmA.GetRowSize(); const int iColSizeA = cmA.GetColSize(); CMatlibMatrix matRet(iRowSizeA, iColSizeA, VTY_TEMP); for (int j = 0; j < iRowSizeA; j++) { for (int i = 0; i < iColSizeA; i++) matRet[j][i] = cmA[j][i] - cmB[j][i]; } return matRet; } /* operator* */ inline CMatlibVector // cm, cv operator*(const CMatlibMatrix& cmA, const CMatlibVector& cvB) { const int iRowSizeA = cmA.GetRowSize(); const int iSizeB = cvB.GetSize(); CMatlibVector vecRet(iSizeB, VTY_TEMP); for (int j = 0; j < iRowSizeA; j++) { vecRet[j] = (CReal) 0.0; for (int i = 0; i < iSizeB; i++) vecRet[j] += cmA[j][i] * cvB[i]; } return vecRet; } /* operator* */ inline CMatlibVector // rm, rv operator*(const CMatlibMatrix& rmA, const CMatlibVector& rvB) { const int iRowSizeA = rmA.GetRowSize(); const int iSizeB = rvB.GetSize(); CMatlibVector vecRet(iSizeB, VTY_TEMP); for (int j = 0; j < iRowSizeA; j++) { vecRet[j] = (CReal) 0.0; for (int i = 0; i < iSizeB; i++) vecRet[j] += rmA[j][i] * rvB[i]; } return vecRet; } /* operator* */ inline CMatlibMatrix // cm, cm operator*(const CMatlibMatrix& cmA, const CMatlibMatrix& cmB) { const int iRowSizeA = cmA.GetRowSize(); const int iRowSizeB = cmB.GetRowSize(); const int iColSizeB = cmB.GetColSize(); CMatlibMatrix matRet(iRowSizeA, iColSizeB, VTY_TEMP); for (int k = 0; k < iColSizeB; k++) { for (int j = 0; j < iRowSizeA; j++) { matRet[j][k] = (CReal) 0.0; for (int i = 0; i < iRowSizeB; i++) matRet[j][k] += cmA[j][i] * cmB[i][k]; } } return matRet; } /* operator* */ inline CMatlibMatrix // c, cm operator*(const CComplex& cA, const CMatlibMatrix& cmB) { const int iRowSizeB = cmB.GetRowSize(); const int iColSizeB = cmB.GetColSize(); CMatlibMatrix matRet(iRowSizeB, iColSizeB, VTY_TEMP); for (int k = 0; k < iColSizeB; k++) { for (int j = 0; j < iRowSizeB; j++) matRet[j][k] = cA * cmB[j][k]; } return matRet; } /* operator* */ inline CMatlibMatrix // r, rm operator*(const CReal& rA, const CMatlibMatrix& rmB) { const int iRowSizeB = rmB.GetRowSize(); const int iColSizeB = rmB.GetColSize(); CMatlibMatrix matRet(iRowSizeB, iColSizeB, VTY_TEMP); for (int k = 0; k < iColSizeB; k++) { for (int j = 0; j < iRowSizeB; j++) matRet[j][k] = rA * rmB[j][k]; } return matRet; } /* Implementation ************************************************************** (the implementation of template classes must be in the header file!) */ template CMatlibMatrix::CMatlibMatrix(const CMatlibMatrix& matI) : eVType(VTY_CONST), iRowSize(matI.GetRowSize()), ppData(NULL) { if (iRowSize > 0) { /* Allocate data block for vector */ ppData = new CMatlibVector[iRowSize]; /* Init column vectors and copy */ for (int i = 0; i < iRowSize; i++) { ppData[i].Init(matI.GetColSize()); /* Copy entire vector */ ppData[i] = matI[i]; } } } template void CMatlibMatrix::Init(const int iNRowLen, const int iNColLen, const T tIniVal) { iRowSize = iNRowLen; /* Allocate data block for vector */ if (iRowSize > 0) { if (ppData != NULL) delete[] ppData; ppData = new CMatlibVector[iRowSize]; /* Init column vectors and set to init value */ for (int i = 0; i < iRowSize; i++) ppData[i].Init(iNColLen, tIniVal); } } template inline CMatlibMatrix CMatlibMatrix::operator()(const int iRowFrom, const int iRowTo, const int iColFrom, const int iColTo) const { const int iStartRow = iRowFrom - 1; const int iStartCol = iColFrom - 1; CMatlibMatrix matRet(iRowTo - iStartRow, iColTo - iStartCol, VTY_TEMP); for (int j = iStartRow; j < iRowTo; j++) { for (int i = iStartCol; i < iColTo; i++) matRet[j - iStartRow][i - iStartCol] = operator[](j)[i]; } return matRet; } /* Include toolboxes after all type definitions */ #include "MatlibStdToolbox.h" #include "MatlibSigProToolbox.h" #endif /* _MATLIB_H_ */ qsstv_8.2.12/qsstv/drmtx/common/matlib/MatlibSigProToolbox.cpp000664 001750 001750 00000036303 12440612574 024465 0ustar00jomajoma000000 000000 /******************************************************************************\ * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * c++ Mathematic Library (Matlib), signal processing toolbox * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "MatlibSigProToolbox.h" /* Implementation *************************************************************/ CMatlibVector Hann(const int iLen) { int iHalf, i; CMatlibVector fvRet(iLen, VTY_TEMP); if (iLen % 2) { /* Odd length window */ iHalf = (iLen + 1) / 2; /* Hanning window */ CMatlibVector vecTemp(iHalf); CMatlibVector w(iHalf); for (i = 0; i < iHalf; i++) vecTemp[i] = (CReal) i; w = (CReal) 0.5 * (1 - Cos((CReal) 2.0 * crPi * vecTemp / (iLen - 1))); /* Make symmetric window */ return fvRet.Merge(w, w(iHalf - 1, -1, 1)); } else { /* Even length window */ iHalf = iLen / 2; /* Hanning window */ CMatlibVector vecTemp(iHalf); CMatlibVector w(iHalf); for (i = 0; i < iHalf; i++) vecTemp[i] = (CReal) i; w = (CReal) 0.5 * (1 - Cos((CReal) 2.0 * crPi * vecTemp / (iLen - 1))); /* Make symmetric window */ return fvRet.Merge(w, w(iHalf, -1, 1)); } } CMatlibVector Hamming(const int iLen) { int iHalf, i; CMatlibVector fvRet(iLen, VTY_TEMP); if (iLen % 2) { /* Odd length window */ iHalf = (iLen + 1) / 2; /* Hanning window */ CMatlibVector vecTemp(iHalf); CMatlibVector w(iHalf); for (i = 0; i < iHalf; i++) vecTemp[i] = (CReal) i; w = (CReal) 0.54 - (CReal) 0.46 * Cos((CReal) 2.0 * crPi * vecTemp / (iLen - 1)); /* Make symmetric window */ return fvRet.Merge(w, w(iHalf - 1, -1, 1)); } else { /* Even length window */ iHalf = iLen / 2; /* Hanning window */ CMatlibVector vecTemp(iHalf); CMatlibVector w(iHalf); for (i = 0; i < iHalf; i++) vecTemp[i] = (CReal) i; w = (CReal) 0.54 - (CReal) 0.46 * Cos((CReal) 2.0 * crPi * vecTemp / (iLen - 1)); /* Make symmetric window */ return fvRet.Merge(w, w(iHalf, -1, 1)); } } CMatlibVector Nuttallwin(const int iLen) { CMatlibVector fvRet(iLen, VTY_TEMP); /* Nuttall coefficients */ const CReal rA0 = (CReal) 0.3635819; const CReal rA1 = (CReal) 0.4891775; const CReal rA2 = (CReal) 0.1365995; const CReal rA3 = (CReal) 0.0106411; const CReal rArg = (CReal) 2.0 * crPi / (iLen - 1); for (int i = 0; i < iLen; i++) { fvRet[i] = rA0 - rA1 * Cos(rArg * i) + rA2 * Cos(rArg * i * 2) - rA3 * Cos(rArg * i * 3); } return fvRet; } CMatlibVector Bartlett(const int iLen) { const int iHalf = (int) Ceil((CReal) iLen / 2); CMatlibVector fvHalfWin(iHalf); CMatlibVector fvRet(iLen, VTY_TEMP); for (int i = 0; i < iHalf; i++) fvHalfWin[i] = (CReal) 2.0 * i / (iLen - 1); /* Build complete output vector depending on odd or even input length */ if (iLen % 2) fvRet.Merge(fvHalfWin, fvHalfWin(iHalf - 1, -1, 1)); /* Odd */ else fvRet.Merge(fvHalfWin, fvHalfWin(iHalf, -1, 1)); /* Even */ return fvRet; } CMatlibVector Triang(const int iLen) { const int iHalf = (int) Ceil((CReal) iLen / 2); CMatlibVector fvHalfWin(iHalf); CMatlibVector fvRet(iLen, VTY_TEMP); /* Build complete output vector depending on odd or even input length */ if (iLen % 2) { for (int i = 0; i < iHalf; i++) fvHalfWin[i] = (CReal) 2.0 * (i + 1) / (iLen + 1); fvRet.Merge(fvHalfWin, fvHalfWin(iHalf - 1, -1, 1)); /* Odd */ } else { for (int i = 0; i < iHalf; i++) fvHalfWin[i] = ((CReal) 2.0 * (i + 1) - 1) / iLen; fvRet.Merge(fvHalfWin, fvHalfWin(iHalf, -1, 1)); /* Even */ } return fvRet; } CMatlibVector Kaiser(const int iLen, const CReal rBeta) { CReal rX; const int iIsOdd = iLen % 2; const int n = (iLen + 1) / 2; /* Half vector size, round up */ CMatlibVector fvRet(iLen); CMatlibVector fvW(n); const CReal rNorm = Abs(Besseli((CReal) 0.0, rBeta)); const CReal rXind = (iLen - 1) * (iLen - 1); if (iIsOdd == 0) rX = (CReal) 0.5; else rX = (CReal) 0.0; for (int i = 0; i < n; i++) { fvW[i] = Besseli((CReal) 0.0, rBeta * Sqrt((CReal) 1.0 - (CReal) 4.0 * rX * rX / rXind)) / rNorm; rX += (CReal) 1.0; } /* Symmetrical window */ fvRet.Merge(fvW(n, -1, iIsOdd + 1), fvW); return Abs(fvRet); } CReal Besseli(const CReal rNu, const CReal rZ) { const CReal rEp = (CReal) 10e-9; /* Define accuracy */ const CReal rY = rZ / (CReal) 2.0; CReal rReturn = (CReal) 1.0; CReal rD = (CReal) 1.0; CReal rS = (CReal) 1.0; /* Only nu = 0 is supported right now! */ if (rNu != (CReal) 0.0) { #ifdef _DEBUG_ DebugError("MatLibr: Besseli function", "The nu = ", rNu, \ " is not supported, only nu = ", 0); #endif } for (int i = 1; i <= 25 && rReturn * rEp <= rS; i++) { rD *= rY / i; rS = rD * rD; rReturn += rS; } return rReturn; } CMatlibVector Randn(const int iLen) { /* Add some constant distributed random processes together */ _VECOP(CReal, iLen, (CReal) ((((CReal) rand() + rand() + rand() + rand() + rand() + rand() + rand()) / RAND_MAX - 0.5) * /* sqrt(3) * 2 / sqrt(7) */ 1.3093)); } CMatlibVector Filter(const CMatlibVector& fvB, const CMatlibVector& fvA, const CMatlibVector& fvX, CMatlibVector& fvZ) { int m, n, iLenCoeff; const int iSizeA = fvA.GetSize(); const int iSizeB = fvB.GetSize(); const int iSizeX = fvX.GetSize(); const int iSizeZ = fvZ.GetSize(); CMatlibVector fvY(iSizeX, VTY_TEMP); CMatlibVector fvANew, fvBNew; if ((iSizeA == 1) && (fvA[0] == (CReal) 1.0)) { /* FIR filter ------------------------------------------------------- */ const int iSizeXNew = iSizeX + iSizeZ; CMatlibVector rvXNew(iSizeXNew); /* Add old values to input vector */ rvXNew.Merge(fvZ, fvX); /* Actual convolution */ for (m = 0; m < iSizeX; m++) { fvY[m] = (CReal) 0.0; for (n = 0; n < iSizeB; n++) fvY[m] += fvB[n] * rvXNew[m + iSizeB - n - 1]; } /* Save last samples in state vector */ fvZ = rvXNew(iSizeXNew - iSizeZ + 1, iSizeXNew); } else { /* IIR filter ------------------------------------------------------- */ /* Length of coefficients */ iLenCoeff = (int) Max((CReal) iSizeB, (CReal) iSizeA); /* Make fvB and fvA the same length (zero padding) */ if (iSizeB > iSizeA) { fvBNew.Init(iSizeB); fvANew.Init(iSizeB); fvBNew = fvB; fvANew.Merge(fvA, Zeros(iSizeB - iSizeA)); } else { fvBNew.Init(iSizeA); fvANew.Init(iSizeA); fvANew = fvA; fvBNew.Merge(fvB, Zeros(iSizeA - iSizeB)); } /* Filter is implemented as a transposed direct form II structure */ for (m = 0; m < iSizeX; m++) { /* y(m) = (b(1) x(m) + z_1(m - 1)) / a(1) */ fvY[m] = (fvBNew[0] * fvX[m] + fvZ[0]) / fvANew[0]; for (n = 1; n < iLenCoeff; n++) { /* z_{n - 2}(m) = b(n - 1) x(m) + z_{n - 1}(m - 1) - a(n - 1) y(m) */ fvZ[n - 1] = fvBNew[n] * fvX[m] + fvZ[n] - fvANew[n] * fvY[m]; } } } return fvY; } CMatlibVector FirLP(const CReal rNormBW, const CMatlibVector& rvWin) { /* Lowpass filter design using windowing method */ const int iLen = rvWin.GetSize(); const int iHalfLen = (int) Floor((CReal) iLen / 2); CMatlibVector fvRet(iLen, VTY_TEMP); /* Generate truncuated ideal response */ for (int i = 0; i < iLen; i++) fvRet[i] = rNormBW * Sinc(rNormBW * (i - iHalfLen)); /* Apply window */ fvRet *= rvWin; return fvRet; } CMatlibVector FirFiltDec(const CMatlibVector& cvB, const CMatlibVector& cvX, CMatlibVector& cvZ, const int iDecFact) { int m, n, iCurPos; const int iSizeX = cvX.GetSize(); const int iSizeZ = cvZ.GetSize(); const int iSizeB = cvB.GetSize(); const int iSizeXNew = iSizeX + iSizeZ; const int iSizeFiltHist = iSizeB - 1; int iNewLenZ; int iDecSizeY; if (iSizeFiltHist >= iSizeXNew) { /* Special case if no new output can be calculated */ iDecSizeY = 0; iNewLenZ = iSizeXNew; } else { /* Calculate the number of output bits which can be generated from the provided input vector */ iDecSizeY = (int) (((CReal) iSizeXNew - iSizeFiltHist - 1) / iDecFact + 1); /* Since the input vector length must not be a multiple of "iDecFact", some input bits will be unused. To store this number, the size of the state vector "Z" is adapted */ iNewLenZ = iSizeFiltHist - (iDecSizeY * iDecFact - (iSizeXNew - iSizeFiltHist)); } CMatlibVector cvY(iDecSizeY, VTY_TEMP); CMatlibVector cvXNew(iSizeXNew); /* Add old values to input vector */ cvXNew.Merge(cvZ, cvX); /* FIR filter */ for (m = 0; m < iDecSizeY; m++) { iCurPos = m * iDecFact + iSizeFiltHist; cvY[m] = (CReal) 0.0; for (n = 0; n < iSizeB; n++) cvY[m] += cvB[n] * cvXNew[iCurPos - n]; } /* Save last samples in state vector */ cvZ.Init(iNewLenZ); cvZ = cvXNew(iSizeXNew - iNewLenZ + 1, iSizeXNew); return cvY; } CMatlibVector Levinson(const CMatlibVector& vecrRx, const CMatlibVector& vecrB) { /* The levinson recursion [S. Haykin] This algorithm solves the following equations: Rp ap = ep u1, Rp Xp = b, where Rp is a Toepliz-matrix of vector prRx and b = prB is an arbitrary correlation-vector. The Result is ap = prA. Parts of the following code are taken from Ptolemy (http://ptolemy.eecs.berkeley.edu/) */ const int iLength = vecrRx.GetSize(); CRealVector vecrX(iLength, VTY_TEMP); CReal rGamma; CReal rGammaCap; CReal rDelta; CReal rE; CReal rQ; int i, j; CRealVector vecraP(iLength); CRealVector vecrA(iLength); /* Initialize the recursion --------------------------------------------- */ // (a) First coefficient is always unity vecrA[0] = (CReal) 1.0; vecraP[0] = (CReal) 1.0; // (b) vecrX[0] = vecrB[0] / vecrRx[0]; // (c) Initial prediction error is simply the zero-lag of // of the autocorrelation, or the signal power estimate. rE = vecrRx[0]; /* Main loop ------------------------------------------------------------ */ // The order recurrence for (j = 0; j < iLength - 1; j++) { const int iNextInd = j + 1; // (a) Compute the new gamma rGamma = vecrRx[iNextInd]; for (i = 1; i < iNextInd; i++) rGamma += vecrA[i] * vecrRx[iNextInd - i]; // (b), (d) Compute and output the reflection coefficient // (which is also equal to the last AR parameter) vecrA[j + 1] = rGammaCap = - rGamma / rE; // (c) for (i = 1; i < iNextInd; i++) vecraP[i] = vecrA[i] + rGammaCap * vecrA[iNextInd - i]; // Swap a and aP for next order recurrence for (i = 1; i < iNextInd; i++) vecrA[i] = vecraP[i]; // (e) Update the prediction error power rE = rE * ((CReal) 1.0 - rGammaCap * rGammaCap); // (f) rDelta = (CReal) 0.0; for (i = 0; i < iNextInd; i++) rDelta += vecrX[i] * vecrRx[iNextInd - i]; // (g), (i) vecrX[iNextInd] = rQ = (vecrB[iNextInd] - rDelta) / rE; // (h) for (i = 0; i < iNextInd; i++) vecrX[i] = vecrX[i] + rQ * vecrA[iNextInd - i]; } return vecrX; } CMatlibVector Levinson(const CMatlibVector& veccRx, const CMatlibVector& veccB) { /* The levinson recursion [S. Haykin] COMPLEX version! This algorithm solves the following equations: Rp ap = ep u1, Rp Xp = b, where Rp is a Toepliz-matrix of vector prRx and b = prB is an arbitrary correlation-vector. The Result is ap = prA. Parts of the following code are taken from Ptolemy (http://ptolemy.eecs.berkeley.edu/) */ const int iLength = veccRx.GetSize(); CComplexVector veccX(iLength, VTY_TEMP); CComplex cGamma; CComplex cGammaCap; CComplex cDelta; CReal rE; CComplex cQ; int i, j; CComplexVector veccaP(iLength); CComplexVector veccA(iLength); /* Initialize the recursion --------------------------------------------- */ // (a) First coefficient is always unity veccA[0] = (CReal) 1.0; veccaP[0] = (CReal) 1.0; // (b) veccX[0] = veccB[0] / veccRx[0]; // (c) Initial prediction error is simply the zero-lag of // of the autocorrelation, or the signal power estimate. rE = Real(veccRx[0]); /* Main loop ------------------------------------------------------------ */ // The order recurrence for (j = 0; j < iLength - 1; j++) { const int iNextInd = j + 1; // (a) Compute the new gamma cGamma = veccRx[iNextInd]; for (i = 1; i < iNextInd; i++) cGamma += veccA[i] * veccRx[iNextInd - i]; // (b), (d) Compute and output the reflection coefficient // (which is also equal to the last AR parameter) veccA[iNextInd] = cGammaCap = - cGamma / rE; // (c) for (i = 1; i < iNextInd; i++) veccaP[i] = veccA[i] + cGammaCap * Conj(veccA[iNextInd - i]); // Swap a and aP for next order recurrence for (i = 1; i < iNextInd; i++) veccA[i] = veccaP[i]; // (e) Update the prediction error power rE = rE * ((CReal) 1.0 - SqMag(cGammaCap)); // (f) cDelta = (CReal) 0.0; for (i = 0; i < iNextInd; i++) cDelta += veccX[i] * veccRx[iNextInd - i]; // (g), (i) veccX[iNextInd] = cQ = (veccB[iNextInd] - cDelta) / rE; // (h) for (i = 0; i < iNextInd; i++) veccX[i] = veccX[i] + cQ * Conj(veccA[iNextInd - i]); } return veccX; } CMatlibVector DomEig(const CMatlibMatrix& rmI, const CReal rEpsilon) { const int iMaxNumIt = 150; /* Maximum number of iterations */ const int iSize = rmI.GetColSize(); CMatlibVector vecrV(iSize, VTY_TEMP); CMatlibVector vecrVold(iSize); CMatlibVector vecrY(iSize); CReal rLambda, rLambdaold, rError; /* Implementing the power method for getting the dominant eigenvector */ /* Start value for eigenvector */ vecrV = Ones(iSize); rLambda = rLambdaold = (CReal) 1.0; rError = _MAXREAL; int iItCnt = iMaxNumIt; while ((iItCnt > 0) && (rError > rEpsilon)) { /* Save old values needed error calculation */ vecrVold = vecrV; rLambdaold = rLambda; /* Actual power method calculations */ rLambda = Max(Abs(vecrV)); vecrV = (CReal) 1.0 / rLambda * rmI * vecrV; /* Take care of number of iterations and error calculations */ iItCnt--; rError = Max(Abs(rLambda - rLambdaold), Max(Abs(vecrV - vecrVold))); } return vecrV; } CReal LinRegr(const CMatlibVector& rvX, const CMatlibVector& rvY) { /* Linear regression */ CReal Xm(Mean(rvX)); CReal Ym(Mean(rvY)); CRealVector Xmrem(rvX - Xm); /* Remove mean of W */ /* Return only the gradient, we do not calculate and return the offset */ return Sum(Xmrem * (rvY - Ym)) / Sum(Xmrem * Xmrem); } qsstv_8.2.12/qsstv/drmtx/common/matlib/MatlibSigProToolbox.h000664 001750 001750 00000011267 12440612574 024134 0ustar00jomajoma000000 000000 /******************************************************************************\ * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * c++ Mathematic Library (Matlib), signal processing toolbox * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #ifndef _MATLIB_SIGNAL_PROC_TOOLBOX_H_ #define _MATLIB_SIGNAL_PROC_TOOLBOX_H_ #include "Matlib.h" #include "MatlibStdToolbox.h" #include /* Helpfunctions **************************************************************/ /* Randomize functions */ CMatlibVector Randn(const int iLen); inline CMatlibVector Rand(const int iLen) {_VECOP(CReal, iLen, (CReal) rand() / RAND_MAX);} /* Window functions */ CMatlibVector Hann(const int iLen); CMatlibVector Hamming(const int iLen); CMatlibVector Nuttallwin(const int iLen); CMatlibVector Bartlett(const int iLen); CMatlibVector Triang(const int iLen); CMatlibVector Kaiser(const int iLen, const CReal rBeta); /* Bessel function */ CReal Besseli(const CReal rNu, const CReal rZ); /* Filter data with a recursive (IIR) or nonrecursive (FIR) filter */ CMatlibVector Filter(const CMatlibVector& fvB, const CMatlibVector& fvA, const CMatlibVector& fvX, CMatlibVector& fvZ); /* Levinson durbin recursion */ CMatlibVector Levinson(const CMatlibVector& vecrRx, const CMatlibVector& vecrB); CMatlibVector Levinson(const CMatlibVector& veccRx, const CMatlibVector& veccB); /* Sinc-function */ inline CReal Sinc(const CReal& rI) {return rI == (CReal) 0.0 ? (CReal) 1.0 : sin(crPi * rI) / (crPi * rI);} inline CMatlibVector Sinc(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Sinc(fvI[i]));} /* My own functions --------------------------------------------------------- */ /* Dominant eigenvector */ CMatlibVector DomEig(const CMatlibMatrix& rmI, const CReal rEpsilon = 1e-5); /* Linear regression */ CReal LinRegr(const CMatlibVector& rvX, const CMatlibVector& rvY); /* Lowpass filter design using windowing method */ CMatlibVector FirLP(const CReal rNormBW, const CMatlibVector& rvWin); /* Complex FIR filter with decimation */ CMatlibVector FirFiltDec(const CMatlibVector& cvB, const CMatlibVector& cvX, CMatlibVector& cvZ, const int iDecFact); /* Squared magnitude */ inline CReal SqMag(const CComplex& cI) {return cI.real() * cI.real() + cI.imag() * cI.imag();} inline CReal SqMag(const CReal& rI) {return rI * rI;} inline CMatlibVector SqMag(const CMatlibVector& veccI) {_VECOP(CReal, veccI.GetSize(), SqMag(veccI[i]));} inline CMatlibVector SqMag(const CMatlibVector& vecrI) {_VECOP(CReal, vecrI.GetSize(), SqMag(vecrI[i]));} /* One pole recursion (first order IIR) y_n = lambda * y_{n - 1} + (1 - lambda) * x_n */ inline void IIR1(CReal& rY, const CReal& rX, const CReal rLambda) {rY = rLambda * (rY - rX) + rX;} inline void IIR1(CComplex& cY, const CComplex& cX, const CReal rLambda) {cY = rLambda * (cY - cX) + cX;} inline void IIR1(CMatlibVector& rY, const CMatlibVector& rX, const CReal rLambda) { const int iSize = rY.GetSize(); for (int i = 0; i < iSize; i++) IIR1(rY[i], rX[i], rLambda); } /* Two-sided one pole recursion */ inline void IIR1TwoSided(CReal& rY, const CReal& rX, const CReal rLamUp, const CReal rLamDown) {rX > rY ? IIR1(rY, rX, rLamUp) : IIR1(rY, rX, rLamDown);} /* Get lambda for one-pole recursion from time constant */ inline CReal IIR1Lam(const CReal& rTau, const CReal& rFs) {return exp((CReal) -1.0 / (rTau * rFs));} #endif /* _MATLIB_SIGNAL_PROC_TOOLBOX_H_ */ qsstv_8.2.12/qsstv/drmtx/common/matlib/MatlibStdToolbox.cpp000664 001750 001750 00000044407 12440612574 024020 0ustar00jomajoma000000 000000 /******************************************************************************\ * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * c++ Mathematic Library (Matlib) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "MatlibStdToolbox.h" /* Implementation *************************************************************/ CReal Min(const CMatlibVector& rvI) { const int iSize = rvI.GetSize(); CReal rMinRet = rvI[0]; for (int i = 1; i < iSize; i++) { if (rvI[i] < rMinRet) rMinRet = rvI[i]; } return rMinRet; } void Min(CReal& rMinVal, int& iMinInd, const CMatlibVector& rvI) { const int iSize = rvI.GetSize(); rMinVal = rvI[0]; /* Init actual minimum value */ iMinInd = 0; /* Init index of minimum */ for (int i = 1; i < iSize; i++) { if (rvI[i] < rMinVal) { rMinVal = rvI[i]; iMinInd = i; } } } CReal Max(const CMatlibVector& rvI) { CReal rMaxRet; int iMaxInd; /* Not used by this function */ Max(rMaxRet, iMaxInd, rvI); return rMaxRet; } void Max(CReal& rMaxVal, int& iMaxInd, const CMatlibVector& rvI) { const int iSize = rvI.GetSize(); rMaxVal = rvI[0]; /* Init actual maximum value */ iMaxInd = 0; /* Init index of maximum */ for (int i = 1; i < iSize; i++) { if (rvI[i] > rMaxVal) { rMaxVal = rvI[i]; iMaxInd = i; } } } CMatlibVector Sort(const CMatlibVector& rvI) { const int iSize = rvI.GetSize(); const int iEnd = iSize - 1; CMatlibVector fvRet(iSize, VTY_TEMP); /* Copy input vector in output vector */ fvRet = rvI; /* Loop through the array one less than its total cell count */ for (int i = 0; i < iEnd; i++) { /* Loop through every cell (value) in array */ for (int j = 0; j < iEnd; j++) { /* Compare the values and switch if necessary */ if (fvRet[j] > fvRet[j + 1]) { const CReal rSwap = fvRet[j]; fvRet[j] = fvRet[j + 1]; fvRet[j + 1] = rSwap; } } } return fvRet; } CMatlibMatrix Eye(const int iLen) { CMatlibMatrix matrRet(iLen, iLen, VTY_TEMP); /* Set all values except of the diagonal to zero, diagonal entries = 1 */ for (int i = 0; i < iLen; i++) { for (int j = 0; j < iLen; j++) { if (i == j) matrRet[i][j] = (CReal) 1.0; else matrRet[i][j] = (CReal) 0.0; } } return matrRet; } CMatlibMatrix Diag(const CMatlibVector& cvI) { const int iSize = cvI.GetSize(); CMatlibMatrix matcRet(iSize, iSize, VTY_TEMP); /* Set the diagonal to the values of the input vector */ for (int i = 0; i < iSize; i++) { for (int j = 0; j < iSize; j++) { if (i == j) matcRet[i][j] = cvI[i]; else matcRet[i][j] = (CReal) 0.0; } } return matcRet; } CReal Trace(const CMatlibMatrix& rmI) { const int iSize = rmI.GetRowSize(); /* matrix must be square */ CReal rReturn = (CReal) 0.0; for (int i = 0; i < iSize; i++) rReturn += rmI[i][i]; return rReturn; } CMatlibMatrix Toeplitz(const CMatlibVector& cvI) { const int iSize = cvI.GetSize(); CMatlibMatrix matcRet(iSize, iSize, VTY_TEMP); /* Create Toeplitz matrix */ for (int i = 0; i < iSize; i++) { for (int j = 0; j < iSize; j++) { if (i < j) matcRet[i][j] = cvI[j - i]; else matcRet[i][j] = Conj(cvI[i - j]); } } return matcRet; } CMatlibMatrix Transp(const CMatlibMatrix& cmI) { const int iRowSize = cmI.GetRowSize(); const int iColSize = cmI.GetColSize(); /* Swaped row and column size due to transpose operation */ CMatlibMatrix matcRet(iColSize, iRowSize, VTY_TEMP); /* Transpose matrix */ for (int i = 0; i < iRowSize; i++) { for (int j = 0; j < iColSize; j++) matcRet[j][i] = cmI[i][j]; } return matcRet; } CMatlibMatrix Inv(const CMatlibMatrix& matrI) { /* Parts of the following code are taken from Ptolemy (http://ptolemy.eecs.berkeley.edu/) The input matrix must be square, this is NOT checked here! */ _COMPLEX temp; int row, col, i; const int iSize = matrI.GetColSize(); CMatlibMatrix matrRet(iSize, iSize, VTY_TEMP); /* Make a working copy of input matrix */ CMatlibMatrix work(matrI); /* Set result to be the identity matrix */ matrRet = Eye(iSize); for (i = 0; i < iSize; i++) { /* Check that the element in (i,i) is not zero */ if ((Real(work[i][i]) == 0) && (Imag(work[i][i]) == 0)) { /* Swap with a row below this one that has a non-zero element in the same column */ for (row = i + 1; row < iSize; row++) { if ((Real(work[i][i]) != 0) || (Imag(work[i][i]) != 0)) break; } // TEST if (row == iSize) { printf("couldn't invert matrix, possibly singular.\n"); matrRet = Eye(iSize); return matrRet; } /* Swap rows */ for (col = 0; col < iSize; col++) { temp = work[i][col]; work[i][col] = work[row][col]; work[row][col] = temp; temp = matrRet[i][col]; matrRet[i][col] = matrRet[row][col]; matrRet[row][col] = temp; } } /* Divide every element in the row by element (i,i) */ temp = work[i][i]; for (col = 0; col < iSize; col++) { work[i][col] /= temp; matrRet[i][col] /= temp; } /* Zero out the rest of column i */ for (row = 0; row < iSize; row++) { if (row != i) { temp = work[row][i]; for (col = iSize - 1; col >= 0; col--) { work[row][col] -= (temp * work[i][col]); matrRet[row][col] -= (temp * matrRet[i][col]); } } } } return matrRet; } /* This function is not listed in the header file. It shall be used only for Matlib internal calculations */ CComplex _integral(MATLIB_CALLBACK_QAUD f, const CReal a, const CReal b, const CReal errorBound, CReal& integralBound, _BOOLEAN& integralError, const CReal ru) { /* The following code (inclusive the actual Quad() function) is based on a JavaScript Example written by Lucio Tavernini. The code is hosted at http://tavernini.com/integral.shtml. Description: Adaptive Simpson's Quadrature _integral(f, a, b, errorBound) attempts to integrate f from a to b while keeping the asymptotic error estimate below errorBound using an adaptive implementation of Simpson's rule. Notes: Instead of NaN we use _MAXREAL. Infinite bounds are not allowed! The lower bound must always be smaller than the higher bound! */ CReal left, right, h, h6, bound; CComplex fa, fb, v1, v2, error, value; int m1, jend, mstart, j; if (integralError) return _MAXREAL; /* NaN */ /* Integrate over [a,b]. Initialize */ const int max = 1024; CRealVector x(max); CComplexVector f1(max); CComplexVector f2(max); CComplexVector f3(max); CComplexVector v(max); int step = 1; int m = 1; bound = errorBound; value = 0; h = b - a; x[0] = a; f1[0] = f(a); f2[0] = f((CReal) 0.5 * (a + b)); f3[0] = f(b); v[0] = h * (f1[0] + (CReal) 4.0 * f2[0] + f3[0]) / (CReal) 6.0; do { /* Are we going to go forward or backward? */ if (step == -1) { /* Forward: j = m,...,max */ step = 1; j = m + 1; jend = max; m = 0; mstart = 0; } else { /* Backward: j = m,...,1 */ step = -1; j = m - 1; jend = -1; m = max - 1; mstart = max - 1; } h = (CReal) 0.5 * h; h6 = h / 6; bound = (CReal) 0.5 * bound; do { left = x[j]; right = x[j] + (CReal) 0.5 * h; /* Complete loss of significance? */ if (left >= right) { printf("integral: Error 1"); return value; } fa = f(x[j] + (CReal) 0.5 * h); fb = f(x[j] + (CReal) 1.5 * h); v1 = h6 * (f1[j] + (CReal) 4.0 * fa + f2[j]); v2 = h6 * (f2[j] + (CReal) 4.0 * fb + f3[j]); error = (v[j] - v1 - v2) / (CReal) 15.0; if ((Abs(error) <= bound) || (Abs(v1 + v2) < Abs(value) * ru)) value = ((v1 + v2) + value) - error; else { if (integralError) return _MAXREAL; /* NaN */ /* Are we out of memory? */ if (m == j) { left = x[j]; right = x[j] + (CReal) 0.5 * h; /* Complete loss of significance? */ if (left >= right) { printf("integral: Error 2"); return value; } value += _integral(f, left, x[j] + 2 * h, bound, integralBound, integralError, ru); } else { /* No, we are not */ left = x[j]; right = x[j] + (CReal) 0.125 * h; if (left >= right) { /* The error bound specified is too small! */ integralError = true; return _MAXREAL; /* NaN */ } m1 = m + step; x[m] = x[j]; x[m1] = x[j] + h; v[m] = v1; v[m1] = v2; f1[m] = f1[j]; f2[m] = fa; f3[m] = f2[j]; f1[m1] = f2[j]; f2[m1] = fb; f3[m1] = f3[j]; m += 2 * step; } } j += step; } while (j != jend); } while (m != mstart); if (integralError) return _MAXREAL; /* NaN */ else return value; } CComplex Quad(MATLIB_CALLBACK_QAUD f, const CReal a, const CReal b, const CReal errorBound) { /* Set globals */ /* Generate rounding unit */ CReal value; CReal ru = (CReal) 1.0; do { ru = (CReal) 0.5 * ru; value = (CReal) 1.0 + ru; } while (value != (CReal) 1.0); ru *= 2; CReal integralBound = errorBound; _BOOLEAN integralError = false; /* Compute */ return _integral(f, a, b, errorBound, integralBound, integralError, ru); } CMatlibVector Fft(const CMatlibVector& cvI, const CFftPlans& FftPlans) { int i; CFftPlans* pCurPlan; fftw_complex* pFftwComplexIn; fftw_complex* pFftwComplexOut; const int n(cvI.GetSize()); CMatlibVector cvReturn(n, VTY_TEMP); /* If input vector has zero length, return */ if (n == 0) return cvReturn; /* Check, if plans are already created, else: create it */ if (!FftPlans.IsInitialized()) { pCurPlan = new CFftPlans; pCurPlan->Init(n); } else { /* Ugly, but ok: We transform "const" object in "non constant" object since we KNOW that the original object is not constant since it was already initialized! */ pCurPlan = (CFftPlans*) &FftPlans; } pFftwComplexIn = pCurPlan->pFftwComplexIn; pFftwComplexOut = pCurPlan->pFftwComplexOut; /* fftw (Homepage: http://www.fftw.org/) */ for (i = 0; i < n; i++) { pFftwComplexIn[i][0] = cvI[i].real(); pFftwComplexIn[i][1] = cvI[i].imag(); /* pa0mbo [0] [1] was .re .im */ } /* Actual fftw call */ fftw_execute(pCurPlan->FFTPlForw); for (i = 0; i < n; i++) cvReturn[i] = CComplex(pFftwComplexOut[i][0], pFftwComplexOut[i][1]); if (!FftPlans.IsInitialized()) delete pCurPlan; return cvReturn; } CMatlibVector Ifft(const CMatlibVector& cvI, const CFftPlans& FftPlans) { int i; CFftPlans* pCurPlan; fftw_complex* pFftwComplexIn; fftw_complex* pFftwComplexOut; const int n(cvI.GetSize()); CMatlibVector cvReturn(n, VTY_TEMP); /* If input vector has zero length, return */ if (n == 0) return cvReturn; /* Check, if plans are already created, else: create it */ if (!FftPlans.IsInitialized()) { pCurPlan = new CFftPlans; pCurPlan->Init(n); } else { /* Ugly, but ok: We transform "const" object in "non constant" object since we KNOW that the original object is not constant since it was already initialized! */ pCurPlan = (CFftPlans*) &FftPlans; } pFftwComplexIn = pCurPlan->pFftwComplexIn; pFftwComplexOut = pCurPlan->pFftwComplexOut; /* fftw (Homepage: http://www.fftw.org/) */ for (i = 0; i < n; i++) { pFftwComplexIn[i][0] = cvI[i].real(); pFftwComplexIn[i][1] = cvI[i].imag(); // printf("vullen pFftwComplexIn %d %14.10f %14.10f \n",i, cvI[i].real(), cvI[i].imag()); } // printf("na vullen pFftwComplexIn \n"); /* Actual fftw call */ fftw_execute(pCurPlan->FFTPlBackw); // printf("Na execute plan in Ifft n is %d \n", n); const CReal scale = (CReal) 1.0 / n; for (i = 0; i < n; i++) { cvReturn[i] = CComplex(pFftwComplexOut[i][0] * scale, pFftwComplexOut[i][1] * scale); // printf("returnvalue %d is %g %g \n", i, pFftwComplexOut[i][0], pFftwComplexOut[i][1]); } if (!FftPlans.IsInitialized()) delete pCurPlan; return cvReturn; } CMatlibVector rfft(const CMatlibVector& fvI, const CFftPlans& FftPlans) { int i; CFftPlans* pCurPlan; double * pFftwRealIn; double * pFftwRealOut; const int iSizeI = fvI.GetSize(); const int iLongLength(iSizeI); const int iShortLength(iLongLength / 2); const int iUpRoundShortLength((iLongLength + 1) / 2); CMatlibVector cvReturn(iShortLength /* Include Nyquist frequency in case of even N */ + 1, VTY_TEMP); /* If input vector has zero length, return */ if (iLongLength == 0) return cvReturn; /* Check, if plans are already created, else: create it */ if (!FftPlans.IsInitialized()) { pCurPlan = new CFftPlans; pCurPlan->Init(iLongLength); } else { /* Ugly, but ok: We transform "const" object in "non constant" object since we KNOW that the original object is not constant since it was already initialized! */ pCurPlan = (CFftPlans*) &FftPlans; } pFftwRealIn = pCurPlan->pFftwRealIn; pFftwRealOut = pCurPlan->pFftwRealOut; /* fftw (Homepage: http://www.fftw.org/) */ for (i = 0; i < iSizeI; i++) pFftwRealIn[i] = fvI[i]; /* Actual fftw call */ fftw_execute(pCurPlan->RFFTPlForw); /* Now build complex output vector */ /* Zero frequency */ cvReturn[0] = pFftwRealOut[0]; for (i = 1; i < iUpRoundShortLength; i++) cvReturn[i] = CComplex(pFftwRealOut[i], pFftwRealOut[iLongLength - i]); /* If N is even, include Nyquist frequency */ if (iLongLength % 2 == 0) cvReturn[iShortLength] = pFftwRealOut[iShortLength]; if (!FftPlans.IsInitialized()) delete pCurPlan; return cvReturn; } CMatlibVector rifft(const CMatlibVector& cvI, const CFftPlans& FftPlans) { /* This function only works with EVEN N! */ int i; CFftPlans* pCurPlan; double* pFftwRealIn; double* pFftwRealOut; const int iShortLength(cvI.GetSize() - 1); /* Nyquist frequency! */ const int iLongLength(iShortLength * 2); CMatlibVector fvReturn(iLongLength, VTY_TEMP); /* If input vector is too short, return */ if (iShortLength <= 0) return fvReturn; /* Check, if plans are already created, else: create it */ if (!FftPlans.IsInitialized()) { pCurPlan = new CFftPlans; pCurPlan->Init(iLongLength); } else { /* Ugly, but ok: We transform "const" object in "non constant" object since we KNOW that the original object is not constant since it was already initialized! */ pCurPlan = (CFftPlans*) &FftPlans; } pFftwRealIn = pCurPlan->pFftwRealIn; pFftwRealOut = pCurPlan->pFftwRealOut; /* Now build half-complex-vector */ pFftwRealIn[0] = cvI[0].real(); for (i = 1; i < iShortLength; i++) { pFftwRealIn[i] = cvI[i].real(); pFftwRealIn[iLongLength - i] = cvI[i].imag(); } /* Nyquist frequency */ pFftwRealIn[iShortLength] = cvI[iShortLength].real(); /* Actual fftw call */ fftw_execute(pCurPlan->RFFTPlBackw); /* Scale output vector */ const CReal scale = (CReal) 1.0 / iLongLength; for (i = 0; i < iLongLength; i++) fvReturn[i] = pFftwRealOut[i] * scale; if (!FftPlans.IsInitialized()) delete pCurPlan; return fvReturn; } CMatlibVector FftFilt(const CMatlibVector& rvH, const CMatlibVector& rvI, CMatlibVector& rvZ, const CFftPlans& FftPlans) { /* This function only works with EVEN N! */ CFftPlans* pCurPlan; const int iL(rvH.GetSize() - 1); /* Nyquist frequency! */ const int iL2(2 * iL); CMatlibVector rvINew(iL2); CMatlibVector rvOutTMP(iL2); /* Check, if plans are already created, else: create it */ if (!FftPlans.IsInitialized()) { pCurPlan = new CFftPlans; pCurPlan->Init(iL2); } else { /* Ugly, but ok: We transform "const" object in "non constant" object since we KNOW that the original object is not constant since it was already initialized! */ pCurPlan = (CFftPlans*) &FftPlans; } /* Update history of input signal */ rvINew.Merge(rvZ, rvI); rvOutTMP = rifft(rfft(rvINew, FftPlans) * rvH, FftPlans); /* Save old input signal vector for next block */ rvZ = rvI; /* Cut out correct samples (to get from cyclic convolution to linear convolution) */ return rvOutTMP(iL + 1, iL2); } /* FftPlans implementation -------------------------------------------------- */ CFftPlans::~CFftPlans() { if (bInitialized) { /* Delete old plans and intermediate buffers */ fftw_destroy_plan(RFFTPlForw); fftw_destroy_plan(RFFTPlBackw); fftw_destroy_plan(FFTPlForw); fftw_destroy_plan(FFTPlBackw); fftw_free(pFftwRealIn); fftw_free(pFftwRealOut); fftw_free(pFftwComplexIn); fftw_free(pFftwComplexOut); } } void CFftPlans::Init(const int iFSi) { if (bInitialized) { /* Delete old plans and intermediate buffers */ fftw_destroy_plan(RFFTPlForw); fftw_destroy_plan(RFFTPlBackw); fftw_destroy_plan(FFTPlForw); fftw_destroy_plan(FFTPlBackw); fftw_free(pFftwRealIn); fftw_free(pFftwRealOut); fftw_free(pFftwComplexIn); fftw_free(pFftwComplexOut); } /* Create new plans and intermediate buffers */ pFftwRealIn = (double *) fftw_malloc(sizeof(double)*2*iFSi); pFftwRealOut = (double *) fftw_malloc(sizeof(double)*2*iFSi); pFftwComplexIn = (fftw_complex *) fftw_malloc(sizeof(fftw_complex)*iFSi); pFftwComplexOut = (fftw_complex *) fftw_malloc(sizeof(fftw_complex)*iFSi); RFFTPlForw = fftw_plan_r2r_1d(iFSi, pFftwRealIn, pFftwRealOut, FFTW_R2HC, FFTW_ESTIMATE); RFFTPlBackw = fftw_plan_r2r_1d(iFSi, pFftwRealIn,pFftwRealOut, FFTW_HC2R, FFTW_ESTIMATE); FFTPlForw = fftw_plan_dft_1d(iFSi, pFftwComplexIn, pFftwComplexOut, FFTW_FORWARD, FFTW_ESTIMATE); FFTPlBackw = fftw_plan_dft_1d(iFSi, pFftwComplexIn, pFftwComplexOut, FFTW_BACKWARD, FFTW_ESTIMATE); bInitialized = true; } qsstv_8.2.12/qsstv/drmtx/common/matlib/MatlibStdToolbox.h000664 001750 001750 00000024515 12440612574 023463 0ustar00jomajoma000000 000000 /******************************************************************************\ * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * c++ Mathematic Library (Matlib), standard toolbox * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #ifndef _MATLIB_STD_TOOLBOX_H_ #define _MATLIB_STD_TOOLBOX_H_ #include "Matlib.h" /* fftw (Homepage: http://www.fftw.org) */ #include /* Classes ********************************************************************/ class CFftPlans { public: CFftPlans() : RFFTPlForw(NULL), RFFTPlBackw(NULL), bInitialized(false) {} CFftPlans(const int iFftSize) : RFFTPlForw(NULL), RFFTPlBackw(NULL), bInitialized(false) {Init(iFftSize);} virtual ~CFftPlans(); void Init(const int iFSi); inline bool IsInitialized() const {return bInitialized;} fftw_plan RFFTPlForw; fftw_plan RFFTPlBackw; fftw_plan FFTPlForw; fftw_plan FFTPlBackw; double * pFftwRealIn; double * pFftwRealOut; fftw_complex* pFftwComplexIn; fftw_complex* pFftwComplexOut; protected: void Clean(); bool bInitialized; }; /* Helpfunctions **************************************************************/ inline CReal Min(const CReal& rA, const CReal& rB) {return rA < rB ? rA : rB;} inline CMatlibVector Min(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), Min(rvA[i], rvB[i]));} CReal Min(const CMatlibVector& rvI); void Min(CReal& rMinVal /* out */, int& iMinInd /* out */, const CMatlibVector& rvI /* in */); inline CReal Min(const CReal& r1, const CReal& r2, const CReal& r3, const CReal& r4) {return Min(Min(Min(r1, r2), r3), r4);} inline CReal Min(const CReal& r1, const CReal& r2, const CReal& r3, const CReal& r4, const CReal& r5, const CReal& r6, const CReal& r7, const CReal& r8) {return Min(Min(Min(Min(Min(Min(Min(r1, r2), r3), r4), r5), r6), r7), r8);} inline CReal Max(const CReal& rA, const CReal& rB) {return rA > rB ? rA : rB;} inline CMatlibVector Max(const CMatlibVector& rvA, const CMatlibVector& rvB) {_VECOP(CReal, rvA.GetSize(), Max(rvA[i], rvB[i]));} CReal Max(const CMatlibVector& rvI); void Max(CReal& rMaxVal /* out */, int& iMaxInd /* out */, const CMatlibVector& rvI /* in */); inline CReal Max(const CReal& r1, const CReal& r2, const CReal& r3) {return Max(Max(r1, r2), r3);} inline CReal Max(const CReal& r1, const CReal& r2, const CReal& r3, const CReal& r4, const CReal& r5, const CReal& r6, const CReal& r7) {return Max(Max(Max(Max(Max(Max(r1, r2), r3), r4), r5), r6), r7);} inline CMatlibVector Ones(const int iLen) {_VECOP(CReal, iLen, (CReal) 1.0);} inline CMatlibVector Zeros(const int iLen) {_VECOP(CReal, iLen, (CReal) 0.0);} inline CReal Real(const CComplex& cI) {return cI.real();} inline CMatlibVector Real(const CMatlibVector& cvI) {_VECOP(CReal, cvI.GetSize(), Real(cvI[i]));} inline CReal Imag(const CComplex& cI) {return cI.imag();} inline CMatlibVector Imag(const CMatlibVector& cvI) {_VECOP(CReal, cvI.GetSize(), Imag(cvI[i]));} inline CComplex Conj(const CComplex& cI) {return conj(cI);} inline CMatlibVector Conj(const CMatlibVector& cvI) {_VECOP(CComplex, cvI.GetSize(), Conj(cvI[i]));} inline CMatlibMatrix Conj(const CMatlibMatrix& cmI) {_MATOP(CComplex, cmI.GetRowSize(), cmI.GetColSize(), Conj(cmI[i]));} /* Absolute and angle (argument) functions */ inline CReal Abs(const CReal& rI) {return fabs(rI);} inline CMatlibVector Abs(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Abs(fvI[i]));} inline CReal Abs(const CComplex& cI) {return abs(cI);} inline CMatlibVector Abs(const CMatlibVector& cvI) {_VECOP(CReal, cvI.GetSize(), Abs(cvI[i]));} inline CReal Angle(const CComplex& cI) {return arg(cI);} inline CMatlibVector Angle(const CMatlibVector& cvI) {_VECOP(CReal, cvI.GetSize(), Angle(cvI[i]));} /* Trigonometric functions */ inline CReal Sin(const CReal& fI) {return sin(fI);} template inline CMatlibVector Sin(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), sin(vecI[i]));} inline CReal Cos(const CReal& fI) {return cos(fI);} template inline CMatlibVector Cos(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), cos(vecI[i]));} inline CReal Tan(const CReal& fI) {return tan(fI);} template inline CMatlibVector Tan(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), tan(vecI[i]));} inline CReal Sinh(const CReal& fI) {return sinh(fI);} template inline CMatlibVector Sinh(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), sinh(vecI[i]));} inline CReal Cosh(const CReal& fI) {return cosh(fI);} template inline CMatlibVector Cosh(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), cosh(vecI[i]));} inline CReal Tanh(const CReal& fI) {return tanh(fI);} template inline CMatlibVector Tanh(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), tanh(vecI[i]));} /* Square root */ inline CReal Sqrt(const CReal& fI) {return sqrt(fI);} template inline CMatlibVector Sqrt(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), sqrt(vecI[i]));} /* Exponential function */ inline CReal Exp(const CReal& fI) {return exp(fI);} template inline CMatlibVector Exp(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), exp(vecI[i]));} /* Logarithm */ inline CReal Log(const CReal& fI) {return log(fI);} template inline CMatlibVector Log(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), log(vecI[i]));} inline CReal Log10(const CReal& fI) {return log10(fI);} template inline CMatlibVector Log10(const CMatlibVector& vecI) {_VECOP(T, vecI.GetSize(), log10(vecI[i]));} /* Mean, variance and standard deviation */ template inline T Mean(const CMatlibVector& vecI) {return Sum(vecI) / vecI.GetSize();} template inline T Std(CMatlibVector& vecI) {return Sqrt(Var(vecI));} template T Var(const CMatlibVector& vecI); /* Rounding functions */ inline CReal Fix(const CReal& fI) {return (int) fI;} inline CMatlibVector Fix(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Fix(fvI[i]));} inline CReal Floor(const CReal& fI) {return floor(fI);} inline CMatlibVector Floor(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Floor(fvI[i]));} inline CReal Ceil(const CReal& fI) {return ceil(fI);} inline CMatlibVector Ceil(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Ceil(fvI[i]));} inline CReal Round(const CReal& fI) {return Floor(fI + (CReal) 0.5);} inline CMatlibVector Round(const CMatlibVector& fvI) {_VECOP(CReal, fvI.GetSize(), Round(fvI[i]));} inline CReal Sign(const CReal& rI) {return rI == 0 ? 0 : rI > 0 ? 1 : -1;} inline int Mod(const int ix, const int iy) {return ix < 0 ? (ix % iy + iy) % iy : ix % iy;} template T Sum(const CMatlibVector& vecI); CMatlibVector Sort(const CMatlibVector& rvI); /* Matrix inverse */ CMatlibMatrix Inv(const CMatlibMatrix& matrI); /* Identity matrix */ CMatlibMatrix Eye(const int iLen); CMatlibMatrix Diag(const CMatlibVector& cvI); CReal Trace(const CMatlibMatrix& rmI); CMatlibMatrix Toeplitz(const CMatlibVector& cvI); /* Matrix transpose */ CMatlibMatrix Transp(const CMatlibMatrix& cmI); inline CMatlibMatrix TranspH(const CMatlibMatrix& cmI) {return Conj(Transp(cmI));} /* With conjugate complex */ /* Fourier transformations (also included: real FFT) */ CMatlibVector Fft(const CMatlibVector& cvI, const CFftPlans& FftPlans = CFftPlans()); CMatlibVector Ifft(const CMatlibVector& cvI, const CFftPlans& FftPlans = CFftPlans()); CMatlibVector rfft(const CMatlibVector& fvI, const CFftPlans& FftPlans = CFftPlans()); CMatlibVector rifft(const CMatlibVector& cvI, const CFftPlans& FftPlans = CFftPlans()); CMatlibVector FftFilt(const CMatlibVector& rvH, const CMatlibVector& rvI, CMatlibVector& rvZ, const CFftPlans& FftPlans = CFftPlans()); /* Numerical integration */ typedef CComplex(MATLIB_CALLBACK_QAUD)(CReal rX); /* Callback function definition */ CComplex Quad(MATLIB_CALLBACK_QAUD f, const CReal a, const CReal b, const CReal errorBound = 1.e-6); /* Implementation ************************************************************** (the implementation of template classes must be in the header file!) */ template inline T Sum(const CMatlibVector& vecI) { const int iSize = vecI.GetSize(); T SumRet = 0; for (int i = 0; i < iSize; i++) SumRet += vecI[i]; return SumRet; } template inline T Var(const CMatlibVector& vecI) { const int iSize = vecI.GetSize(); /* First calculate mean */ T tMean = Mean(vecI); /* Now variance (sum formula) */ T tRet = 0; for (int i = 0; i < iSize; i++) tRet += (vecI[i] - tMean) * (vecI[i] - tMean); return tRet / (iSize - 1); /* Normalizing */ } #endif /* _MATLIB_STD_TOOLBOX_H_ */ qsstv_8.2.12/qsstv/drmtx/common/mlc/BitInterleaver.cpp000664 001750 001750 00000011037 12440612574 023001 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * The two parts with different protection levels shall not overlap in the * interleaving process. Therefore the interleaved lower protected part shall * be appended to the interleaved higher protected part. * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "BitInterleaver.h" /* Implementation *************************************************************/ /******************************************************************************\ * Bit interleaver * \******************************************************************************/ void CBitInterleaver::Interleave(CVector<_DECISION>& InputData) { int i; /* Block 1 -------------------------------------------------------------- */ /* Interleave data according the interleaver table */ for (i = 0; i < ix_in1; i++) vecInterlMemory1[i] = InputData[veciIntTable1[i]]; /* Copy result in input-vector */ for (i = 0; i < ix_in1; i++) InputData[i] = vecInterlMemory1[i]; /* Block 2 -------------------------------------------------------------- */ /* Interleave data according the interleaver table */ for (i = 0; i < ix_in2; i++) vecInterlMemory2[i] = InputData[veciIntTable2[i] + ix_in1]; /* Copy result in input-vector */ for (i = 0; i < ix_in2; i++) InputData[i + ix_in1] = vecInterlMemory2[i]; } void CBitInterleaver::Init(int iNewx_in1, int iNewx_in2, int it_0) { /* Set internal parameters */ ix_in1 = iNewx_in1; ix_in2 = iNewx_in2; /* ix_in1 can be 0 but ix_in2 is always greater than "0" */ if (ix_in1 > 0) { /* Allocate memory for table */ veciIntTable1.Init(ix_in1); /* Make interleaver table */ MakeTable(veciIntTable1, ix_in1, it_0); /* Allocate memory for interleaver */ vecInterlMemory1.Init(ix_in1); } /* Allocate memory for table */ veciIntTable2.Init(ix_in2); /* Make interleaver table */ MakeTable(veciIntTable2, ix_in2, it_0); /* Allocate memory for interleaver */ vecInterlMemory2.Init(ix_in2); } /******************************************************************************\ * Bit deinterleaver * \******************************************************************************/ void CBitDeinterleaver::Deinterleave(CVector& vecInput) { int i; /* Block 1 -------------------------------------------------------------- */ /* Deinterleave data according the deinterleaver table */ for (i = 0; i < ix_in1; i++) vecDeinterlMemory1[veciIntTable1[i]] = vecInput[i]; /* Copy result in input-vector */ for (i = 0; i < ix_in1; i++) vecInput[i] = vecDeinterlMemory1[i]; /* Block 2 -------------------------------------------------------------- */ /* Deinterleave data according the deinterleaver table */ for (i = 0; i < ix_in2; i++) vecDeinterlMemory2[veciIntTable2[i]] = vecInput[i + ix_in1]; /* Copy result in input-vector */ for (i = 0; i < ix_in2; i++) vecInput[i + ix_in1] = vecDeinterlMemory2[i]; } void CBitDeinterleaver::Init(int iNewx_in1, int iNewx_in2, int it_0) { /* Set internal parameters */ ix_in1 = iNewx_in1; ix_in2 = iNewx_in2; /* ix_in1 can be 0 but ix_in2 is always greater than "0" */ if (ix_in1 > 0) { /* Allocate memory for table */ veciIntTable1.Init(ix_in1); /* Make interleaver table */ MakeTable(veciIntTable1, ix_in1, it_0); /* Allocate memory for interleaver */ vecDeinterlMemory1.Init(ix_in1); } /* Allocate memory for table */ veciIntTable2.Init(ix_in2); /* Make interleaver table */ MakeTable(veciIntTable2, ix_in2, it_0); /* Allocate memory for interleaver */ vecDeinterlMemory2.Init(ix_in2); } qsstv_8.2.12/qsstv/drmtx/common/mlc/BitInterleaver.h000664 001750 001750 00000004467 12440612574 022457 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(BIT_INTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define BIT_INTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../interleaver/BlockInterleaver.h" #include "utils/vector.h" /* Classes ********************************************************************/ class CBitInterleaver: public CBlockInterleaver { public: CBitInterleaver() {} virtual ~CBitInterleaver() {} void Init(int iNewx_in1, int iNewx_in2, int it_0); void Interleave(CVector<_DECISION>& InputData); protected: int ix_in1; int ix_in2; CVector veciIntTable1; CVector veciIntTable2; CVector<_DECISION> vecInterlMemory1; CVector<_DECISION> vecInterlMemory2; }; class CBitDeinterleaver: public CBlockInterleaver { public: CBitDeinterleaver() {} virtual ~CBitDeinterleaver() {} void Init(int iNewx_in1, int iNewx_in2, int it_0); void Deinterleave(CVector& vecInput); protected: int ix_in1; int ix_in2; CVector veciIntTable1; CVector veciIntTable2; CVector vecDeinterlMemory1; CVector vecDeinterlMemory2; }; #endif // !defined(BIT_INTERLEAVER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/mlc/ChannelCode.cpp000664 001750 001750 00000013377 12440612574 022236 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "ChannelCode.h" /* Implementation *************************************************************/ CVector CChannelCode::GenPuncPatTable(ECodScheme eNewCodingScheme, EChanType eNewChannelType, int iN1, int iN2, int iNewNumOutBitsPartA, int iNewNumOutBitsPartB, int iPunctPatPartA, int iPunctPatPartB, int iLevel) { int i; int iNumOutBits; int iNumOutBitsWithMemory; int iTailbitPattern; int iTailbitParamL0; int iTailbitParamL1; int iPartAPatLen; int iPartBPatLen; int iPunctCounter; CVector veciPuncPatPartA; CVector veciPuncPatPartB; CVector veciTailBitPat; CVector veciReturn; /* Number of bits out is the sum of all protection levels */ iNumOutBits = iNewNumOutBitsPartA + iNewNumOutBitsPartB; /* Number of out bits including the state memory */ iNumOutBitsWithMemory = iNumOutBits + MC_CONSTRAINT_LENGTH - 1; /* Init vector, storing table for puncturing pattern */ veciReturn.Init(iNumOutBitsWithMemory); /* Set tail-bit pattern ------------------------------------------------- */ /* We have to consider two cases because in HSYM "N1 + N2" is used instead of only "N2" to calculate the tailbit pattern */ switch (eNewCodingScheme) { case CS_3_HMMIX: iTailbitParamL0 = iN1 + iN2; iTailbitParamL1 = iN2; break; case CS_3_HMSYM: iTailbitParamL0 = 2 * (iN1 + iN2); iTailbitParamL1 = 2 * iN2; break; default: iTailbitParamL0 = 2 * iN2; iTailbitParamL1 = 2 * iN2; } /* Tailbit pattern calculated according DRM-standard. We have to consider two cases because in HSYM "N1 + N2" is used instead of only "N2" */ if (iLevel == 0) iTailbitPattern = iTailbitParamL0 - 12 - iPuncturingPatterns[iPunctPatPartB][1] * (int) ((iTailbitParamL0 - 12) / iPuncturingPatterns[iPunctPatPartB][1]); else iTailbitPattern = iTailbitParamL1 - 12 - iPuncturingPatterns[iPunctPatPartB][1] * (int) ((iTailbitParamL1 - 12) / iPuncturingPatterns[iPunctPatPartB][1]); /* Set puncturing bit patterns and lengths ------------------------------ */ /* Lengths */ iPartAPatLen = iPuncturingPatterns[iPunctPatPartA][0]; iPartBPatLen = iPuncturingPatterns[iPunctPatPartB][0]; /* Vector, storing patterns for part A. Patterns begin at [][2 + x] */ veciPuncPatPartA.Init(iPartAPatLen); for (i = 0; i < iPartAPatLen; i++) veciPuncPatPartA[i] = iPuncturingPatterns[iPunctPatPartA][2 + i]; /* Vector, storing patterns for part B. Patterns begin at [][2 + x] */ veciPuncPatPartB.Init(iPartBPatLen); for (i = 0; i < iPartBPatLen; i++) veciPuncPatPartB[i] = iPuncturingPatterns[iPunctPatPartB][2 + i]; /* Vector, storing patterns for tailbit pattern */ veciTailBitPat.Init(LENGTH_TAIL_BIT_PAT); for (i = 0; i < LENGTH_TAIL_BIT_PAT; i++) veciTailBitPat[i] = iPunctPatTailbits[iTailbitPattern][i]; /* Generate actual table for puncturing pattern ------------------------- */ /* Reset counter for puncturing */ iPunctCounter = 0; for (i = 0; i < iNumOutBitsWithMemory; i++) { if (i < iNewNumOutBitsPartA) { /* Puncturing patterns part A */ /* Get current pattern */ veciReturn[i] = veciPuncPatPartA[iPunctCounter]; /* Increment index and take care of wrap around */ iPunctCounter++; if (iPunctCounter == iPartAPatLen) iPunctCounter = 0; } else { /* In case of FAC do not use special tailbit-pattern! */ if ((i < iNumOutBits) || (eNewChannelType == CT_FAC)) { /* Puncturing patterns part B */ /* Reset counter when beginning of part B is reached */ if (i == iNewNumOutBitsPartA) iPunctCounter = 0; /* Get current pattern */ veciReturn[i] = veciPuncPatPartB[iPunctCounter]; /* Increment index and take care of wrap around */ iPunctCounter++; if (iPunctCounter == iPartBPatLen) iPunctCounter = 0; } else { /* Tailbits */ /* Check when tailbit pattern starts */ if (i == iNumOutBits) iPunctCounter = 0; /* Set tailbit pattern */ veciReturn[i] = veciTailBitPat[iPunctCounter]; /* No test for wrap around needed, since there ist only one cycle of this pattern */ iPunctCounter++; } } } return veciReturn; } CChannelCode::CChannelCode() { /* Create table for parity bit */ for (int j = 0; j < 1 << SIZEOF__BYTE; j++) { /* XOR all bits in byResult. We observe always the LSB by masking using operator "& 1". To get access to all bits in "byResult" we shift the current bit so long until it reaches the mask (at zero) by using operator ">> i". The actual XOR operation is done by "^=" */ vecbiParity[j] = 0; for (int i = 0; i < MC_CONSTRAINT_LENGTH; i++) vecbiParity[j] ^= (j >> i) & 1; } } qsstv_8.2.12/qsstv/drmtx/common/mlc/ChannelCode.h000664 001750 001750 00000004567 12440612574 021704 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(CHANNEL_CODE_H__3B0BA660_CA63345347A0D31912__INCLUDED_) #define CHANNEL_CODE_H__3B0BA660_CA63345347A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../tables/TableMLC.h" #include "utils/vector.h" #include "../Parameter.h" /* Classes ********************************************************************/ class CChannelCode { public: CChannelCode(); virtual ~CChannelCode() {} inline _BINARY Convolution(const _BYTE byNewStateShiftReg, const int iGenPolyn) const { /* Mask bits with generator polynomial and get convolution result from pre-calculated table (speed optimization). Since we have a AND operation on the "byGeneratorMatrix", the index of the convolution table cannot exceed the size of the table (although the value in "byNewStateShiftReg" can be larger) */ return vecbiParity[byNewStateShiftReg & byGeneratorMatrix[iGenPolyn]]; } CVector GenPuncPatTable(ECodScheme eNewCodingScheme, EChanType eNewChannelType, int iN1, int iN2, int iNewNumOutBitsPartA, int iNewNumOutBitsPartB, int iPunctPatPartA, int iPunctPatPartB, int iLevel); private: _BINARY vecbiParity[1 << SIZEOF__BYTE]; }; #endif // !defined(CHANNEL_CODE_H__3B0BA660_CA63345347A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/mlc/ConvEncoder.cpp000664 001750 001750 00000016307 12440612574 022274 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * Note: We always shift the bits towards the MSB * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "ConvEncoder.h" /* Implementation *************************************************************/ int CConvEncoder::Encode(CVector<_DECISION>& vecInputData, CVector<_DECISION>& vecOutputData) { /* Set output size to zero, increment it each time a new bit is encoded */ int iOutputCnt = 0; /* Reset counter for puncturing and state-register */ _BYTE byStateShiftReg = 0; #ifdef USE_MAX_LOG_MAP /* We know the initial state of the shift registers, therefore a very high soft information value */ vecStateMem.Reset(ML_SOFT_INF_MAX_VALUE); #endif for (int i = 0; i < iNumInBitsWithMemory; i++) { /* Update shift-register (state information) ------------------------ */ /* Shift bits in state-shift-register */ byStateShiftReg <<= 1; /* Tailbits are calculated in this loop. Check when end of vector is reached and no more bits must be added */ if (i < iNumInBits) { /* Add new bit at the beginning */ if (ExtractBit(vecInputData[i]) != 0) byStateShiftReg |= 1; #ifdef USE_MAX_LOG_MAP /* Update shift register for soft information. We assume here that the decision type is some floating point type -> we use fabs() function */ vecStateMem.AddBegin(fabs(vecInputData[i])); #endif } /* Puncturing ------------------------------------------------------- */ /* Depending on the current puncturing pattern, different numbers of output bits are generated. The state shift register "byStateShiftReg" is convoluted with the respective patterns for this bit (is done inside the convolution function) */ #ifdef USE_MAX_LOG_MAP switch (veciTablePuncPat[i]) { case PP_TYPE_0001: /* Pattern 0001 */ vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 0); break; case PP_TYPE_0101: /* Pattern 0101 */ vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 0); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 2); break; case PP_TYPE_0011: /* Pattern 0011 */ vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 0); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 1); break; case PP_TYPE_0111: /* Pattern 0111 */ vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 0); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 1); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 2); break; case PP_TYPE_1111: /* Pattern 1111 */ vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 0); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 1); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 2); vecOutputData[iOutputCnt++] = SoftConvolution(byStateShiftReg, vecStateMem, 3); break; } #else switch (veciTablePuncPat[i]) { case PP_TYPE_0001: /* Pattern 0001 */ vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 0); break; case PP_TYPE_0101: /* Pattern 0101 */ vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 0); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 2); break; case PP_TYPE_0011: /* Pattern 0011 */ vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 0); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 1); break; case PP_TYPE_0111: /* Pattern 0111 */ vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 0); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 1); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 2); break; case PP_TYPE_1111: /* Pattern 1111 */ vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 0); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 1); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 2); vecOutputData[iOutputCnt++] = Convolution(byStateShiftReg, 3); break; } #endif } /* Return number of encoded bits */ return iOutputCnt; } #ifdef USE_MAX_LOG_MAP _DECISION CConvEncoder::SoftConvolution(const _BYTE byNewStateShiftReg, CShiftRegister<_DECISION>& vecStateMem, const int iGenPolyn) { _DECISION decSoftOut; /* Search for minimum norm value of input soft-informations. Here we implement the convolution of the soft information independent of the poylnoms stored in "byGeneratorMatrix[]"! When changing the polynoms, it has to be changed here, too */ switch (iGenPolyn) { case 0: case 3: /* oct: 0155 -> 1101101 */ decSoftOut = Min(Min(Min(Min(vecStateMem[0], vecStateMem[2]), vecStateMem[3]), vecStateMem[5]), vecStateMem[6]); break; case 1: /* oct: 0117 -> 1001111 */ decSoftOut = Min(Min(Min(Min(vecStateMem[0], vecStateMem[1]), vecStateMem[2]), vecStateMem[3]), vecStateMem[6]); break; case 2: /* oct: 0123 -> 1010011 */ decSoftOut = Min(Min(Min(vecStateMem[0], vecStateMem[1]), vecStateMem[4]), vecStateMem[6]); break; } /* Hard decision defines the sign, the norm is defined by the minimum of input norms of soft informations using max-log approximation */ if (Convolution(byNewStateShiftReg, iGenPolyn) == 0) return -decSoftOut; else return decSoftOut; } #endif void CConvEncoder::Init(ECodScheme eNewCodingScheme, EChanType eNewChannelType, int iN1, int iN2, int iNewNumInBitsPartA, int iNewNumInBitsPartB, int iPunctPatPartA, int iPunctPatPartB, int iLevel) { /* Number of bits out is the sum of all protection levels */ iNumInBits = iNewNumInBitsPartA + iNewNumInBitsPartB; /* Number of out bits including the state memory */ iNumInBitsWithMemory = iNumInBits + MC_CONSTRAINT_LENGTH - 1; /* Init vector, storing table for puncturing pattern and generate pattern */ veciTablePuncPat.Init(iNumInBitsWithMemory); veciTablePuncPat = GenPuncPatTable(eNewCodingScheme, eNewChannelType, iN1, iN2, iNewNumInBitsPartA, iNewNumInBitsPartB, iPunctPatPartA, iPunctPatPartB, iLevel); #ifdef USE_MAX_LOG_MAP vecStateMem.Init(MC_CONSTRAINT_LENGTH); #endif } qsstv_8.2.12/qsstv/drmtx/common/mlc/ConvEncoder.h000664 001750 001750 00000004405 12440612574 021735 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(CONNVOL_ENC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define CONNVOL_ENC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../tables/TableMLC.h" #include "utils/vector.h" #include "../Parameter.h" #include "ChannelCode.h" /* Classes ********************************************************************/ class CConvEncoder : public CChannelCode { public: CConvEncoder() {} virtual ~CConvEncoder() {} int Encode(CVector<_DECISION>& vecInputData, CVector<_DECISION>& vecOutputData); void Init(ECodScheme eNewCodingScheme, EChanType eNewChannelType, int iN1, int iN2, int iNewNumInBitsPartA, int iNewNumInBitsPartB, int iPunctPatPartA, int iPunctPatPartB, int iLevel); protected: int iNumInBits; int iNumInBitsWithMemory; CVector veciTablePuncPat; EChanType eChannelType; #ifdef USE_MAX_LOG_MAP CShiftRegister<_DECISION> vecStateMem; _DECISION SoftConvolution(const _BYTE byNewStateShiftReg, CShiftRegister<_DECISION>& vecStateMem, const int iGenPolyn); #endif }; #endif // !defined(CONNVOL_ENC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/mlc/EnergyDispersal.cpp000664 001750 001750 00000005415 12440612574 023165 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * Note: * Input data stream is divided into a regluar stream and the VSPP stream. * Both stream are treated independently. The respective positions of the * two streams are requested in the init-routine. * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "EnergyDispersal.h" /* Implementation *************************************************************/ void CEngergyDispersal::ProcessData(CVector<_BINARY>* pbiData) { int i; uint32_t iTempShiftRegister; _BINARY biPRBSbit; /* Init shift register and set all registers to "1" with bit-wise not-operation */ iShiftRegisterSPP = ~uint32_t(0); iShiftRegisterVSPP = ~uint32_t(0); /* Main routine */ for (i = 0; i < iNumInBits; i++) { if (i < iEndIndVSPP) { /* Calculate new PRBS bit */ iTempShiftRegister = iShiftRegisterVSPP; /* P(X) = X^9 + X^5 + 1, in this implementation we have to shift n-1! */ biPRBSbit = _BINARY(((iTempShiftRegister >> 4) & 1) ^ ((iTempShiftRegister >> 8) & 1)); /* Shift bits in shift register and add new bit */ iShiftRegisterVSPP <<= 1; iShiftRegisterVSPP |= (biPRBSbit & 1); } else { /* Calculate new PRBS bit */ iTempShiftRegister = iShiftRegisterSPP; /* P(X) = X^9 + X^5 + 1, in this implementation we have to shift n-1! */ biPRBSbit = _BINARY(((iTempShiftRegister >> 4) & 1) ^ ((iTempShiftRegister >> 8) & 1)); /* Shift bits in shift register and add new bit */ iShiftRegisterSPP <<= 1; iShiftRegisterSPP |= (biPRBSbit & 1); } /* Apply PRBS to the data-stream */ (*pbiData)[i] ^= biPRBSbit; } } void CEngergyDispersal::Init(int iNewNumInBits, int iNewLengthVSPP) { /* Set the internal parameters */ iNumInBits = iNewNumInBits; iEndIndVSPP = iNewLengthVSPP; } qsstv_8.2.12/qsstv/drmtx/common/mlc/EnergyDispersal.h000664 001750 001750 00000003453 12440612574 022632 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(ENERGYDISPERSAL_H__3B0BA660_CA63_4344_2B_23453E7A0D31912__INCLUDED_) #define ENERGYDISPERSAL_H__3B0BA660_CA63_4344_2B_23453E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "utils/vector.h" /* Classes ********************************************************************/ class CEngergyDispersal { public: CEngergyDispersal() {} virtual ~CEngergyDispersal() {} void ProcessData(CVector<_BINARY>* pbiData); void Init(int iNewNumInBits, int iNewLengthVSPP); protected: int iNumInBits; int iStartIndVSPP; int iEndIndVSPP; uint32_t iShiftRegisterSPP; uint32_t iShiftRegisterVSPP; }; #endif // !defined(ENERGYDISPERSAL_H__3B0BA660_CA63_4344_2B_23453E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/mlc/MLC.cpp000664 001750 001750 00000033257 12440612574 020505 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * * Description: * Multi-level-channel (de)coder (MLC) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "MLC.h" #define NUM_FAC_CELLS 45 /* Implementation *************************************************************/ /******************************************************************************\ * MLC-encoder * \******************************************************************************/ void CMLCEncoder::ProcessDataInternal(CParameter&) { int i, j; int iElementCounter; /* Energy dispersal ----------------------------------------------------- */ /* VSPP is treated as a separate part for energy dispersal */ EnergyDisp.ProcessData(pvecInputData); /* Partitioning of input-stream ----------------------------------------- */ iElementCounter = 0; if (iL[2] == 0) { /* Standard departitioning */ /* Protection level A */ for (j = 0; j < iLevels; j++) { /* Bits */ for (i = 0; i < iM[j][0]; i++) { vecEncInBuffer[j][i] = // BitToSoft((*pvecInputData)[iElementCounter]); (*pvecInputData)[iElementCounter]; iElementCounter++; } } /* Protection level B */ for (j = 0; j < iLevels; j++) { /* Bits */ for (i = 0; i < iM[j][1]; i++) { vecEncInBuffer[j][iM[j][0] + i] = // BitToSoft((*pvecInputData)[iElementCounter]); (*pvecInputData)[iElementCounter]; iElementCounter++; } } } else { /* Special partitioning with hierarchical modulation. First set hierarchical bits at the beginning, then append the rest */ /* Hierarchical frame (always "iM[0][1]"). "iM[0][0]" is always "0" in this case */ for (i = 0; i < iM[0][1]; i++) { vecEncInBuffer[0][i] = // BitToSoft((*pvecInputData)[iElementCounter]); (*pvecInputData)[iElementCounter]; iElementCounter++; } /* Protection level A (higher protected part) */ for (j = 1; j < iLevels; j++) { /* Bits */ for (i = 0; i < iM[j][0]; i++) { vecEncInBuffer[j][i] = // BitToSoft((*pvecInputData)[iElementCounter]); (*pvecInputData)[iElementCounter]; iElementCounter++; } } /* Protection level B (lower protected part) */ for (j = 1; j < iLevels; j++) { /* Bits */ for (i = 0; i < iM[j][1]; i++) { vecEncInBuffer[j][iM[j][0] + i] = // BitToSoft((*pvecInputData)[iElementCounter]); (*pvecInputData)[iElementCounter]; iElementCounter++; } } } /* Convolutional encoder ------------------------------------------------ */ for (j = 0; j < iLevels; j++) ConvEncoder[j].Encode(vecEncInBuffer[j], vecEncOutBuffer[j]); /* Bit interleaver ------------------------------------------------------ */ for (j = 0; j < iLevels; j++) if (piInterlSequ[j] != -1) BitInterleaver[piInterlSequ[j]].Interleave(vecEncOutBuffer[j]); /* QAM mapping ---------------------------------------------------------- */ QAMMapping.Map(vecEncOutBuffer[0], vecEncOutBuffer[1], vecEncOutBuffer[2], vecEncOutBuffer[3], vecEncOutBuffer[4], vecEncOutBuffer[5], pvecOutputData); } void CMLCEncoder::InitInternal(CParameter& TransmParam) { int i; int iNumInBits; TransmParam.Lock(); CalculateParam(TransmParam, eChannelType); TransmParam.Unlock(); iNumInBits = iL[0] + iL[1] + iL[2]; /* Init modules --------------------------------------------------------- */ /* Energy dispersal */ EnergyDisp.Init(iNumInBits, iL[2]); /* Encoder */ for (i = 0; i < iLevels; i++) ConvEncoder[i].Init(eCodingScheme, eChannelType, iN[0], iN[1], iM[i][0], iM[i][1], iCodeRate[i][0], iCodeRate[i][1], i); /* Bit interleaver */ /* First init all possible interleaver (According table "TableMLC.h" -> "Interleaver sequence") */ if (eCodingScheme == CS_3_HMMIX) { BitInterleaver[0].Init(iN[0], iN[1], 13); BitInterleaver[1].Init(iN[0], iN[1], 21); } else { BitInterleaver[0].Init(2 * iN[0], 2 * iN[1], 13); BitInterleaver[1].Init(2 * iN[0], 2 * iN[1], 21); } /* QAM-mapping */ QAMMapping.Init(iN_mux, eCodingScheme); /* Allocate memory for internal bit-buffers ----------------------------- */ for (i = 0; i < iLevels; i++) { /* Buffers for each encoder on all different levels */ /* Add bits from higher protected and lower protected part */ vecEncInBuffer[i].Init(iM[i][0] + iM[i][1]); /* Encoder output buffers for all levels. Must have the same length */ vecEncOutBuffer[i].Init(iNumEncBits); } /* Define block-size for input and output */ iInputBlockSize = iNumInBits; iOutputBlockSize = iN_mux; // printf("In init MSCMLCEnc inputblk = %d outpublk = %d\n", // iInputBlockSize, iOutputBlockSize); } /******************************************************************************\ * MLC base class * \******************************************************************************/ void CMLC::CalculateParam(CParameter& Parameter, int iNewChannelType) { int i; // int iMSCDataLenPartA; switch (iNewChannelType) { /* FAC ********************************************************************/ case CT_FAC: eCodingScheme = CS_1_SM; iN_mux = NUM_FAC_CELLS; iNumEncBits = NUM_FAC_CELLS * 2; iLevels = 1; /* Code rates for prot.-Level A and B for each level */ /* Protection Level A */ iCodeRate[0][0] = 0; /* Protection Level B */ iCodeRate[0][1] = iCodRateCombFDC4SM; /* Define interleaver sequence for all levels */ piInterlSequ = iInterlSequ4SM; /* iN: Number of OFDM-cells of each protection level ---------------- */ iN[0] = 0; iN[1] = iN_mux; /* iM: Number of bits each level ------------------------------------ */ iM[0][0] = 0; iM[0][1] = NUM_FAC_BITS_PER_BLOCK; /* iL: Number of bits each protection level ------------------------- */ /* Higher protected part */ iL[0] = 0; /* Lower protected part */ iL[1] = iM[0][1]; /* Very strong protected part (VSPP) */ iL[2] = 0; break; /* MSC ********************************************************************/ case CT_MSC: eCodingScheme = Parameter.eMSCCodingScheme; iN_mux = Parameter.CellMappingTable.iNumUsefMSCCellsPerFrame; // printf("iN_mux %d \n", iN_mux); /* Data length for part A is the sum of all lengths of the streams */ // iMSCDataLenPartA = 0; // for hamversion /* iMSCDataLenPartA = Parameter.Stream[0].iLenPartA + Parameter.Stream[1].iLenPartA + Parameter.Stream[2].iLenPartA + Parameter.Stream[3].iLenPartA; */ switch (eCodingScheme) { case CS_1_SM: iLevels = 1; /* Code rates for prot.-Level A and B for each level */ /* Protection Level A */ iCodeRate[0][0] = 0; /* Protection Level B */ iCodeRate[0][1] = iCodRateCombMSC4SM; /* Define interleaver sequence for all levels */ piInterlSequ = iInterlSequ4SM; iNumEncBits = iN_mux * 2; /* iN: Number of OFDM-cells of each protection level ---------------- */ iN[0] = 0; iN[1] = iN_mux; /* iM: Number of bits each level ------------------------------------ */ iM[0][0] = 0; /* M_p,2 = RX_p * floor((2 * N_2 - 12) / RY_p) */ iM[0][1] = iPuncturingPatterns[iCodRateCombMSC4SM][0] * (int) ((_REAL) (2 * iN_mux - 12) / iPuncturingPatterns[iCodRateCombMSC4SM][1]); /* iL: Number of bits each protection level ------------------------- */ /* Higher protected part */ iL[0] = 0; /* Lower protected part */ iL[1] = iM[0][1]; /* Very strong protected part (VSPP) */ iL[2] = 0; /* printf("in CalcuPar CS_1_SM iN[0]= %d iN[1]= %d iM[0][0] = %d iM[0][1] = %d\n", iN[0], iN[1], iM[0][0], iM[0][1] ); printf("in CalcuPar iL[o]= %d iL[1]= %d iL[2] = %d\n", iL[0], iL[1], iL[1]); */ break; case CS_2_SM: iLevels = 2; /* Code rates for prot.-Level A and B for each level */ for (i = 0; i < 2; i++) { /* Protection Level A */ iCodeRate[i][0] = 0 ; // hamversion /* iCodeRate[i][0] = iCodRateCombMSC16SM[Parameter.MSCPrLe.iPartA][i]; */ /* Protection Level B */ iCodeRate[i][1] = iCodRateCombMSC16SM[Parameter.MSCPrLe.iPartB][i]; } /* Define interleaver sequence for all levels */ piInterlSequ = iInterlSequ16SM; iNumEncBits = iN_mux * 2; /* iN: Number of OFDM-cells of each protection level ------------ */ /* N_1 = ceil(8 * X / (2 * RY_Icm * sum(R_p)) * RY_Icm */ iN[0] = 0; // hamversion /* iN[0] = (int) ceil(8 * (_REAL) iMSCDataLenPartA / (2 * (_REAL) iCodRateCombMSC16SM[Parameter.MSCPrLe.iPartA][2] * ( (_REAL) iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][0]][0] / iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][0]][1] + (_REAL) iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][1]][0] / iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][1]][1]))) * iCodRateCombMSC16SM[Parameter.MSCPrLe.iPartA][2]; */ /* Check if result can be possible, if not -> correct. This can happen, if a wrong number is in "Param.Stream[x].iLenPartA" */ if (iN[0] > iN_mux) iN[0] = 0; iN[1] = iN_mux - iN[0]; /* iM: Number of bits each level -------------------------------- */ for (i = 0; i < 2; i++) { /* M_p,1 = 2 * N_1 * R_p */ iM[i][0] = 0; /* iM[i][0] = (int) (2 * iN[0] * (_REAL) iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][i]][0] / iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartA][i]][1]); */ /* M_p,2 = RX_p * floor((2 * N_2 - 12) / RY_p) */ iM[i][1] = iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartB][i]][0] * (int) ((_REAL) (2 * iN[1] - 12) / iPuncturingPatterns[iCodRateCombMSC16SM[ Parameter.MSCPrLe.iPartB][i]][1]); // printf("In calcparam iM[%d][0] = %d iM[%d][1] = %d \n", i, iM[i][0], i, iM[i][1]); } /* iL: Number of bits each protection level --------------------- */ /* Higher protected part */ iL[0] = iM[0][0] + iM[1][0]; /* Lower protected part */ iL[1] = iM[0][1] + iM[1][1]; /* Very strong protected part (VSPP) */ iL[2] = 0; /* printf("in CalcuPar CS_2_SM iN[0]= %d iN[1]= %d iM[0][0] = %d iM[0][1] = %d\n", iN[0], iN[1], iM[0][0], iM[0][1] ); printf("in CalcuPar iL[o]= %d iL[1]= %d iL[2] = %d\n", iL[0], iL[1], iL[1]); */ break; case CS_3_SM: iLevels = 3; /* Code rates for prot.-Level A and B for each level */ for (i = 0; i < 3; i++) { /* Protection Level A */ iCodeRate[i][0] = 0; /* iCodeRate[i][0] = iCodRateCombMSC64SM[Parameter.MSCPrLe.iPartA][i]; */ /* Protection Level B */ iCodeRate[i][1] = iCodRateCombMSC64SM[Parameter.MSCPrLe.iPartB][i]; } /* Define interleaver sequence for all levels */ piInterlSequ = iInterlSequ64SM; iNumEncBits = iN_mux * 2; /* iN: Number of OFDM-cells of each protection level ------------ */ /* N_1 = ceil(8 * X / (2 * RY_Icm * sum(R_p)) * RY_Icm */ iN[0] = 0; /* Check if result can be possible, if not -> correct. This can happen, if a wrong number is in "Param.Stream[x].iLenPartA" */ if (iN[0] > iN_mux) iN[0] = 0; iN[1] = iN_mux - iN[0]; /* iM: Number of bits each level -------------------------------- */ for (i = 0; i < 3; i++) { /* M_p,1 = 2 * N_1 * R_p */ iM[i][0] = 0; /* iM[i][0] = (int) (2 * iN[0] * (_REAL) iPuncturingPatterns[iCodRateCombMSC64SM[ Parameter.MSCPrLe.iPartA][i]][0] / iPuncturingPatterns[iCodRateCombMSC64SM[ Parameter.MSCPrLe.iPartA][i]][1]); */ /* M_p,2 = RX_p * floor((2 * N_2 - 12) / RY_p) */ iM[i][1] = iPuncturingPatterns[iCodRateCombMSC64SM[ Parameter.MSCPrLe.iPartB][i]][0] * (int) ((_REAL) (2 * iN[1] - 12) / iPuncturingPatterns[iCodRateCombMSC64SM[ Parameter.MSCPrLe.iPartB][i]][1]); } /* iL: Number of bits each protection level --------------------- */ /* Higher protected part */ iL[0] = iM[0][0] + iM[1][0] + iM[2][0]; /* Lower protected part */ iL[1] = iM[0][1] + iM[1][1] + iM[2][1]; /* Very strong protected part (VSPP) */ iL[2] = 0; /* printf("in CalcuPar CS_3_SM iN[0]= %d iN[1]= %d iM[0][0] = %d iM[0][1] = %d\n", iN[0], iN[1], iM[0][0], iM[0][1] ); printf("in CalcuPar iL[o]= %d iL[1]= %d iL[2] = %d\n", iL[0], iL[1], iL[2]); */ break; default: break; } /* Set number of output bits for next module */ Parameter.SetNumDecodedBitsMSC(iL[0] + iL[1] + iL[2]); /* Set total number of bits for hiearchical frame (needed for MSC demultiplexer module) */ Parameter.SetNumBitsHieraFrTot(iL[2]); // Parameter.DataParam.iPacketLen = 1234; break; } } qsstv_8.2.12/qsstv/drmtx/common/mlc/MLC.h000664 001750 001750 00000007440 12440612574 020145 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See MLC.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(MLC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define MLC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../util/Modul.h" #include "../Parameter.h" #include "../tables/TableMLC.h" #include "../tables/TableCarMap.h" #include "ConvEncoder.h" //#include "ViterbiDecoder.h" //#include "Metric.h" #include "BitInterleaver.h" #include "QAMMapping.h" #include "EnergyDispersal.h" /* Classes ********************************************************************/ class CMLC { public: CMLC() : iN_mux(0), eChannelType(CT_MSC) {} virtual ~CMLC() {} void CalculateParam(CParameter& Parameter, int iNewChannelType); protected: int iLevels; /* No input bits for each level. First index: Level, second index: Protection level. For three levels: [M_0,l M_1,l M2,l] For six levels: [M_0,lRe M_0,lIm M_1,lRe M_1,lIm M_2,lRe ... ] */ int iM[MC_MAX_NUM_LEVELS][2]; int iN[2]; int iL[3]; int iN_mux; int iCodeRate[MC_MAX_NUM_LEVELS][2]; const int* piInterlSequ; int iNumEncBits; EChanType eChannelType; ECodScheme eCodingScheme; }; class CMLCEncoder : public CTransmitterModul<_BINARY, _COMPLEX>, public CMLC { public: CMLCEncoder() {} virtual ~CMLCEncoder() {} protected: CConvEncoder ConvEncoder[MC_MAX_NUM_LEVELS]; /* Two different types of interleaver table */ CBitInterleaver BitInterleaver[2]; CQAMMapping QAMMapping; CEngergyDispersal EnergyDisp; /* Internal buffers */ CVector<_DECISION> vecEncInBuffer[MC_MAX_NUM_LEVELS]; CVector<_DECISION> vecEncOutBuffer[MC_MAX_NUM_LEVELS]; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& Parameter); }; /******************************************************************************\ * Customized channel (de-)coders * \******************************************************************************/ class CMSCMLCEncoder : public CMLCEncoder { protected: virtual void InitInternal(CParameter& TransmParam) { /* Set corresponding type */ eChannelType = CT_MSC; /* Call init in encoder */ CMLCEncoder::InitInternal(TransmParam); }; }; class CSDCMLCEncoder : public CMLCEncoder { protected: virtual void InitInternal(CParameter& TransmParam) { /* Set corresponding type */ eChannelType = CT_SDC; /* Call init in encoder */ CMLCEncoder::InitInternal(TransmParam); }; }; class CFACMLCEncoder : public CMLCEncoder { protected: virtual void InitInternal(CParameter& TransmParam) { /* Set corresponding type */ eChannelType = CT_FAC; /* Call init in encoder */ CMLCEncoder::InitInternal(TransmParam); }; }; #endif // !defined(MLC_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/mlc/QAMMapping.cpp000664 001750 001750 00000014364 12440612574 022022 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "QAMMapping.h" /* Implementation *************************************************************/ void CQAMMapping::Map(CVector<_DECISION>& vecInputData1, CVector<_DECISION>& vecInputData2, CVector<_DECISION>& vecInputData3, CVector<_DECISION>& vecInputData4, CVector<_DECISION>& vecInputData5, CVector<_DECISION>& vecInputData6, CVector<_COMPLEX>* pcOutputData) { /* We always use "& 1" when we combine binary values with logical operators for safety reasons. */ int i; int iIndexReal; int iIndexImag; switch (eMapType) { case CS_1_SM: /* 4QAM ------------------------------------------------------------- */ /* Mapping according DRM-standard: {i_0 q_0} = (y'_0 y'_1) = (y_0,0 y_0,1) */ for (i = 0; i < iOutputBlockSize; i++) { (*pcOutputData)[i] = _COMPLEX( /* Odd entries (second column in "rTableQAM4") */ rTableQAM4[ExtractBit(vecInputData1[2 * i]) & 1][0], /* Even entries in input-vector */ rTableQAM4[ExtractBit(vecInputData1[2 * i + 1]) & 1][1]); } break; case CS_2_SM: /* 16QAM ------------------------------------------------------------ */ /* Mapping according DRM-standard: {i_0 i_1 q_0 q_1} = (y_0,0 y_1,0 y_0,1 y_1,1) */ for (i = 0; i < iOutputBlockSize; i++) { const int i2i = 2 * i; const int i2ip1 = 2 * i + 1; /* Filling indices [y_0,0, y_1,0]. Incoming bits are shifted to their desired positions in the integer variables "iIndexImag" and "iIndexReal" and combined */ iIndexReal = ((ExtractBit(vecInputData1[i2i]) & 1) << 1) | (ExtractBit(vecInputData2[i2i]) & 1); iIndexImag = ((ExtractBit(vecInputData1[i2ip1]) & 1) << 1) | (ExtractBit(vecInputData2[i2ip1]) & 1); (*pcOutputData)[i] = /* Odd entries (second column in "rTableQAM16") */ _COMPLEX(rTableQAM16[iIndexReal][0], /* Even entries in input-vector */ rTableQAM16[iIndexImag][1]); } break; case CS_3_SM: /* 64QAM SM --------------------------------------------------------- */ /* Mapping according DRM-standard: {i_0 i_1 i_2 q_0 q_1 q_2} = (y_0,0 y_1,0 y_2,0 y_0,1 y_1,1 y_2,1) */ for (i = 0; i < iOutputBlockSize; i++) { const int i2i = 2 * i; const int i2ip1 = 2 * i + 1; /* Filling indices [y_0,0, y_1,0, y_2,0]. Incoming bits are shifted to their desired positions in the integer variables "iIndexImag" and "iIndexReal" and combined */ iIndexReal = ((ExtractBit(vecInputData1[i2i]) & 1) << 2) | ((ExtractBit(vecInputData2[i2i]) & 1) << 1) | (ExtractBit(vecInputData3[i2i]) & 1); iIndexImag = ((ExtractBit(vecInputData1[i2ip1]) & 1) << 2) | ((ExtractBit(vecInputData2[i2ip1]) & 1) << 1) | (ExtractBit(vecInputData3[i2ip1]) & 1); (*pcOutputData)[i] = /* Odd entries (second column in "rTableQAM64SM") */ _COMPLEX(rTableQAM64SM[iIndexReal][0], /* Even entries in input-vector */ rTableQAM64SM[iIndexImag][1]); } break; case CS_3_HMSYM: /* 64QAM HMsym ------------------------------------------------------ */ /* Mapping according DRM-standard: {i_0 i_1 i_2 q_0 q_1 q_2} = (y_0,0 y_1,0 y_2,0 y_0,1 y_1,1 y_2,1) */ for (i = 0; i < iOutputBlockSize; i++) { const int i2i = 2 * i; const int i2ip1 = 2 * i + 1; /* Filling indices [y_0,0, y_1,0, y_2,0]. Incoming bits are shifted to their desired positions in the integer variables "iIndexImag" and "iIndexReal" and combined */ iIndexReal = ((ExtractBit(vecInputData1[i2i]) & 1) << 2) | ((ExtractBit(vecInputData2[i2i]) & 1) << 1) | (ExtractBit(vecInputData3[i2i]) & 1); iIndexImag = ((ExtractBit(vecInputData1[i2ip1]) & 1) << 2) | ((ExtractBit(vecInputData2[i2ip1]) & 1) << 1) | (ExtractBit(vecInputData3[i2ip1]) & 1); (*pcOutputData)[i] = /* Odd entries (second column in "rTableQAM64HMsym") */ _COMPLEX(rTableQAM64HMsym[iIndexReal][0], /* Even entries in input-vector */ rTableQAM64HMsym[iIndexImag][1]); } break; case CS_3_HMMIX: /* 64QAM HMmix------------------------------------------------------- */ /* Mapping according DRM-standard: {i_0 i_1 i_2 q_0 q_1 q_2} = (y_0,0Re y_1,0Re y_2,0Re y_0,0Im y_1,0Im y_2,0Im) */ for (i = 0; i < iOutputBlockSize; i++) { /* Filling indices [y_0,0, y_1,0, y_2,0] (Re, Im). Incoming bits are shifted to their desired positions in the integer variables "iIndexImag" and "iIndexReal" and combined */ iIndexReal = ((ExtractBit(vecInputData1[i]) & 1) << 2) | ((ExtractBit(vecInputData3[i]) & 1) << 1) | (ExtractBit(vecInputData5[i]) & 1); iIndexImag = ((ExtractBit(vecInputData2[i]) & 1) << 2) | ((ExtractBit(vecInputData4[i]) & 1) << 1) | (ExtractBit(vecInputData6[i]) & 1); (*pcOutputData)[i] = /* Odd entries (second column in "rTableQAM64HMmix") */ _COMPLEX(rTableQAM64HMmix[iIndexReal][0], /* Even entries in input-vector */ rTableQAM64HMmix[iIndexImag][1]); } break; } } void CQAMMapping::Init(int iNewOutputBlockSize, ECodScheme eNewCodingScheme) { /* Set the two internal parameters */ iOutputBlockSize = iNewOutputBlockSize; eMapType = eNewCodingScheme; } qsstv_8.2.12/qsstv/drmtx/common/mlc/QAMMapping.h000664 001750 001750 00000003777 12440612574 021475 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(QAM_MAPPING_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define QAM_MAPPING_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../tables/TableQAMMapping.h" #include "utils/vector.h" #include "../Parameter.h" /* Classes ********************************************************************/ class CQAMMapping { public: CQAMMapping() {} virtual ~CQAMMapping() {} void Map(CVector<_DECISION>& vecInputData1, CVector<_DECISION>& vecInputData2, CVector<_DECISION>& vecInputData3, CVector<_DECISION>& vecInputData4, CVector<_DECISION>& vecInputData5, CVector<_DECISION>& vecInputData6, CVector<_COMPLEX>* pcOutputData); void Init(int iNewOutputBlockSize, ECodScheme eNewCodingScheme); protected: int iOutputBlockSize; ECodScheme eMapType; }; #endif // !defined(QAM_MAPPING_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/ofdmcellmapping/CellMappingTable.cpp000664 001750 001750 00000055473 12440612574 025627 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Table of the mapping of OFDM cells. * We build a table of one super-frame where we set flags for each cell to * identify the symbol for this place. E.g. if the flag "CM_MSC" is set for * one table entry this is the cell for a MSC-symbol. The name of the table * is matiMapTab. * We use the table "matcPilotCells" for storing the complex values for the * pilots. For simplicity we allocate memory for all blocks but only the * pilot positions are used. * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "../GlobalDefinitions.h" #include "../tables/TableCarrier.h" #include "CellMappingTable.h" //#define _DEBUG_ 1 /* Implementation *************************************************************/ void CCellMappingTable::MakeTable(ERobMode eNewRobustnessMode, ESpecOcc eNewSpectOccup) { int iNoMSCDummyCells; /* Number of MSC dummy cells */ int iNumTimePilots; /* Number of time pilots per frame */ CScatPilots ScatPilots; int iSym; int iFrameSym; int iCar; int iTimePilotsCounter; int iFreqPilotsCounter; int iScatPilotsCounter; int iMSCCounter; int iFACCounter=0; int iScatPilPhase; int iCarArrInd; int iSpecOccArrayIndex; /* Tables */ const int* piTableFAC; const int* piTableTimePilots; const int* piTableFreqPilots; /* Set Parameters and pointers to the tables ******************************/ switch (eNewSpectOccup) { case SO_0: iSpecOccArrayIndex = 0; break; case SO_1: iSpecOccArrayIndex = 1; break; default: iSpecOccArrayIndex = 1; break; } // initialize defaults to avoid unitialized warning piTableTimePilots = &iTableTimePilRobModA[0][0]; piTableFreqPilots = &iTableFreqPilRobModA[0][0]; piTableFAC = &iTableFACRobModA[0][0]; iNumTimePilots = RMA_NUM_TIME_PIL; /* The robust mode defines all other parameters */ switch (eNewRobustnessMode) { case RM_ROBUSTNESS_MODE_A: iCarrierKmin = iTableCarrierKmin[iSpecOccArrayIndex][0]; iCarrierKmax = iTableCarrierKmax[iSpecOccArrayIndex][0]; iFFTSizeN = RMA_FFT_SIZE_N; RatioTgTu.iEnum = RMA_ENUM_TG_TU; RatioTgTu.iDenom = RMA_DENOM_TG_TU; iNumSymPerFrame = RMA_NUM_SYM_PER_FRAME; iNumSymbolsPerSuperframe = iNumSymPerFrame * NUM_FRAMES_IN_SUPERFRAME; piTableFAC = &iTableFACRobModA[0][0]; iNumTimePilots = RMA_NUM_TIME_PIL; piTableTimePilots = &iTableTimePilRobModA[0][0]; piTableFreqPilots = &iTableFreqPilRobModA[0][0]; iScatPilTimeInt = RMA_SCAT_PIL_TIME_INT; iScatPilFreqInt = RMA_SCAT_PIL_FREQ_INT; /* Scattered pilots phase definition */ ScatPilots.piConst = iTableScatPilConstRobModA; ScatPilots.iColSizeWZ = SIZE_COL_WZ_ROB_MOD_A; ScatPilots.piW = &iScatPilWRobModA[0][0]; ScatPilots.piZ = &iScatPilZRobModA[0][0]; ScatPilots.iQ = iScatPilQRobModA; ScatPilots.piGainTable = &iScatPilGainRobModA[iSpecOccArrayIndex][0]; break; case RM_ROBUSTNESS_MODE_B: iCarrierKmin = iTableCarrierKmin[iSpecOccArrayIndex][1]; iCarrierKmax = iTableCarrierKmax[iSpecOccArrayIndex][1]; iFFTSizeN = RMB_FFT_SIZE_N; RatioTgTu.iEnum = RMB_ENUM_TG_TU; RatioTgTu.iDenom = RMB_DENOM_TG_TU; iNumSymPerFrame = RMB_NUM_SYM_PER_FRAME; iNumSymbolsPerSuperframe = iNumSymPerFrame * NUM_FRAMES_IN_SUPERFRAME; piTableFAC = &iTableFACRobModB[0][0]; iNumTimePilots = RMB_NUM_TIME_PIL; piTableTimePilots = &iTableTimePilRobModB[0][0]; piTableFreqPilots = &iTableFreqPilRobModB[0][0]; iScatPilTimeInt = RMB_SCAT_PIL_TIME_INT; iScatPilFreqInt = RMB_SCAT_PIL_FREQ_INT; /* Scattered pilots phase definition */ ScatPilots.piConst = iTableScatPilConstRobModB; ScatPilots.iColSizeWZ = SIZE_COL_WZ_ROB_MOD_B; ScatPilots.piW = &iScatPilWRobModB[0][0]; ScatPilots.piZ = &iScatPilZRobModB[0][0]; ScatPilots.iQ = iScatPilQRobModB; ScatPilots.piGainTable = &iScatPilGainRobModB[iSpecOccArrayIndex][0]; break; case RM_NO_MODE_DETECTED: case RM_ROBUSTNESS_MODE_D: // not used in HAM default to E joma case RM_ROBUSTNESS_MODE_E: iCarrierKmin = iTableCarrierKmin[iSpecOccArrayIndex][2]; iCarrierKmax = iTableCarrierKmax[iSpecOccArrayIndex][2]; iFFTSizeN = RME_FFT_SIZE_N; RatioTgTu.iEnum = RME_ENUM_TG_TU; RatioTgTu.iDenom = RME_DENOM_TG_TU; iNumSymPerFrame = RME_NUM_SYM_PER_FRAME; iNumSymbolsPerSuperframe = iNumSymPerFrame * NUM_FRAMES_IN_SUPERFRAME; piTableFAC = &iTableFACRobModE[0][0]; iNumTimePilots = RME_NUM_TIME_PIL; piTableTimePilots = &iTableTimePilRobModE[0][0]; piTableFreqPilots = &iTableFreqPilRobModE[0][0]; iScatPilTimeInt = RME_SCAT_PIL_TIME_INT; iScatPilFreqInt = RME_SCAT_PIL_FREQ_INT; /* Scattered pilots phase definition */ ScatPilots.piConst = iTableScatPilConstRobModE; ScatPilots.iColSizeWZ = SIZE_COL_WZ_ROB_MOD_E; ScatPilots.piW = &iScatPilWRobModE[0][0]; ScatPilots.piZ = &iScatPilZRobModE[0][0]; ScatPilots.iQ = iScatPilQRobModE; ScatPilots.piGainTable = &iScatPilGainRobModE[iSpecOccArrayIndex][0]; break; } /* Get number of carriers with DC */ iNumCarrier = iCarrierKmax - iCarrierKmin + 1; /* Length of guard-interval measured in "time-bins". We do the calculation with integer variables -> "/ RatioTgTu.iDenom" MUST be the last operation! */ iGuardSize = iFFTSizeN * RatioTgTu.iEnum / RatioTgTu.iDenom; /* Symbol block size is the guard-interval plus the useful part */ iSymbolBlockSize = iFFTSizeN + iGuardSize; /* Calculate the index of the DC carrier in the shifted spectrum */ iIndexDCFreq = (int) ((_REAL) VIRTUAL_INTERMED_FREQ * iFFTSizeN / SOUNDCRD_SAMPLE_RATE); /* Index of minimum useful carrier (shifted) */ iShiftedKmin = iIndexDCFreq + iCarrierKmin; /* Index. of maximum useful carrier (shifted) */ iShiftedKmax = iIndexDCFreq + iCarrierKmax; /* Calculate number of time-interploated frequency pilots. Special case with robustness mode D: pilots in all carriers! BUT: DC carrier is counted as a pilot in that case!!! Be aware of that! */ if (iScatPilFreqInt > 1) iNumIntpFreqPil = (int) ((_REAL) iNumCarrier / iScatPilFreqInt + 1); else iNumIntpFreqPil = iNumCarrier; // printf("CellMappingTable Maktable iNumCarrier %d iShiftedKmin %d iIndexDCFreq %d iShiftedKmax %d fftsize %d\n", // iNumCarrier, iShiftedKmin, iIndexDCFreq, iShiftedKmax, iFFTSizeN); /* Allocate memory for vectors and matrices ----------------------------- */ /* Allocate memory for mapping table (Matrix) */ matiMapTab.Init(iNumSymbolsPerSuperframe, iNumCarrier); /* Allocate memory for pilot cells definition and set it to zero */ matcPilotCells.Init(iNumSymbolsPerSuperframe, iNumCarrier, _COMPLEX((_REAL) 0.0, (_REAL) 0.0)); /* Allocate memory for vectors with number of certain cells */ veciNumMSCSym.Init(iNumSymbolsPerSuperframe); veciNumFACSym.Init(iNumSymbolsPerSuperframe); /* Build table ************************************************************/ /* Some of the definitions at the beginning are overwritten by successive definitions! E.g., first define all carriers as MSC cells */ iFreqPilotsCounter = 0; iTimePilotsCounter = 0; for (iSym = 0; iSym < iNumSymbolsPerSuperframe; iSym++) { /* Frame symbol: Counts symbols in one frame, not super frame! */ iFrameSym = iSym % iNumSymPerFrame; /* Reset FAC counter at the beginning of each new frame */ if (iFrameSym == 0) iFACCounter = 0; /* Calculate the start value of "p" in equation for gain reference cells in Table 90 (8.4.4.1) */ iScatPilotsCounter = (int) ((_REAL) (iCarrierKmin - (int) ((_REAL) iScatPilFreqInt / 2 + .5) - iScatPilFreqInt * mod(iFrameSym, iScatPilTimeInt) ) / (iScatPilFreqInt * iScatPilTimeInt)); for (iCar = iCarrierKmin; iCar < iCarrierKmax + 1; iCar++) { /* Set carrier array index (since we do not have negative indices in c++) */ iCarArrInd = iCar - iCarrierKmin; /* MSC ---------------------------------------------------------- */ /* First set all cells to MSC-cells */ matiMapTab[iSym][iCarArrInd] = CM_MSC; /* FAC ---------------------------------------------------------- */ /* FAC positions are defined in a table */ if (iFACCounter <= NUM_FAC_CELLS) { /* piTableFAC[x * 2]: first column; piTableFAC[x * 2 + 1]: second column */ if (piTableFAC[iFACCounter * 2] * iNumCarrier + piTableFAC[iFACCounter * 2 + 1] == iFrameSym * iNumCarrier + iCar) { iFACCounter++; matiMapTab[iSym][iCarArrInd] = CM_FAC; } } /* Scattered pilots --------------------------------------------- */ /* Standard: 8.4.4.3: "In some cases gain references fall in locations which coincide with those already defined for either frequency or time references. In these cases, the phase definitions given in clauses 8.4.2 and 8.4.3 take precedence." Therefore, Scattered pilots must be definded FIRST here! */ /* The rule for calculating the scattered pilots is defined in the specification in the following form: e.g.: k = 2 + 4 * (s mod 5) + 20 * p We define a "frequency-" (FreqInt) and "time-interpolation" (TimeInt). In this example, "4" is the FreqInt and "5" is the TimeInt. The first term "2" is the half of the FreqInt, rounded towards infinity. The parameter "20" is FreqInt * TimeInt */ if (iCar == (int) ((_REAL) iScatPilFreqInt / 2 + .5) + iScatPilFreqInt * mod(iFrameSym, iScatPilTimeInt) + iScatPilFreqInt * iScatPilTimeInt * iScatPilotsCounter) { iScatPilotsCounter++; /* Set flag in mapping table */ matiMapTab[iSym][iCarArrInd] = CM_SCAT_PI; /* Set complex value for this pilot */ /* Phase calculation ---------------------------------------- */ int in, im, ip, i; /* Calculations as in drm-standard (8.4.4.3.1) */ /* "in" is ROW No and "im" is COLUMN No! */ in = mod(iFrameSym, ScatPilots.piConst[1] /* "y" */); im = (int) ((_REAL) iFrameSym / ScatPilots.piConst[1] /* "y" */); ip = (int) ((_REAL) (iCar - ScatPilots.piConst[2] /* "k_0" */ - in * ScatPilots.piConst[0] /* "x" */) / ( ScatPilots.piConst[0] /* "x" */ * ScatPilots.piConst[1] /* "y" */)); /* Phase_1024[s,k] = (4Z_256[n,m]pW_1024[n,m] + p^2(1 + s)Q_1024) mod 1024 */ iScatPilPhase = mod(4 * ScatPilots.piZ[in * ScatPilots.iColSizeWZ + im] + ip * ScatPilots.piW[in * ScatPilots.iColSizeWZ + im] + ip * ip * (1 + iFrameSym) * ScatPilots.iQ, 1024); /* Gain calculation and applying of complex value ----------- */ /* Test, if current carrier-index is one of the "boosted pilots" position */ _BOOLEAN bIsBoostedPilot = false; for (i = 0; i < NUM_BOOSTED_SCAT_PILOTS; i++) { /* In case of match set flag */ if (ScatPilots.piGainTable[i] == iCar) bIsBoostedPilot = true; } /* Boosted pilot: Gain = 2, Regular pilot: Gain = sqrt(2) */ if (bIsBoostedPilot) { matcPilotCells[iSym][iCarArrInd] = Polar2Cart(2, iScatPilPhase); /* Add flag for boosted pilot */ matiMapTab[iSym][iCarArrInd] |= CM_BOOSTED_PI; } else { matcPilotCells[iSym][iCarArrInd] = Polar2Cart(sqrt((_REAL) 2.0), iScatPilPhase); } } /* Time-reference pilots ---------------------------------------- */ /* Time refs at the beginning of each frame, we use a table */ if (iFrameSym == 0) { /* Use only the first column in piTableTimePilots */ if (piTableTimePilots[iTimePilotsCounter * 2] == iCar) { /* Set flag in mapping table, consider case of both, scattered pilot and time pilot at same position */ if (_IsScatPil(matiMapTab[iSym][iCarArrInd])) matiMapTab[iSym][iCarArrInd] |= CM_TI_PI; else matiMapTab[iSym][iCarArrInd] = CM_TI_PI; /* Set complex value for this pilot */ matcPilotCells[iSym][iCarArrInd] = Polar2Cart(sqrt((_REAL) 2.0), piTableTimePilots[iTimePilotsCounter * 2 + 1]); if (iTimePilotsCounter == iNumTimePilots - 1) iTimePilotsCounter = 0; else iTimePilotsCounter++; } } /* Frequency-reference pilots ----------------------------------- */ /* These pilots are in all symbols, the positions are stored in a table */ /* piTableFreqPilots[x * 2]: first column; piTableFreqPilots[x * 2 + 1]: second column */ if (piTableFreqPilots[iFreqPilotsCounter * 2] == iCar) { /* Set flag in mapping table, consider case of multiple definitions of pilot-mapping */ if (_IsTiPil(matiMapTab[iSym][iCarArrInd]) || _IsScatPil(matiMapTab[iSym][iCarArrInd])) { matiMapTab[iSym][iCarArrInd] |= CM_FRE_PI; } else matiMapTab[iSym][iCarArrInd] = CM_FRE_PI; /* Set complex value for this pilot */ /* Test for "special case" defined in drm-standard */ _BOOLEAN bIsFreqPilSpeciCase = false; if (eNewRobustnessMode == RM_ROBUSTNESS_MODE_E) { /* For robustness mode D, carriers 7 and 21 (Means: first and second pilot, not No. 28 (NUM_FREQ_PILOTS - 1) */ if (iFreqPilotsCounter != NUM_FREQ_PILOTS - 1) { /* Test for odd values of "s" (iSym) */ if ((iFrameSym % 2) == 1) bIsFreqPilSpeciCase = true; } } /* Apply complex value */ if (bIsFreqPilSpeciCase) matcPilotCells[iSym][iCarArrInd] = Polar2Cart(sqrt((_REAL) 2.0), mod(piTableFreqPilots[iFreqPilotsCounter * 2 + 1] + 512, 1024)); else matcPilotCells[iSym][iCarArrInd] = Polar2Cart(sqrt((_REAL) 2.0), piTableFreqPilots[iFreqPilotsCounter * 2 + 1]); /* Increase counter and wrap if needed */ if (iFreqPilotsCounter == NUM_FREQ_PILOTS - 1) iFreqPilotsCounter = 0; else iFreqPilotsCounter++; } /* DC-carrier (not used by DRM) --------------------------------- */ /* Mark DC-carrier. Must be marked after scattered pilots, because in one case (Robustness Mode D) some pilots must be overwritten! */ if (iCar == 0) matiMapTab[iSym][iCarArrInd] = CM_DC; /* In Robustness Mode A there are three "not used carriers" */ if (eNewRobustnessMode == RM_ROBUSTNESS_MODE_A) { if ((iCar == -1) || (iCar == 1)) matiMapTab[iSym][iCarArrInd] = CM_DC; } } } /* Count individual cells *************************************************/ /* We need to count the cells in a symbol for defining how many values from each source is needed to generate one symbol in carrier-mapping */ /* Init all counters */ iMaxNumMSCSym = 0; iMSCCounter = 0; rAvPowPerSymbol = (_REAL) 0.0; rAvPilPowPerSym = (_REAL) 0.0; for (iSym = 0; iSym < iNumSymbolsPerSuperframe; iSym++) { /* Init all counters */ veciNumMSCSym[iSym] = 0; veciNumFACSym[iSym] = 0; for (iCar = 0; iCar < iNumCarrier; iCar++) { /* MSC */ if (_IsMSC(matiMapTab[iSym][iCar])) { veciNumMSCSym[iSym]++; /* Count ALL MSC cells per super-frame */ iMSCCounter++; } /* FAC */ if (_IsFAC(matiMapTab[iSym][iCar])) veciNumFACSym[iSym]++; /* Calculations for average power per symbol (needed for SNR estimation and simulation). DC carrier is zero (contributes not to the average power) */ if (!_IsDC(matiMapTab[iSym][iCar])) { if (_IsData(matiMapTab[iSym][iCar])) { /* Data cells have average power of 1 */ rAvPowPerSymbol += (_REAL) 1.0; } else { /* All pilots have power of 2 except of the boosted pilots at the edges of the spectrum (they have power of 4) */ if (_IsBoosPil(matiMapTab[iSym][iCar])) { rAvPowPerSymbol += (_REAL) 4.0; rAvPilPowPerSym += (_REAL) 4.0; } else { /* Regular pilot has power of 2 */ rAvPowPerSymbol += (_REAL) 2.0; rAvPilPowPerSym += (_REAL) 2.0; } } } } /* Set maximum for symbol */ /* MSC */ if (iMaxNumMSCSym < veciNumMSCSym[iSym]) iMaxNumMSCSym = veciNumMSCSym[iSym]; } /* Set number of useful MSC cells */ iNumUsefMSCCellsPerFrame = (int) (iMSCCounter / NUM_FRAMES_IN_SUPERFRAME); /* Calculate dummy cells for MSC */ iNoMSCDummyCells = iMSCCounter - iNumUsefMSCCellsPerFrame * NUM_FRAMES_IN_SUPERFRAME; /* Correct last MSC count (because of dummy cells) */ veciNumMSCSym[iNumSymbolsPerSuperframe - 1] -= iNoMSCDummyCells; /* Normalize the average powers */ rAvPowPerSymbol /= iNumSymbolsPerSuperframe; rAvPilPowPerSym /= iNumSymbolsPerSuperframe; /* ########################################################################## */ #ifdef _DEBUG_ /* Save table in file */ FILE* pFile = fopen("CarMapTable.txt", "w"); /* Title */ fprintf(pFile, "Robustness mode "); switch (eNewRobustnessMode) { case RM_ROBUSTNESS_MODE_A: fprintf(pFile, "A"); break; case RM_ROBUSTNESS_MODE_B: fprintf(pFile, "B"); break; case RM_ROBUSTNESS_MODE_E: fprintf(pFile, "E"); break; } fprintf(pFile, " / Spectrum occupancy %d\n\n", iSpecOccArrayIndex); /* Actual table */ for (int i = 0; i < iNumSymbolsPerSuperframe; i++) { for (int j = 0; j < iNumCarrier; j++) { if (_IsDC(matiMapTab[i][j])) { fprintf(pFile, ":"); continue; } if (_IsMSC(matiMapTab[i][j])) { fprintf(pFile, "."); continue; } if (_IsFAC(matiMapTab[i][j])) { fprintf(pFile, "X"); continue; } if (_IsTiPil(matiMapTab[i][j])) { fprintf(pFile, "T"); continue; } if (_IsFreqPil(matiMapTab[i][j])) { fprintf(pFile, "f"); continue; } if (_IsScatPil(matiMapTab[i][j])) { /* Special mark for boosted pilots */ if (_IsBoosPil(matiMapTab[i][j])) fprintf(pFile, "*"); else fprintf(pFile, "0"); continue; } } fprintf(pFile, "\n"); } /* Legend */ fprintf(pFile, "\n\nLegend:\n\t: DC-carrier\n\t. MCS cells"); fprintf(pFile, "\n\tX FAC cells\n\tT time pilots\n\tf frequency pilots"); fprintf(pFile, "\n\t0 scattered pilots\n\t* boosted scattered pilots\n"); fclose(pFile); //#ifdef _DEBUG_ /* Save pilot values in file */ /* Use following command to plot pilot complex values in Matlab: clear all;close all;load PilotCells.dat;subplot(211),mesh(abs(complex(PilotCells(:,1:2:end), PilotCells(:,2:2:end))));subplot(212),mesh(angle(complex(PilotCells(:,1:2:end), PilotCells(:,2:2:end)))) (It plots the absolute of the pilots in the upper plot and angle in the lower plot.) */ pFile = fopen("test/PilotCells.dat", "w"); for (int z = 0; z < iNumSymbolsPerSuperframe; z++) { for (int v = 0; v < iNumCarrier; v++) fprintf(pFile, "%e %e ", matcPilotCells[z][v].real(), matcPilotCells[z][v].imag()); fprintf(pFile, "\n"); } fclose(pFile); #endif /* ########################################################################## */ } _COMPLEX CCellMappingTable::Polar2Cart(const _REAL rAbsolute, const int iPhase) const { /* This function takes phases normalized to 1024 as defined in the drm- standard. */ return _COMPLEX(rAbsolute * cos((_REAL) 2 * crPi * iPhase / 1024), rAbsolute * sin((_REAL) 2 * crPi * iPhase / 1024)); } int CCellMappingTable::mod(const int ix, const int iy) const { /* Modulus definition for integer numbers */ if (ix < 0) return ix % iy + iy; else return ix % iy; } qsstv_8.2.12/qsstv/drmtx/common/ofdmcellmapping/CellMappingTable.h000664 001750 001750 00000012167 12440612574 025265 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(CELLMAPPINGTABLE_H__3B0BA660_CA63_4347A0D31912__INCLUDED_) #define CELLMAPPINGTABLE_H__3B0BA660_CA63_4347A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../tables/TableCarMap.h" #include "../tables/TableFAC.h" #include "utils/vector.h" /* Definitions ****************************************************************/ /* Power definitions for pilots, boosted pilots and data cells (average) */ #define AV_DATA_CELLS_POWER ((_REAL) 1.0) #define AV_PILOT_POWER ((_REAL) 2.0) #define AV_BOOSTED_PIL_POWER ((_REAL) 4.0) /* We define a bit for each flag to allow multiple assignments */ #define CM_DC 1 /* Bit 0 */ // CM: Carrier Mapping #define CM_MSC 2 /* Bit 1 */ #define CM_SDC 4 /* Bit 2 */ #define CM_FAC 8 /* Bit 3 */ #define CM_TI_PI 16 /* Bit 4 */ #define CM_FRE_PI 32 /* Bit 5 */ #define CM_SCAT_PI 64 /* Bit 6 */ #define CM_BOOSTED_PI 128 /* Bit 7 */ /* Definitions for checking the cells */ #define _IsDC(a) ((a) & CM_DC) #define _IsMSC(a) ((a) & CM_MSC) #define _IsSDC(a) ((a) & CM_SDC) #define _IsFAC(a) ((a) & CM_FAC) #define _IsData(a) (((a) & CM_MSC) || ((a) & CM_SDC) || ((a) & CM_FAC)) #define _IsTiPil(a) ((a) & CM_TI_PI) #define _IsFreqPil(a) ((a) & CM_FRE_PI) #define _IsScatPil(a) ((a) & CM_SCAT_PI) #define _IsPilot(a) (((a) & CM_TI_PI) || ((a) & CM_FRE_PI) || ((a) & CM_SCAT_PI)) #define _IsBoosPil(a) ((a) & CM_BOOSTED_PI) /* Classes ********************************************************************/ class CCellMappingTable { public: CCellMappingTable() : iNumSymbolsPerSuperframe(0) {} virtual ~CCellMappingTable() {} void MakeTable(ERobMode eNewRobustnessMode, ESpecOcc eNewSpectOccup); struct CRatio {int iEnum; int iDenom;}; /* Mapping table and pilot cell matrix */ CMatrix matiMapTab; CMatrix<_COMPLEX> matcPilotCells; int iNumSymbolsPerSuperframe; int iNumSymPerFrame; /* Number of symbols per frame */ int iNumCarrier; int iScatPilTimeInt; /* Time interpolation */ int iScatPilFreqInt; /* Frequency interpolation */ int iMaxNumMSCSym; /* Max number of MSC cells in a symbol */ /* Number of MSC cells in a symbol */ CVector veciNumMSCSym; /* Number of FAC cells in a symbol */ CVector veciNumFACSym; /* Number of SDC cells in a symbol */ CVector veciNumSDCSym; int iFFTSizeN; /* FFT size of the OFDM modulation */ int iCarrierKmin; /* Carrier index of carrier with lowest frequency */ int iCarrierKmax; /* Carrier index of carrier with highest frequency */ int iIndexDCFreq; /* Index of DC carrier */ int iShiftedKmin; /* Shifted carrier min ("sound card pass-band") */ int iShiftedKmax; /* Shifted carrier max ("sound card pass-band") */ CRatio RatioTgTu; /* Ratio between guard-interval and useful part */ int iGuardSize; /* Length of guard-interval measured in "time-bins" */ int iSymbolBlockSize; /* Useful part plus guard-interval in "time-bins" */ int iNumIntpFreqPil; /* Number of time-interploated frequency pilots */ int iNumUsefMSCCellsPerFrame; /* Number of MSC cells per multiplex frame N_{MUX} */ int iNumSDCCellsPerSFrame; /* Number of SDC cells per super-frame */ /* Needed for SNR estimation and simulation */ _REAL rAvPowPerSymbol; /* Total average power per symbol */ _REAL rAvScatPilPow; /* Average power of scattered pilots per cell */ _REAL rAvPilPowPerSym ; /* added pa0mbo */ protected: /* Internal parameters for MakeTable function --------------------------- */ struct CScatPilots { CScatPilots(): piConst(NULL), iColSizeWZ(0), piW(NULL), piZ(NULL), iQ(0),piGainTable(NULL) {} /* For the pase */ const int* piConst; int iColSizeWZ; const int* piW; const int* piZ; int iQ; /* For the gain */ const int* piGainTable; }; private: _COMPLEX Polar2Cart(const _REAL rAbsolute, const int iPhase) const; int mod(const int ix, const int iy) const; }; #endif // !defined(CELLMAPPINGTABLE_H__3B0BA660_CA63_4347A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/ofdmcellmapping/OFDMCellMapping.cpp000664 001750 001750 00000011422 12440612574 025307 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * Mapping of the symbols on the carriers * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "OFDMCellMapping.h" #include "../tables/TableCarrier.h" /* Implementation *************************************************************/ /******************************************************************************\ * OFDM cells mapping * \******************************************************************************/ void COFDMCellMapping::ProcessDataInternal(CParameter& TransmParam) { const CCellMappingTable& Param = TransmParam.CellMappingTable; /* pa0mbo */ int iCar; int iMSCCounter; int iFACCounter; int iDummyCellCounter; int iSymbolCounterAbs; /* Mapping of the data and pilot cells on the OFDM symbol --------------- */ /* Set absolute symbol position */ iSymbolCounterAbs = TransmParam.iFrameIDTransm * iNumSymPerFrame + iSymbolCounter; /* Init temporary counter */ iDummyCellCounter = 0; iMSCCounter = 0; iFACCounter = 0; for (iCar = 0; iCar < iNumCarrier; iCar++) { /* MSC */ if (_IsMSC(Param.matiMapTab[iSymbolCounterAbs][iCar])) /* pa0mbo was TransmParam. */ { if (iMSCCounter >= Param.veciNumMSCSym[iSymbolCounterAbs]) { /* Insert dummy cells */ (*pvecOutputData)[iCar] = pcDummyCells[iDummyCellCounter]; iDummyCellCounter++; } else (*pvecOutputData)[iCar] = (*pvecInputData)[iMSCCounter]; iMSCCounter++; } /* FAC */ if (_IsFAC(Param.matiMapTab[iSymbolCounterAbs][iCar])) { (*pvecOutputData)[iCar] = (*pvecInputData2)[iFACCounter]; iFACCounter++; } /* DC carrier */ if (_IsDC(Param.matiMapTab[iSymbolCounterAbs][iCar])) (*pvecOutputData)[iCar] = _COMPLEX((_REAL) 0.0, (_REAL) 0.0); /* Pilots */ if (_IsPilot(Param.matiMapTab[iSymbolCounterAbs][iCar])) (*pvecOutputData)[iCar] = Param.matcPilotCells[iSymbolCounterAbs][iCar]; } /* Increase symbol-counter and wrap if needed */ iSymbolCounter++; if (iSymbolCounter == iNumSymPerFrame) { iSymbolCounter = 0; /* Increase frame-counter (ID) (Used also in FAC.cpp) */ TransmParam.iFrameIDTransm++; if (TransmParam.iFrameIDTransm == NUM_FRAMES_IN_SUPERFRAME) TransmParam.iFrameIDTransm = 0; } /* Set absolute symbol position (for updated relative positions) */ iSymbolCounterAbs = TransmParam.iFrameIDTransm * iNumSymPerFrame + iSymbolCounter; /* Set input block-sizes for next symbol */ iInputBlockSize = Param.veciNumMSCSym[iSymbolCounterAbs]; iInputBlockSize2 = Param.veciNumFACSym[iSymbolCounterAbs]; /* printf("OFDMCellmapping proces updated iInpblk %d iInp2 %d iSymbcntrabs %d \n", iInputBlockSize, iInputBlockSize2, iSymbolCounterAbs); */ } void COFDMCellMapping::InitInternal(CParameter& TransmParam) { const CCellMappingTable& Param = TransmParam.CellMappingTable; /* pa0mbo */ iNumSymPerFrame = Param.iNumSymPerFrame; iNumCarrier = Param.iNumCarrier; /* Init symbol-counter */ iSymbolCounter = 0; /* Init frame ID */ TransmParam.iFrameIDTransm = 0; /* Choose right dummy cells for MSC QAM scheme */ switch (TransmParam.eMSCCodingScheme) { case CS_3_HMSYM: // not use so default to case CS_2_SM case CS_3_HMMIX: case CS_1_SM: case CS_2_SM: // pa0mbo was CParameter::CS_2_SM pcDummyCells = (_COMPLEX*) &cDummyCells16QAM[0]; break; case CS_3_SM: pcDummyCells = (_COMPLEX*) &cDummyCells64QAM[0]; // pa0mbo was CParameter::CS_#_SM break; } /* Define block-sizes for input and output of the module ---------------- */ iInputBlockSize = Param.veciNumMSCSym[0]; /* MSC */ iInputBlockSize2 = Param.veciNumFACSym[0]; /* FAC */ iOutputBlockSize = Param.iNumCarrier; /* Output */ // printf("OFDM CELLMAP : Inputblksiz %d Inpublksiz2 %d OutputBlkSiz %d\n", // iInputBlockSize, iInputBlockSize2, iOutputBlockSize); } qsstv_8.2.12/qsstv/drmtx/common/ofdmcellmapping/OFDMCellMapping.h000664 001750 001750 00000003635 12440612574 024763 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(OFDMCELLMAPPING_H__3B0BA660_CA63_4344_BB2BE7A0D31912__INCLUDED_) #define OFDMCELLMAPPING_H__3B0BA660_CA63_4344_BB2BE7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../Parameter.h" #include "../util/Modul.h" #include "../tables/TableCarMap.h" #include "../tables/TableFAC.h" /* Classes ********************************************************************/ class COFDMCellMapping : public CTransmitterModul<_COMPLEX, _COMPLEX> { public: COFDMCellMapping() {} virtual ~COFDMCellMapping() {} protected: int iNumSymPerFrame; int iNumCarrier; int iSymbolCounter; _COMPLEX* pcDummyCells; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; #endif // !defined(OFDMCELLMAPPING_H__3B0BA660_CA63_4344_BB2BE7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/sourcedecoders/AudioSourceDecoder.cpp000664 001750 001750 00000011647 12440612574 026037 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * Audio source encoder/decoder * * adapted to ham sstv use PA0MBO - Ties Bos * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 1111 * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "AudioSourceDecoder.h" #include #include #define AUD_DEC_TRANSFROM_LENGTH 960 /******************************************************************************\ * Encoder * \******************************************************************************/ void CAudioSourceEncoderImplementation::ProcessDataInternal( CVectorEx < _BINARY > *pvecOutputData, int &iOutputBlockSize) { int i; /* Reset data to zero. This is important since usually not all data is used and this data has to be set to zero as defined in the DRM standard */ for (i = 0; i < iOutputBlockSize; i++) (*pvecOutputData)[i] = 0; /* Data service and text message application ---------------------------- */ if (bIsDataService == true) { // TODO: make a separate modul for data encoding /* Write data packets in stream */ CVector < _BINARY > vecbiData; const int iNumPack = iOutputBlockSize / iTotPacketSize; // printf("In process data AudioSourceEnc iOutputBlcksi %d iTotPacketSize = %d \n", iOutputBlockSize, iTotPacketSize); int iPos = 0; for (int j = 0; j < iNumPack; j++) { /* Get new packet */ DataEncoder.GeneratePacket(vecbiData); /* Put it on stream */ for (i = 0; i < iTotPacketSize; i++) { (*pvecOutputData)[iPos] = vecbiData[i]; iPos++; } } } } void CAudioSourceEncoderImplementation::InitInternalTx(CParameter & TransmParam, int &iOutputBlockSize) { int iCurStreamID; int iCurSelServ = 0; // TEST TransmParam.Lock(); // Calculate number of input samples in mono. Audio block are always 400 ms long // const int iNumInSamplesMono = (int) ((_REAL) SOUNDCRD_SAMPLE_RATE * (_REAL) 0.4 /* 400 ms */ ); /* Set the total available number of bits, byte aligned */ iTotNumBitsForUsage = (TransmParam.iNumDecodedBitsMSC / SIZEOF__BYTE) * SIZEOF__BYTE; /* Total number of bytes which can be used for data and audio */ const int iTotNumBytesForUsage = iTotNumBitsForUsage / SIZEOF__BYTE; /* printf("in audiosourceEncoder init smplmono = %d iTotNumBitsForUsage = %d bytefor usage = %d \n", iNumInSamplesMono, iTotNumBitsForUsage, iTotNumBytesForUsage ); */ if (TransmParam.iNumDataService == 1) { /* Data service ----------------------------------------------------- */ bIsDataService = true; // printf("Data servic is true \n"); iTotPacketSize = DataEncoder.Init(TransmParam); // printf("na DataEncoder Init in AudioSourceEncoder init iTotPacketSize = %d\n", iTotPacketSize); /* Get stream ID for data service */ iCurStreamID = TransmParam.Service[iCurSelServ].DataParam.iStreamID; /* printf(" in AudioSourceEncoder dataservice is true iTotPacketSize = %d, custreamId = %d \n", iTotPacketSize, iCurStreamID ); */ } else { printf("Not implemented \n"); exit(1); } /* Adjust part B length for SDC stream. Notice, that the "TransmParam.iNumDecodedBitsMSC" parameter depends on these settings. Thus, length part A and B have to be set before, preferably in the DRMTransmitter initialization */ if ((TransmParam.Stream[iCurStreamID].iLenPartA == 0) || (iTotNumBytesForUsage < TransmParam.Stream[iCurStreamID].iLenPartA)) { /* Equal error protection was chosen or protection part A was chosen too high, set to equal error protection! */ TransmParam.Stream[iCurStreamID].iLenPartA = 0; TransmParam.Stream[iCurStreamID].iLenPartB = iTotNumBytesForUsage; } else TransmParam.Stream[iCurStreamID].iLenPartB = iTotNumBytesForUsage - TransmParam.Stream[iCurStreamID].iLenPartA; /* Define input and output block size */ iOutputBlockSize = TransmParam.iNumDecodedBitsMSC; TransmParam.Unlock(); } CAudioSourceEncoderImplementation::~CAudioSourceEncoderImplementation() { } qsstv_8.2.12/qsstv/drmtx/common/sourcedecoders/AudioSourceDecoder.h000664 001750 001750 00000010234 12440612574 025473 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer, Ollie Haffenden * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(AUIDOSOURCEDECODER_H__3B0BA660_CABB2B_23E7A0D31912__INCLUDED_) #define AUIDOSOURCEDECODER_H__3B0BA660_CABB2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../Parameter.h" #include "../util/Modul.h" #include "../util/CRC.h" //#include "../TextMessage.h" #include "../datadecoding/DataDecoder.h" #include "../util/Utilities.h" /* Classes ********************************************************************/ class CAudioSourceEncoderImplementation { public: CAudioSourceEncoderImplementation() : bUsingTextMessage(false) {} virtual ~CAudioSourceEncoderImplementation(); // void SetTextMessage(const string& strText); // void ClearTextMessage(); void SetPicFileName(QByteArray *ba, const QString name,const QString format) { DataEncoder.GetSliShowEnc()->AddArray(ba,name,format); } void ClearPicFileNames() {DataEncoder.GetSliShowEnc()->ClearAllFileNames();} _BOOLEAN GetTransStat(string& strCPi, _REAL& rCPe) {return DataEncoder.GetSliShowEnc()->GetTransStat(strCPi, rCPe);} protected: // CTextMessageEncoder TextMessage; _BOOLEAN bUsingTextMessage; CDataEncoder DataEncoder; int iTotPacketSize; _BOOLEAN bIsDataService; int iTotNumBitsForUsage; public: virtual void InitInternalTx(CParameter &TransmParam, int &iOutputBlockSize); // virtual void InitInternalRx(CParameter& Param, int &iInputBlockSize, int &iOutputBlockSize); virtual void ProcessDataInternal( CVectorEx<_BINARY>* pvecOutputData, int &iOutputBlockSize); // virtual void ProcessDataInternalRx( CVectorEx<_SAMPLE>* pvecInputData, // CVectorEx<_BINARY>* pvecOutputData, int &InputBlockSize, int &iOutputBlockSize); // virtual void ProcessDataInternal(CVectorEx<_SAMPLE>*,CVectorEx<_BINARY>* pvecOutputData, int &, int &iOutputBlockSize); }; class CAudioSourceEncoder : public CTransmitterModul<_SAMPLE, _BINARY> { public: CAudioSourceEncoder() {} virtual ~CAudioSourceEncoder() {} // void SetTextMessage(const string& strText) {AudioSourceEncoderImpl.SetTextMessage(strText);} // void ClearTextMessage() {AudioSourceEncoderImpl.ClearTextMessage();} void SetPicFileName(QByteArray *ba, const QString name,const QString format) { AudioSourceEncoderImpl.SetPicFileName(ba,name,format); } void ClearPicFileNames() {AudioSourceEncoderImpl.ClearPicFileNames();} _BOOLEAN GetTransStat(string& strCPi, _REAL& rCPe) {return AudioSourceEncoderImpl.GetTransStat(strCPi, rCPe);} protected: CAudioSourceEncoderImplementation AudioSourceEncoderImpl; virtual void InitInternal(CParameter& TransmParam) { AudioSourceEncoderImpl.InitInternalTx(TransmParam, iOutputBlockSize); } virtual void ProcessDataInternal(CParameter& ) { AudioSourceEncoderImpl.ProcessDataInternal(pvecOutputData, iOutputBlockSize); } // virtual void ProcessDataInternalRx(CParameter& ) // { // AudioSourceEncoderImpl.ProcessDataInternalRx(pvecInputData, pvecOutputData, iInputBlockSize, iOutputBlockSize); // } }; #endif // !defined(AUIDOSOURCEDECODER_H__3B0BA660_CABB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableAMSS.h000664 001750 001750 00000003370 12440612574 021742 0ustar00jomajoma000000 000000 /******************************************************************************\ * BBC Research & Development * Copyright (c) 2005 * * Author(s): * Andrew Murphy * * Description: * Tables for AMSS * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(__TABLE_AMSS_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_) #define __TABLE_AMSS_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_ #include #include "../GlobalDefinitions.h" /* Definitions ****************************************************************/ #define LEN_TABLE_AMSS_CARRIER_MODE 8 const string strTableAMSSCarrierMode[LEN_TABLE_AMSS_CARRIER_MODE] = { "No Carrier Control", // 0 0 0 "reserved", // 0 0 1 "AMC Mode 1 (-3dB)", // 0 1 0 "AMC Mode 2 (-6dB)", // 0 1 1 "DAM Mode 1 (+3dB)", // 1 0 0 "DAM Mode 2 (+6dB)", // 1 0 1 "reserved", // 1 1 0 "reserved" // 1 1 1 }; #endif // !defined(__TABLE_AMSS_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableCarMap.h000664 001750 001750 00000016143 12440612574 022344 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sttv use Ties Bos - PA0MBO * * Description: * Tables for carrier mapping * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(TABLE_CAR_MAP_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) #define TABLE_CAR_MAP_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_ #include "../GlobalDefinitions.h" #include "../matlib/Matlib.h" #include "TableQAMMapping.h" /* Global functions ***********************************************************/ /* ---------------------------------------------------------------------------- Implementation of distance to nearest constellation point (symbol) for all QAM types */ inline CComplex MinDist4QAM(const CComplex cI) { /* Return vector pointing to nearest signal point of this constellation. 2 possible constellation points for real and imaginary axis */ return CComplex( /* Real axis minimum distance */ Min(Abs(rTableQAM4[0][0] - Real(cI)), Abs(rTableQAM4[1][0] - Real(cI))), /* Imaginary axis minimum distance */ Min(Abs(rTableQAM4[0][1] - Imag(cI)), Abs(rTableQAM4[1][1] - Imag(cI)))); } inline CComplex MinDist16QAM(const CComplex cI) { /* Return vector pointing to nearest signal point of this constellation. 4 possible constellation points for real and imaginary axis */ return CComplex( /* Real axis minimum distance */ Min(Abs(rTableQAM16[0][0] - Real(cI)), Abs(rTableQAM16[1][0] - Real(cI)), Abs(rTableQAM16[2][0] - Real(cI)), Abs(rTableQAM16[3][0] - Real(cI))), /* Imaginary axis minimum distance */ Min(Abs(rTableQAM16[0][1] - Imag(cI)), Abs(rTableQAM16[1][1] - Imag(cI)), Abs(rTableQAM16[2][1] - Imag(cI)), Abs(rTableQAM16[3][1] - Imag(cI)))); } inline CComplex MinDist64QAM(const CComplex cI) { /* Return vector pointing to nearest signal point of this constellation. 8 possible constellation points for real and imaginary axis */ return CComplex( /* Real axis minimum distance */ Min(Abs(rTableQAM64SM[0][0] - Real(cI)), Abs(rTableQAM64SM[1][0] - Real(cI)), Abs(rTableQAM64SM[2][0] - Real(cI)), Abs(rTableQAM64SM[3][0] - Real(cI)), Abs(rTableQAM64SM[4][0] - Real(cI)), Abs(rTableQAM64SM[5][0] - Real(cI)), Abs(rTableQAM64SM[6][0] - Real(cI)), Abs(rTableQAM64SM[7][0] - Real(cI))), /* Imaginary axis minimum distance */ Min(Abs(rTableQAM64SM[0][1] - Imag(cI)), Abs(rTableQAM64SM[1][1] - Imag(cI)), Abs(rTableQAM64SM[2][1] - Imag(cI)), Abs(rTableQAM64SM[3][1] - Imag(cI)), Abs(rTableQAM64SM[4][1] - Imag(cI)), Abs(rTableQAM64SM[5][1] - Imag(cI)), Abs(rTableQAM64SM[6][1] - Imag(cI)), Abs(rTableQAM64SM[7][1] - Imag(cI)))); } /* Time pilots ****************************************************************/ /* The two numbers are: {carrier no, phase} (Phases are normalized to 1024) */ #define RMA_NUM_TIME_PIL 16 const int iTableTimePilRobModA[RMA_NUM_TIME_PIL][2] = { { 6, 973}, { 7, 205}, {11, 717}, {12, 264}, {15, 357}, {16, 357}, {23, 952}, {29, 440}, {30, 856}, {33, 88}, {34, 88}, {38, 68}, {39, 836}, {41, 836}, {45, 836}, {46, 1008}, }; #define RMB_NUM_TIME_PIL 15 const int iTableTimePilRobModB[RMB_NUM_TIME_PIL][2] = { { 6, 304}, {10, 331}, {11, 108}, {14, 620}, {17, 192}, {18, 704}, {27, 44}, {28, 432}, {30, 588}, {33, 844}, {34, 651}, {38, 651}, {40, 651}, {41, 460}, {44, 944}, }; #define RME_NUM_TIME_PIL 8 const int iTableTimePilRobModE[RME_NUM_TIME_PIL][2] = { { 7, 432}, { 8, 331}, {13, 108}, {14, 620}, {21, 192}, {22, 704}, {26, 44}, {27, 304}, }; /* Scattered pilots ***********************************************************/ /* Definitions for the positions of scattered pilots */ #define RMA_SCAT_PIL_FREQ_INT 4 #define RMA_SCAT_PIL_TIME_INT 5 #define RMB_SCAT_PIL_FREQ_INT 2 #define RMB_SCAT_PIL_TIME_INT 3 #define RME_SCAT_PIL_FREQ_INT 1 #define RME_SCAT_PIL_TIME_INT 4 /* Phase definitions of scattered pilots ------------------------------------ */ const int iTableScatPilConstRobModA[3] = {4, 5, 2}; const int iTableScatPilConstRobModB[3] = {2, 3, 1}; const int iTableScatPilConstRobModE[3] = {1, 4, 1}; #define SIZE_ROW_WZ_ROB_MOD_A 5 #define SIZE_COL_WZ_ROB_MOD_A 3 const int iScatPilWRobModA[SIZE_ROW_WZ_ROB_MOD_A][SIZE_COL_WZ_ROB_MOD_A] = { {228, 341, 455}, {455, 569, 683}, {683, 796, 910}, {910, 0, 114}, {114, 228, 341} }; const int iScatPilZRobModA[SIZE_ROW_WZ_ROB_MOD_A][SIZE_COL_WZ_ROB_MOD_A] = { {0, 81, 248}, {18, 106, 106}, {122, 116, 31}, {129, 129, 39}, {33, 32, 111} }; const int iScatPilQRobModA = 36; #define SIZE_ROW_WZ_ROB_MOD_B 3 #define SIZE_COL_WZ_ROB_MOD_B 5 const int iScatPilWRobModB[SIZE_ROW_WZ_ROB_MOD_B][SIZE_COL_WZ_ROB_MOD_B] = { {512, 0, 512, 0, 512}, {0, 512, 0, 512, 0}, {512, 0, 512, 0, 512} }; const int iScatPilZRobModB[SIZE_ROW_WZ_ROB_MOD_B][SIZE_COL_WZ_ROB_MOD_B] = { {0, 57, 164, 64, 12}, {168, 255, 161, 106, 118}, {25, 232, 132, 233, 38} }; const int iScatPilQRobModB = 12; #define SIZE_ROW_WZ_ROB_MOD_E 4 #define SIZE_COL_WZ_ROB_MOD_E 5 const int iScatPilWRobModE[SIZE_ROW_WZ_ROB_MOD_E][SIZE_COL_WZ_ROB_MOD_E] = { {512, 0, 512, 0, 512}, {0, 512, 0, 512, 0}, {512, 0, 512, 0, 512}, {0, 512, 0, 512, 0} }; const int iScatPilZRobModE[SIZE_ROW_WZ_ROB_MOD_E][SIZE_COL_WZ_ROB_MOD_E] = { {0, 57, 164, 64, 12}, {168, 255, 161, 106, 118}, {25, 232, 132, 233, 38}, {168, 255, 161, 106, 118} }; const int iScatPilQRobModE = 10; /* Gain definitions of scattered pilots ------------------------------------- */ #define NUM_BOOSTED_SCAT_PILOTS 4 const int iScatPilGainRobModA[2][NUM_BOOSTED_SCAT_PILOTS] = { {2, 4, 50, 54}, {2, 6, 54, 58} }; const int iScatPilGainRobModB[2][NUM_BOOSTED_SCAT_PILOTS] = { {1, 3, 43, 45}, {1, 3, 49, 51} }; /* Dummy cells for the MSC ****************************************************/ /* Already normalized */ const _COMPLEX cDummyCells64QAM[2] = { _COMPLEX(0.1543033499f, 0.1543033499f), _COMPLEX(0.1543033499f, -0.1543033499f) }; const _COMPLEX cDummyCells16QAM[2] = { _COMPLEX(0.3162277660f, 0.3162277660f), _COMPLEX(0.3162277660f, -0.3162277660f) }; const int iScatPilGainRobModE[2][NUM_BOOSTED_SCAT_PILOTS] = { {1,29, 0, 0}, {1,31, 0, 0} }; #endif // !defined(TABLE_CAR_MAP_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableCarrier.h000664 001750 001750 00000004670 12440612574 022572 0ustar00jomajoma000000 000000 /* Definitions ****************************************************************/ /* FAC ************************************************************************/ #define NUM_FAC_CELLS 45 /* FAC positions. The two numbers are {symbol no, carrier no} */ const int iTableFACRobModA[NUM_FAC_CELLS][2] = { { 1, 10}, { 1, 22}, { 1, 30}, { 1, 50}, { 2, 14}, { 2, 26}, { 2, 34}, { 3, 18}, { 3, 30}, { 3, 38}, { 4, 22}, { 4, 34}, { 4, 42}, { 5, 18}, { 5, 26}, { 5, 38}, { 5, 46}, { 6, 22}, { 6, 30}, { 6, 42}, { 6, 50}, { 7, 26}, { 7, 34}, { 7, 46}, { 8, 10}, { 8, 30}, { 8, 38}, { 8, 50}, { 9, 14}, { 9, 34}, { 9, 42}, {10, 18}, {10, 38}, {10, 46}, {11, 10}, {11, 22}, {11, 42}, {11, 50}, {12, 14}, {12, 26}, {12, 46}, {13, 18}, {13, 30}, {14, 22}, {14, 34}, }; const int iTableFACRobModB[NUM_FAC_CELLS][2] = { { 0, 21}, { 1, 11}, { 1, 23}, { 1, 35}, { 2, 13}, { 2, 25}, { 2, 37}, { 3, 15}, { 3, 27}, { 3, 39}, { 4, 5}, { 4, 17}, { 4, 29}, { 4, 41}, { 5, 7}, { 5, 19}, { 5, 31}, { 6, 9}, { 6, 21}, { 6, 33}, { 7, 11}, { 7, 23}, { 7, 35}, { 8, 13}, { 8, 25}, { 8, 37}, { 9, 15}, { 9, 27}, { 9, 39}, {10, 5}, {10, 17}, {10, 29}, {10, 41}, {11, 7}, {11, 19}, {11, 31}, {12, 9}, {12, 21}, {12, 33}, {13, 11}, {13, 23}, {13, 35}, {14, 13}, {14, 25}, {14, 37}, }; const int iTableFACRobModE[NUM_FAC_CELLS][2] = { { 1, 7}, { 1,23}, { 2, 8}, { 2,16}, { 2,24}, { 3, 9}, { 3,17}, { 4,10}, { 4,18}, { 5,11}, { 5,19}, { 6, 4}, { 6,12}, { 7,13}, { 7,21}, { 8, 6}, { 8,14}, { 8,22}, { 9, 7}, { 9,23}, {10, 8}, {10,16}, {10,24}, {11, 9}, {11,13}, {11,17}, {12,10}, {12,18}, {13,11}, {13,19}, {14, 4}, {14,12}, {14,16}, {15,13}, {15,21}, {16, 6}, {16,14}, {16,22}, {17, 7}, {17,23}, {18, 8}, {18,16}, {18,24}, {19, 9}, {19,17}, }; /* Frequency pilots ***********************************************************/ #define NUM_FREQ_PILOTS 3 const int iTableFreqPilRobModA[NUM_FREQ_PILOTS][2] = { { 9, 205}, {27, 836}, {36, 215} }; const int iTableFreqPilRobModB[NUM_FREQ_PILOTS][2] = { { 8, 331}, {24, 651}, {32, 555} }; const int iTableFreqPilRobModE[NUM_FREQ_PILOTS][2] = { { 5, 788}, {15, 1014}, {20, 332} }; /* Spectrum occupancy, carrier numbers for each mode **************************/ const int iTableCarrierKmin[2][3] = { {2, 1, 1}, {2, 1, 1} }; const int iTableCarrierKmax[2][3] = { {54, 45, 29}, {58, 51, 31} }; qsstv_8.2.12/qsstv/drmtx/common/tables/TableDRMGlobal.h000664 001750 001750 00000006530 12440612574 022743 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBo * * Description: * DRM global definitions * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(TABLE_DRM_GLOB_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) #define TABLE_DRM_GLOB_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_ /* Definitions ****************************************************************/ /* We define a "virtual" intermedia frequency for the DC carrier in the range of the FFT-size. This IF is independent of the "real" IF defined by the frequency estimation acquisition unit. Here, we are constrained to certain numbers to get continuous signals like they are defined in the DRM-standard, i.e. the frequency pilots which have to be continuous. Our IF must be a multiple of 1500 Hz and must also be chosen so that the largest mode (20 kHz) must fit into the range of the FFT-size. Therefore 6000 Hz was chosen */ #define VIRTUAL_INTERMED_FREQ 6000 // Hz #define SOUNDCRD_SAMPLE_RATE 48000 // Hz pa0mbo was 48000 #define AUD_DEC_TRANSFORM_LENGTH 960 /* DRM parameters */ #define NUM_FRAMES_IN_SUPERFRAME 3 #define RMA_FFT_SIZE_N 1152 // RMB: Robustness Mode A #define RMA_NUM_SYM_PER_FRAME 15 #define RMA_ENUM_TG_TU 1 #define RMA_DENOM_TG_TU 9 #define RMB_FFT_SIZE_N 1024 // RMA: Robustness Mode B #define RMB_NUM_SYM_PER_FRAME 15 #define RMB_ENUM_TG_TU 1 #define RMB_DENOM_TG_TU 4 #define RME_FFT_SIZE_N 640 // RME: Robustness Mode E #define RME_NUM_SYM_PER_FRAME 20 #define RME_ENUM_TG_TU 1 #define RME_DENOM_TG_TU 2 #define MAX_NUM_STREAMS 4 #define MAX_NUM_SERVICES 4 #define NUM_ROBUSTNESS_MODES 3 /* Service ID has 24 bits, define a number which cannot be an ID and fits into the 32 bits of the length of the variable (e.g.: 1 << 25) */ #define SERV_ID_NOT_USED (1 << 25) /* Define a stream ID which is not valid to show that this service is not attached to a stream */ #define STREAM_ID_NOT_USED (MAX_NUM_STREAMS + 1) /* Audio stream definitions ------------------------------------------------- */ /* The text message (when present) shall occupy the last four bytes of the lower protected part of each logical frame carrying an audio stream (6.5.1) */ #define NUM_BYTES_TEXT_MESS_IN_AUD_STR 4 #endif // !defined(TABLE_DRM_GLOB_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableFAC.cpp000664 001750 001750 00000064100 12440612574 022121 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Tables for FAC * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "TableFAC.h" /* Definitions ****************************************************************/ /* ETSI ES201980V2.1.1: page 115, 7.5.3: ...FAC shall use 4-QAM mapping. A fixed code rate shall be applied...R_all=0.6... 6 tailbits are used for the encoder to get in zero state -> 65 [number of cells] * 2 [4-QAM] * 0.6 [code-rate] - 6 [tailbits] = 72 */ // #define NUM_FAC_BITS_PER_BLOCK 72 /* iTableNumOfServices[a][b] a: Number of audio services b: Number of data services (6.3.4) */ const int iTableNumOfServices[5][5] = { /* -> Data */ {-1, 1, 2, 3, 15}, { 4, 5, 6, 7, -1}, { 8, 9, 10, -1, -1}, {12, 13, -1, -1, -1}, { 0, -1, -1, -1, -1} }; /* Language code */ #define LEN_TABLE_LANGUAGE_CODE 16 const string strTableLanguageCode[LEN_TABLE_LANGUAGE_CODE] = { "No language specified", "Arabic", "Bengali", "Chinese (Mandarin)", "Dutch", "English", "French", "German", "Hindi", "Japanese", "Javanese", "Korean", "Portuguese", "Russian", "Spanish", "Other language" }; /* Programme Type codes */ #define LEN_TABLE_PROG_TYPE_CODE_TOT 32 #define LEN_TABLE_PROG_TYPE_CODE 30 const string strTableProgTypCod[LEN_TABLE_PROG_TYPE_CODE_TOT] = { "No programme type", "News", "Current Affairs", "Information", "Sport", "Education", "Drama", "Culture", "Science", "Varied", "Pop Music", "Rock Music", "Easy Listening Music", "Light Classical", "Serious Classical", "Other Music", "Weather/meteorology", "Finance/Business", "Children's programmes", "Social Affairs", "Religion", "Phone In", "Travel", "Leisure", "Jazz Music", "Country Music", "National Music", "Oldies Music", "Folk Music", "Documentary", "Not used", "Not used" }; /* Country code table according to ISO 3166 */ const struct elCountry TableCountryCode[LEN_TABLE_COUNTRY_CODE] = { {"af", "Afghanistan"}, {"ax", "Aland Islands"}, {"al", "Albania"}, {"dz", "Algeria"}, {"as", "American Samoa"}, {"ad", "Andorra"}, {"ao", "Angola"}, {"ai", "Anguilla"}, {"aq", "Antarctica"}, {"ag", "Antigua and barbuda"}, {"ar", "Argentina"}, {"am", "Armenia"}, {"aw", "Aruba"}, {"au", "Australia"}, {"at", "Austria"}, {"az", "Azerbaijan"}, {"bs", "Bahamas"}, {"bh", "Bahrain"}, {"bd", "Bangladesh"}, {"bb", "Barbados"}, {"by", "Belarus"}, {"be", "Belgium"}, {"bz", "Belize"}, {"bj", "Benin"}, {"bm", "Bermuda"}, {"bt", "Bhutan"}, {"bo", "Bolivia"}, {"ba", "Bosnia and Herzegovina"}, {"bw", "Botswana"}, {"bv", "Bouvet Island"}, {"br", "Brazil"}, {"io", "British Indian Ocean Ter."}, {"bn", "Brunei Darussalam"}, {"bg", "Bulgaria"}, {"bf", "Burkina Faso"}, {"bi", "Burundi"}, {"kh", "Cambodia"}, {"cm", "Cameroon"}, {"ca", "Canada"}, {"cv", "Cape Verde"}, {"ky", "Cayman Islands"}, {"cf", "Central African Republic"}, {"td", "Chad"}, {"cl", "Chile"}, {"cn", "China"}, {"cx", "Christmas Island"}, {"cc", "Cocos (Keeling) Islands"}, {"co", "Colombia"}, {"km", "Comoros"}, {"cg", "Congo Democratic Rep."}, {"cd", "Congo"}, {"ck", "Cook Islands"}, {"cr", "Costa Rica"}, {"ci", "Côte d'Ivoire"}, {"hr", "Croatia"}, {"cu", "Cuba"}, {"cy", "Cyprus"}, {"cz", "Czech Republic"}, {"dk", "Denmark"}, {"dj", "Djibouti"}, {"dm", "Dominica"}, {"do", "Dominican Republic"}, {"ec", "Ecuador"}, {"eg", "Egypt"}, {"sv", "El Salvador"}, {"gq", "Equatorial Guinea"}, {"er", "Eritrea"}, {"ee", "Estonia"}, {"et", "Ethiopia"}, {"fk", "Falkland Islands"}, {"fo", "Faroe Islands"}, {"fj", "Fiji"}, {"fi", "Finland"}, {"fr", "France"}, {"gf", "French Guiana"}, {"pf", "French Polynesia"}, {"tf", "French Southern Ter."}, {"ga", "Gabon"}, {"gm", "Gambia"}, {"ge", "Georgia"}, {"de", "Germany"}, {"gh", "Ghana"}, {"gi", "Gibraltar"}, {"gr", "Greece"}, {"gl", "Greenland"}, {"gd", "Grenada"}, {"gp", "Guadeloupe"}, {"gu", "Guam"}, {"gt", "Guatemala"}, {"gg", "Guernsey"}, {"gn", "Guinea"}, {"gw", "Guinea-Bissau"}, {"gy", "Guyana"}, {"ht", "Haiti"}, {"hm", "Heard Is. Mcdonald Is."}, {"va", "Vatican City State"}, {"hn", "Honduras"}, {"hk", "Hong Kong"}, {"hu", "Hungary"}, {"is", "Iceland"}, {"in", "India"}, {"id", "Indonesia"}, {"ir", "Iran"}, {"iq", "Iraq"}, {"im", "Isle of Man"}, {"ie", "Ireland"}, {"il", "Israel"}, {"it", "Italy"}, {"jm", "Jamaica"}, {"jp", "Japan"}, {"je", "Jersey"}, {"jo", "Jordan"}, {"kz", "Kazakhstan"}, {"ke", "Kenya"}, {"ki", "Kiribati"}, {"kp", "Korea Democratic Rep."}, {"kr", "Korea, Republic of"}, {"kw", "Kuwait"}, {"kg", "Kyrgyzstan"}, {"la", "Lao People's Democratic Rep."}, {"lv", "Latvia"}, {"lb", "Lebanon"}, {"ls", "Lesotho"}, {"lr", "Liberia"}, {"ly", "Libyan Arab Jamahiriya"}, {"li", "Liechtenstein"}, {"lt", "Lithuania"}, {"lu", "Luxembourg"}, {"mo", "Macao"}, {"mk", "Macedonia"}, {"mg", "Madagascar"}, {"mw", "Malawi"}, {"my", "Malaysia"}, {"mv", "Maldives"}, {"ml", "Mali"}, {"mt", "Malta"}, {"mh", "Marshall Islands"}, {"mq", "Martinique"}, {"mr", "Mauritania"}, {"mu", "Mauritius"}, {"yt", "Mayotte"}, {"mx", "Mexico"}, {"fm", "Micronesia"}, {"md", "Moldova"}, {"mc", "Monaco"}, {"mn", "Mongolia"}, {"me", "Montenegro"}, {"ms", "Montserrat"}, {"ma", "Morocco"}, {"mz", "Mozambique"}, {"mm", "Myanmar"}, {"na", "Namibia"}, {"nr", "Nauru"}, {"np", "Nepal"}, {"nl", "Netherlands"}, {"an", "Netherlands Antilles"}, {"nc", "New Caledonia"}, {"nz", "New Zealand"}, {"ni", "Nicaragua"}, {"ne", "Niger"}, {"ng", "Nigeria"}, {"nu", "Niue"}, {"nf", "Norfolk Island"}, {"mp", "Northern Mariana Is."}, {"no", "Norway"}, {"om", "Oman"}, {"pk", "Pakistan"}, {"pw", "Palau"}, {"ps", "Palestinian Territory"}, {"pa", "Panama"}, {"pg", "Papua New Guinea"}, {"py", "Paraguay"}, {"pe", "Peru"}, {"ph", "Philippines"}, {"pn", "Pitcairn"}, {"pl", "Poland"}, {"pt", "Portugal"}, {"pr", "Puerto Rico"}, {"qa", "Qatar"}, {"re", "Réunion"}, {"ro", "Romania"}, {"ru", "Russian Federation"}, {"rw", "Rwanda"}, {"sh", "Saint Helena"}, {"kn", "Saint Kitts and Nevis"}, {"lc", "Saint Lucia"}, {"pm", "Saint Pierre and Miquelon"}, {"vc", "Saint Vincent and the Grenadines"}, {"ws", "Samoa"}, {"sm", "San Marino"}, {"st", "Sao Tome and Principe"}, {"sa", "Saudi arabia"}, {"sn", "Senegal"}, {"rs", "Serbia"}, {"sc", "Seychelles"}, {"sl", "Sierra Leone"}, {"sg", "Singapore"}, {"sk", "Slovakia"}, {"si", "Slovenia"}, {"sb", "Solomon Islands"}, {"so", "Somalia"}, {"za", "South Africa"}, {"gs", "South Georgia South Sandwich Is."}, {"es", "Spain"}, {"lk", "Sri Lanka"}, {"sd", "Sudan"}, {"sr", "Suriname"}, {"sj", "Svalbard and Jan Mayen"}, {"sz", "Swaziland"}, {"se", "Sweden"}, {"ch", "Switzerland"}, {"sy", "Syrian Arab Republic"}, {"tw", "Taiwan"}, {"tj", "Tajikistan"}, {"tz", "Tanzania"}, {"th", "Thailand"}, {"tl", "Timor-Leste"}, {"tg", "Togo"}, {"tk", "Tokelau"}, {"to", "Tonga"}, {"tt", "Trinidad and Tobago"}, {"tn", "Tunisia"}, {"tr", "Turkey"}, {"tm", "Turkmenistan"}, {"tc", "Turks and Caicos Islands"}, {"tv", "Tuvalu"}, {"ug", "Uganda"}, {"ua", "Ukraine"}, {"ae", "United Arab Emirates"}, {"gb", "United Kingdom"}, {"us", "United States"}, {"um", "United States Is."}, {"uy", "Uruguay"}, {"uz", "Uzbekistan"}, {"vu", "Vanuatu"}, {"ve", "Venezuela"}, {"vn", "Vietnam"}, {"vg", "Virgin Islands, British"}, {"vi", "Virgin Islands, U.S."}, {"wf", "Wallis and Futuna"}, {"eh", "Western Sahara"}, {"ye", "Yemen"}, {"zm", "Zambia"}, {"zw", "Zimbabwe"} }; /* Get country name from ISO 3166 A2 */ string GetISOCountryName(const string strA2) { for (int i = 0; i < LEN_TABLE_COUNTRY_CODE; i++) { if (!strA2.compare(TableCountryCode[i].strcode)) return TableCountryCode[i].strDesc; } return ""; } /* Language code table according to ISO 639-2 */ /* All Alpha 3 codes: "bibliographic" (B code) and "terminological" (T code) */ const struct elLanguage TableISOLanguageCode[LEN_TABLE_ISO_LANGUAGE_CODE] = { {"aar", "Afar"}, {"abk", "Abkhazian"}, {"ace", "Achinese"}, {"ach", "Acoli"}, {"ada", "Adangme"}, {"ady", "Adyghe; Adygei"}, {"afa", "Afro-Asiatic (Other)"}, {"afh", "Afrihili"}, {"afr", "Afrikaans"}, {"ain", "Ainu"}, {"aka", "Akan"}, {"akk", "Akkadian"}, {"alb", "Albanian"}, {"sqi", "Albanian"}, {"ale", "Aleut"}, {"alg", "Algonquian languages"}, {"alt", "Southern Altai"}, {"amh", "Amharic"}, {"ang", "English, Old (ca.450-1100)"}, {"anp", "Angika"}, {"apa", "Apache languages"}, {"ara", "Arabic"}, {"arc", "Aramaic"}, {"arg", "Aragonese"}, {"arm", "Armenian"}, {"hye", "Armenian"}, {"arn", "Araucanian"}, {"arp", "Arapaho"}, {"art", "Artificial (Other)"}, {"arw", "Arawak"}, {"asm", "Assamese"}, {"ast", "Asturian; Bable"}, {"ath", "Athapascan languages"}, {"aus", "Australian languages"}, {"ava", "Avaric"}, {"ave", "Avestan"}, {"awa", "Awadhi"}, {"aym", "Aymara"}, {"aze", "Azerbaijani"}, {"bad", "Banda"}, {"bai", "Bamileke languages"}, {"bak", "Bashkir"}, {"bal", "Baluchi"}, {"bam", "Bambara"}, {"ban", "Balinese"}, {"baq", "Basque"}, {"eus", "Basque"}, {"bas", "Basa"}, {"bat", "Baltic (Other)"}, {"bej", "Beja"}, {"bel", "Belarusian"}, {"bem", "Bemba"}, {"ben", "Bengali"}, {"ber", "Berber (Other)"}, {"bho", "Bhojpuri"}, {"bih", "Bihari"}, {"bik", "Bikol"}, {"bin", "Bini"}, {"bis", "Bislama"}, {"bla", "Siksika"}, {"bnt", "Bantu (Other)"}, {"bos", "Bosnian"}, {"bra", "Braj"}, {"bre", "Breton"}, {"btk", "Batak (Indonesia)"}, {"bua", "Buriat"}, {"bug", "Buginese"}, {"bul", "Bulgarian"}, {"bur", "Burmese"}, {"mya", "Burmese"}, {"byn", "Blin; Bilin"}, {"cad", "Caddo"}, {"cai", "Central American Indian (Other)"}, {"car", "Carib"}, {"cat", "Catalan; Valencian"}, {"cau", "Caucasian (Other)"}, {"ceb", "Cebuano"}, {"cel", "Celtic (Other)"}, {"cha", "Chamorro"}, {"chb", "Chibcha"}, {"che", "Chechen"}, {"chg", "Chagatai"}, {"chi", "Chinese"}, {"zho", "Chinese"}, {"chk", "Chuukese"}, {"chm", "Mari"}, {"chn", "Chinook jargon"}, {"cho", "Choctaw"}, {"chp", "Chipewyan"}, {"chr", "Cherokee"}, {"chu", "Church Slavic - Slavonic..."}, {"chv", "Chuvash"}, {"chy", "Cheyenne"}, {"cmc", "Chamic languages"}, {"cop", "Coptic"}, {"cor", "Cornish"}, {"cos", "Corsican"}, {"cpe", "Creoles and pidgins, English based"}, {"cpf", "Creoles and pidgins, French-based"}, {"cpp", "Creoles and pidgins, Portuguese-based"}, {"cre", "Cree"}, {"crh", "Crimean Tatar; Crimean Turkish"}, {"crp", "Creoles and pidgins (Other)"}, {"csb", "Kashubian"}, {"cus", "Cushitic (Other)"}, {"cze", "Czech"}, {"ces", "Czech"}, {"dak", "Dakota"}, {"dan", "Danish"}, {"dar", "Dargwa"}, {"day", "Dayak"}, {"del", "Delaware"}, {"den", "Slave (Athapascan)"}, {"dgr", "Dogrib"}, {"din", "Dinka"}, {"div", "Divehi; Dhivehi; Maldivian"}, {"doi", "Dogri"}, {"dra", "Dravidian (Other)"}, {"dsb", "Lower Sorbian"}, {"dua", "Duala"}, {"dum", "Dutch, Middle (ca.1050-1350)"}, {"dut", "Dutch; Flemish"}, {"nld", "Dutch; Flemish"}, {"dyu", "Dyula"}, {"dzo", "Dzongkha"}, {"efi", "Efik"}, {"egy", "Egyptian (Ancient)"}, {"eka", "Ekajuk"}, {"elx", "Elamite"}, {"eng", "English"}, {"enm", "English, Middle (1100-1500)"}, {"epo", "Esperanto"}, {"est", "Estonian"}, {"ewe", "Ewe"}, {"ewo", "Ewondo"}, {"fan", "Fang"}, {"fao", "Faroese"}, {"fat", "Fanti"}, {"fij", "Fijian"}, {"fil", "Filipino; Pilipino"}, {"fin", "Finnish"}, {"fiu", "Finno-Ugrian (Other)"}, {"fon", "Fon"}, {"fre", "French"}, {"fra", "French"}, {"frm", "French, Middle (ca.1400-1600)"}, {"fro", "French, Old (842-ca.1400)"}, {"frr", "Northern Frisian"}, {"frs", "Eastern Frisian"}, {"fry", "Western Frisian"}, {"ful", "Fulah"}, {"fur", "Friulian"}, {"gaa", "Ga"}, {"gay", "Gayo"}, {"gba", "Gbaya"}, {"gem", "Germanic (Other)"}, {"geo", "Georgian"}, {"kat", "Georgian"}, {"ger", "German"}, {"deu", "German"}, {"gez", "Geez"}, {"gil", "Gilbertese"}, {"gla", "Gaelic; Scottish Gaelic"}, {"gle", "Irish"}, {"glg", "Galician"}, {"glv", "Manx"}, {"gmh", "German, Middle High (ca.1050-1500)"}, {"goh", "German, Old High (ca.750-1050)"}, {"gon", "Gondi"}, {"gor", "Gorontalo"}, {"got", "Gothic"}, {"grb", "Grebo"}, {"grc", "Greek, Ancient (to 1453)"}, {"gre", "Greek, Modern (1453-)"}, {"ell", "Greek, Modern (1453-)"}, {"grn", "Guarani"}, {"gsw", "Alemani; Swiss German"}, {"guj", "Gujarati"}, {"gwi", "Gwich´in"}, {"hai", "Haida"}, {"hat", "Haitian; Haitian Creole"}, {"hau", "Hausa"}, {"haw", "Hawaiian"}, {"heb", "Hebrew"}, {"her", "Herero"}, {"hil", "Hiligaynon"}, {"him", "Himachali"}, {"hin", "Hindi"}, {"hit", "Hittite"}, {"hmn", "Hmong"}, {"hmo", "Hiri Motu"}, {"hsb", "Upper Sorbian"}, {"hun", "Hungarian"}, {"hup", "Hupa"}, {"iba", "Iban"}, {"ibo", "Igbo"}, {"ice", "Icelandic"}, {"isl", "Icelandic"}, {"ido", "Ido"}, {"iii", "Sichuan Yi"}, {"ijo", "Ijo"}, {"iku", "Inuktitut"}, {"ile", "Interlingue"}, {"ilo", "Iloko"}, {"ina", "Interlingua"}, {"inc", "Indic (Other)"}, {"ind", "Indonesian"}, {"ine", "Indo-European (Other)"}, {"inh", "Ingush"}, {"ipk", "Inupiaq"}, {"ira", "Iranian (Other)"}, {"iro", "Iroquoian languages"}, {"ita", "Italian"}, {"jav", "Javanese"}, {"jbo", "Lojban"}, {"jpn", "Japanese"}, {"jpr", "Judeo-Persian"}, {"jrb", "Judeo-Arabic"}, {"kaa", "Kara-Kalpak"}, {"kab", "Kabyle"}, {"kac", "Kachin"}, {"kal", "Kalaallisut; Greenlandic"}, {"kam", "Kamba"}, {"kan", "Kannada"}, {"kar", "Karen"}, {"kas", "Kashmiri"}, {"kau", "Kanuri"}, {"kaw", "Kawi"}, {"kaz", "Kazakh"}, {"kbd", "Kabardian"}, {"kha", "Khasi"}, {"khi", "Khoisan (Other)"}, {"khm", "Khmer"}, {"kho", "Khotanese"}, {"kik", "Kikuyu; Gikuyu"}, {"kin", "Kinyarwanda"}, {"kir", "Kirghiz"}, {"kmb", "Kimbundu"}, {"kok", "Konkani"}, {"kom", "Komi"}, {"kon", "Kongo"}, {"kor", "Korean"}, {"kos", "Kosraean"}, {"kpe", "Kpelle"}, {"krc", "Karachay-Balkar"}, {"krl", "Karelian"}, {"kro", "Kru"}, {"kru", "Kurukh"}, {"kua", "Kuanyama; Kwanyama"}, {"kum", "Kumyk"}, {"kur", "Kurdish"}, {"kut", "Kutenai"}, {"lad", "Ladino"}, {"lah", "Lahnda"}, {"lam", "Lamba"}, {"lao", "Lao"}, {"lat", "Latin"}, {"lav", "Latvian"}, {"lez", "Lezghian"}, {"lim", "Limburgan; Limburger; Limburgish"}, {"lin", "Lingala"}, {"lit", "Lithuanian"}, {"lol", "Mongo"}, {"loz", "Lozi"}, {"ltz", "Luxembourgish; Letzeburgesch"}, {"lua", "Luba-Lulua"}, {"lub", "Luba-Katanga"}, {"lug", "Ganda"}, {"lui", "Luiseno"}, {"lun", "Lunda"}, {"luo", "Luo (Kenya and Tanzania)"}, {"lus", "lushai"}, {"mac", "Macedonian"}, {"mkd", "Macedonian"}, {"mad", "Madurese"}, {"mag", "Magahi"}, {"mah", "Marshallese"}, {"mai", "Maithili"}, {"mak", "Makasar"}, {"mal", "Malayalam"}, {"man", "Mandingo"}, {"mao", "Maori"}, {"mri", "Maori"}, {"map", "Austronesian (Other)"}, {"mar", "Marathi"}, {"mas", "Masai"}, {"may", "Malay"}, {"msa", "Malay"}, {"mdf", "Moksha"}, {"mdr", "Mandar"}, {"men", "Mende"}, {"mga", "Irish, Middle (900-1200)"}, {"mic", "Mi'kmaq; Micmac"}, {"min", "Minangkabau"}, {"mis", "Miscellaneous languages"}, {"mkh", "Mon-Khmer (Other)"}, {"mlg", "Malagasy"}, {"mlt", "Maltese"}, {"mnc", "Manchu"}, {"mni", "Manipuri"}, {"mno", "Manobo languages"}, {"moh", "Mohawk"}, {"mol", "Moldavian"}, {"mon", "Mongolian"}, {"mos", "Mossi"}, {"mul", "Multiple languages"}, {"mun", "Munda languages"}, {"mus", "Creek"}, {"mwl", "Mirandese"}, {"mwr", "Marwari"}, {"myn", "Mayan languages"}, {"myv", "Erzya"}, {"nah", "Nahuatl"}, {"nai", "North American Indian"}, {"nap", "Neapolitan"}, {"nau", "Nauru"}, {"nav", "Navajo; Navaho"}, {"nbl", "Ndebele, South; South Ndebele"}, {"nde", "Ndebele, North; North Ndebele"}, {"ndo", "Ndonga"}, {"nds", "Low German; Low Saxon..."}, {"nep", "Nepali"}, {"new", "Nepal Bhasa; Newari"}, {"nia", "Nias"}, {"nic", "Niger-Kordofanian (Other)"}, {"niu", "Niuean"}, {"nno", "Norwegian Nynorsk"}, {"nob", "Norwegian Bokmål"}, {"nog", "Nogai"}, {"non", "Norse, Old"}, {"nor", "Norwegian"}, {"nqo", "N'ko"}, {"nso", "Northern Sotho; Pedi; Sepedi"}, {"nub", "Nubian languages"}, {"nwc", "Classical Newari; Classical Nepal Bhasa"}, {"nya", "Chichewa; Chewa; Nyanja"}, {"nym", "Nyamwezi"}, {"nyn", "Nyankole"}, {"nyo", "Nyoro"}, {"nzi", "Nzima"}, {"oci", "Occitan (post 1500); Provençal"}, {"oji", "Ojibwa"}, {"ori", "Oriya"}, {"orm", "Oromo"}, {"osa", "Osage"}, {"oss", "Ossetian; Ossetic"}, {"ota", "Turkish, Ottoman (1500-1928)"}, {"oto", "Otomian languages"}, {"paa", "Papuan (Other)"}, {"pag", "Pangasinan"}, {"pal", "Pahlavi"}, {"pam", "Pampanga"}, {"pan", "Panjabi; Punjabi"}, {"pap", "Papiamento"}, {"pau", "Palauan"}, {"peo", "Persian, Old (ca.600-400 B.C.)"}, {"per", "Persian"}, {"fas", "Persian"}, {"phi", "Philippine (Other)"}, {"phn", "Phoenician"}, {"pli", "Pali"}, {"pol", "Polish"}, {"pon", "Pohnpeian"}, {"por", "Portuguese"}, {"pra", "Prakrit languages"}, {"pro", "Provençal, Old (to 1500)"}, {"pus", "Pushto"}, {"que", "Quechua"}, {"raj", "Rajasthani"}, {"rap", "Rapanui"}, {"rar", "Rarotongan"}, {"roa", "Romance (Other)"}, {"roh", "Raeto-Romance"}, {"rom", "Romany"}, {"rum", "Romanian"}, {"ron", "Romanian"}, {"run", "Rundi"}, {"rup", "Aromanian; Arumanian; Macedo-Romanian"}, {"rus", "Russian"}, {"sad", "Sandawe"}, {"sag", "Sango"}, {"sah", "Yakut"}, {"sai", "South American Indian (Other)"}, {"sal", "Salishan languages"}, {"sam", "Samaritan Aramaic"}, {"san", "Sanskrit"}, {"sas", "Sasak"}, {"sat", "Santali"}, {"scc", "Serbian"}, {"srp", "Serbian"}, {"scn", "Sicilian"}, {"sco", "Scots"}, {"scr", "Croatian"}, {"hrv", "Croatian"}, {"sel", "Selkup"}, {"sem", "Semitic (Other)"}, {"sga", "Irish, Old (to 900)"}, {"sgn", "Sign Languages"}, {"shn", "Shan"}, {"sid", "Sidamo"}, {"sin", "Sinhala; Sinhalese"}, {"sio", "Siouan languages"}, {"sit", "Sino-Tibetan (Other)"}, {"sla", "Slavic (Other)"}, {"slo", "Slovak"}, {"slk", "Slovak"}, {"slv", "Slovenian"}, {"sma", "Southern Sami"}, {"sme", "Northern Sami"}, {"smi", "Sami languages (Other)"}, {"smj", "Lule Sami"}, {"smn", "Inari Sami"}, {"smo", "Samoan"}, {"sms", "Skolt Sami"}, {"sna", "Shona"}, {"snd", "Sindhi"}, {"snk", "Soninke"}, {"sog", "Sogdian"}, {"som", "Somali"}, {"son", "Songhai"}, {"sot", "Sotho, Southern"}, {"spa", "Spanish; Castilian"}, {"srd", "Sardinian"}, {"srn", "Sranan Togo"}, {"srr", "Serer"}, {"ssa", "Nilo-Saharan (Other)"}, {"ssw", "Swati"}, {"suk", "Sukuma"}, {"sun", "Sundanese"}, {"sus", "Susu"}, {"sux", "Sumerian"}, {"swa", "Swahili"}, {"swe", "Swedish"}, {"syr", "Syriac"}, {"tah", "Tahitian"}, {"tai", "Tai (Other)"}, {"tam", "Tamil"}, {"tat", "Tatar"}, {"tel", "Telugu"}, {"tem", "Timne"}, {"ter", "Tereno"}, {"tet", "Tetum"}, {"tgk", "Tajik"}, {"tgl", "Tagalog"}, {"tha", "Thai"}, {"tib", "Tibetan"}, {"bod", "Tibetan"}, {"tig", "Tigre"}, {"tir", "Tigrinya"}, {"tiv", "Tiv"}, {"tkl", "Tokelau"}, {"tlh", "Klingon; tlhIngan-Hol"}, {"tli", "Tlingit"}, {"tmh", "Tamashek"}, {"tog", "Tonga (Nyasa)"}, {"ton", "Tonga (Tonga Islands)"}, {"tpi", "Tok Pisin"}, {"tsi", "Tsimshian"}, {"tsn", "Tswana"}, {"tso", "Tsonga"}, {"tuk", "Turkmen"}, {"tum", "Tumbuka"}, {"tup", "Tupi languages"}, {"tur", "Turkish"}, {"tut", "Altaic (Other)"}, {"tvl", "Tuvalu"}, {"twi", "Twi"}, {"tyv", "Tuvinian"}, {"udm", "Udmurt"}, {"uga", "Ugaritic"}, {"uig", "Uighur; Uyghur"}, {"ukr", "Ukrainian"}, {"umb", "Umbundu"}, {"und", "Undetermined"}, {"urd", "Urdu"}, {"uzb", "Uzbek"}, {"vai", "Vai"}, {"ven", "Venda"}, {"vie", "Vietnamese"}, {"vol", "Volapük"}, {"vot", "Votic"}, {"wak", "Wakashan languages"}, {"wal", "Walamo"}, {"war", "Waray"}, {"was", "Washo"}, {"wel", "Welsh"}, {"cym", "Welsh"}, {"wen", "Sorbian languages"}, {"wln", "Walloon"}, {"wol", "Wolof"}, {"xal", "Kalmyk; Oirat"}, {"xho", "Xhosa"}, {"yao", "Yao"}, {"yap", "Yapese"}, {"yid", "Yiddish"}, {"yor", "Yoruba"}, {"ypk", "Yupik languages"}, {"zap", "Zapotec"}, {"zen", "Zenaga"}, {"zha", "Zhuang; Chuang"}, {"znd", "Zande"}, {"zul", "Zulu"}, {"zun", "Zuni"}, {"zxx", "No linguistic content"}, {"zza", "Zaza; Dimili; Dimli; Kirdki..."} }; /* Get language name from ISO */ string GetISOLanguageName(const string strA3) { for (int i = 0; i < LEN_TABLE_ISO_LANGUAGE_CODE; i++) { if (!strA3.compare(TableISOLanguageCode[i].strISOCode)) return TableISOLanguageCode[i].strDesc; } return ""; } /* CIRAF zones */ const string strTableCIRAFzones[LEN_TABLE_CIRAF_ZONES] = { "", /* 0 undefined */ "Alaska", /* 1 */ "west Canada", /* 2 */ "central Canada - west", /* 3 */ "central Canada - east, Baffin Island", /* 4 */ "Greenland", /* 5 */ "west USA", /* 6 */ "central USA", /* 7 */ "east USA", /* 8 */ "east Canada", /* 9 */ "Belize, Guatemala, Mexico", /* 10 */ "Caribbean, central America", /* 11 */ "northwestern south America", /* 12 */ "northeast Brazil", /* 13 */ "southwestern south America", /* 14 */ "southeast Brazil", /* 15 */ "south Argentina, south Chile, Falkland Islands", /* 16 */ "Iceland", /* 17 */ "Scandinavia", /* 18 */ "west Russia northwest", /* 19 */ "west Russia north", /* 20 */ "central Russia northwest", /* 21 */ "central Russia north", /* 22 */ "central Russia east", /* 23 */ "east Russia northwest", /* 24 */ "east Russia north", /* 25 */ "east Russia northeast", /* 26 */ "northwest Europe", /* 27 */ "central east south Europe", /* 28 */ "Baltics and west Russia", /* 29 */ "central Asia, west Russia southeast", /* 30 */ "central Russia southwest, east Kazakhstan, east Kyrgyzstan", /* 31 */ "central Russia south, west Mongolia", /* 32 */ "central Russia southeast, east Mongolia", /* 33 */ "east Russia southwest: Sakhalin, Sikhote Alin", /* 34 */ "east Russia east: Kamchatka", /* 35 */ "Azores, Canary Island, Madeira", /* 36 */ "southwest Europe, northwest Africa", /* 37 */ "Egypt, Libya", /* 38 */ "Middle East", /* 39 */ "Afghanistan, Iran", /* 40 */ "Bangladesh, Bhutan, India, Nepal, Pakistan", /* 41 */ "west China", /* 42 */ "central China", /* 43 */ "east China, Macao, Hong Kong, North Korea, South Korea, Taiwan", /* 44 */ "Japan", /* 45 */ "west Africa", /* 46 */ "west Sudan", /* 47 */ "Horn of Africa", /* 48 */ "Kampuchea, Laos, Myanmar, Vietnam", /* 49 */ "Philippines", /* 50 */ "Malaysia, Papua New Guinea, west Indonesia", /* 51 */ "Angola, Burundi, Congo, Gabon, Zaire", /* 52 */ "Madagascar, Malawi, Mozambique, Seychelles, Zambia, Zimbabwe", /* 53 */ "Malaysia, Singapore, west Indonesia", /* 54 */ "northeast Australia", /* 55 */ "Caledonia, Fiji/Vanuatu", /* 56 */ "Botswana, Lesotho, Namibia, Swaziland, South African Republic", /* 57 */ "west Australia", /* 58 */ "southeast Australia", /* 59 */ "New Zealand", /* 60 */ "Hawaii", /* 61 */ "Phoenix Islands, Samoa", /* 62 */ "Cook Islands, Polynesia", /* 63 */ "Guam/Palau, Saipan", /* 64 */ "Kiribati, Marshall", /* 65 */ "central Atlantic - south: Ascension, St. Helena", /* 66 */ "Antarctica", /* 67 */ "southwest Indian Ocean: Kerguelen", /* 68 */ "Antarctica", /* 69 */ "Antarctica", /* 70 */ "Antarctica", /* 71 */ "Antarctica", /* 72 */ "Antarctica", /* 73 */ "South Pole", /* 74 */ "North Pole", /* 75 */ "northeast Pacific", /* 76 */ "central Pacific - northeast", /* 77 */ "central Pacific - southeast", /* 78 */ "central Indian Ocean", /* 79 */ "northern Atlantic", /* 80 */ "central Atlantic", /* 81 */ "northwest Pacific", /* 82 */ "south Pacific", /* 83 */ "south Atlantic", /* 84 */ "southeast Indian Ocean" /* 85 */ }; qsstv_8.2.12/qsstv/drmtx/common/tables/TableFAC.h000664 001750 001750 00000006321 12440612574 021567 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Tables for FAC * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(TABLE_FAC_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_) #define TABLE_FAC_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_ #include #include "../GlobalDefinitions.h" /* Definitions ****************************************************************/ /* ETSI ES201980V2.1.1: page 115, 7.5.3: ...FAC shall use 4-QAM mapping. A fixed code rate shall be applied...R_all=0.6... 6 tailbits are used for the encoder to get in zero state -> 65 [number of cells] * 2 [4-QAM] * 0.6 [code-rate] - 6 [tailbits] = 72 */ #define NUM_FAC_BITS_PER_BLOCK 48 /* iTableNumOfServices[a][b] a: Number of audio services b: Number of data services (6.3.4) */ extern const int iTableNumOfServices[5][5]; /* Language code */ #define LEN_TABLE_LANGUAGE_CODE 16 extern const string strTableLanguageCode[LEN_TABLE_LANGUAGE_CODE]; /* Programme Type codes */ #define LEN_TABLE_PROG_TYPE_CODE_TOT 32 #define LEN_TABLE_PROG_TYPE_CODE 30 extern const string strTableProgTypCod[LEN_TABLE_PROG_TYPE_CODE_TOT]; /* Country code table according to ISO 3166 */ #define LEN_TABLE_COUNTRY_CODE 244 #define LEN_COUNTRY_CODE 2 #define MAX_LEN_DESC_COUNTRY_CODE 44 struct elCountry { char strcode [LEN_COUNTRY_CODE+1]; char strDesc [MAX_LEN_DESC_COUNTRY_CODE+1]; }; extern const struct elCountry TableCountryCode[LEN_TABLE_COUNTRY_CODE]; /* Get country name from ISO 3166 A2 */ string GetISOCountryName(const string strA2); /* Language code table according to ISO/IEC 639-2 */ #define LEN_TABLE_ISO_LANGUAGE_CODE 505 #define LEN_ISO_LANGUAGE_CODE 3 #define MAX_LEN_DESC_ISO_LANGUAGE_CODE 44 struct elLanguage { char strISOCode [LEN_ISO_LANGUAGE_CODE+1]; char strDesc [MAX_LEN_DESC_ISO_LANGUAGE_CODE+1]; }; extern const struct elLanguage TableISOLanguageCode[LEN_TABLE_ISO_LANGUAGE_CODE]; /* Get language name from ISO 3166 */ string GetISOLanguageName(const string strA3); /* CIRAF zones */ #define LEN_TABLE_CIRAF_ZONES 86 extern const string strTableCIRAFzones[LEN_TABLE_CIRAF_ZONES]; #endif // !defined(TABLE_FAC_H__3B0_CA63_4344_BGDEB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableMLC.h000664 001750 001750 00000021303 12440612574 021606 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Tables for MLC * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(_TABLE_MLC_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) #define _TABLE_MLC_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_ #include "../GlobalDefinitions.h" /* Definitions ****************************************************************/ /* Default number of iterations at application startup */ #define MC_NUM_ITERATIONS 1 /* Generator polynomials used for channel coding (octal form, defined by a leading "0"!). We must bit-reverse the octal-forms given in the standard since we shift bits from right to the left! */ /* In this implementation we shift bits from right to left, therefore the order of the code-words are: [..., b_(0, i), b_(1, i), b(2, i), b(3, i), ...] */ #define MC_NUM_OUTPUT_BITS_PER_STEP 4 /* MC: Multi-level Coder */ const _BYTE byGeneratorMatrix[MC_NUM_OUTPUT_BITS_PER_STEP] = { 0155, /* (133) x_{0, i} */ 0117, /* (171) x_{1, i} */ 0123, /* (145) x_{2, i} */ 0155 /* (133) x_{3, i} */ }; #define MC_CONSTRAINT_LENGTH 7 /* Since we have a periodical structure in the trellis it is enough to build one step. 2^(MC_CONSTRAINT_LENGTH - 1) states have to be considered. ("- 1": since one bit is the transition to the next state) */ #define MC_NUM_STATES (1 << (MC_CONSTRAINT_LENGTH - 1)) #define MC_NUM_OUTPUT_COMBINATIONS (1 << MC_NUM_OUTPUT_BITS_PER_STEP) /* Maximum number of levels (Its in case of HMmix) */ #define MC_MAX_NUM_LEVELS 6 /* Puncturing --------------------------------------------------------------- */ /* Only these types of patterns are used in DRM */ #define PP_TYPE_0000 0 /* not used, dummy */ #define PP_TYPE_1111 1 #define PP_TYPE_0111 2 #define PP_TYPE_0011 3 #define PP_TYPE_0001 4 #define PP_TYPE_0101 5 /* {a, b, c ...}: a = Number of groups, b = Number of "1"s, c = Patterns */ const uint32_t iPuncturingPatterns[13][10] = { /* B0: 1 B1: 1 B2: 1 B3: 1 */ {1, 4, PP_TYPE_1111, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 B1: 1 1 1 B2: 1 1 1 B3: 1 0 0 */ {3, 10, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 B1: 1 B2: 1 B3: 0 */ {1, 3, PP_TYPE_0111, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 1 B1: 1 1 1 1 B2: 1 1 1 0 B3: 0 0 0 0 */ {4, 11, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 B1: 1 B2: 0 B3: 0 */ {1, 2, PP_TYPE_0011, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 1 B1: 1 0 1 0 B2: 0 1 0 0 B3: 0 0 0 0 */ {4, 7, PP_TYPE_0011, PP_TYPE_0101, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 B1: 1 0 1 B2: 0 0 0 B3: 0 0 0 */ {3, 5, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0011, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 B1: 1 0 B2: 0 0 B3: 0 0 */ {2, 3, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 1 1 1 1 1 B1: 1 0 0 1 0 0 1 0 B2: 0 0 0 0 0 0 0 0 B3: 0 0 0 0 0 0 0 0 */ {8, 11, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0011, PP_TYPE_0001}, /* B0: 1 1 1 B1: 1 0 0 B2: 0 0 0 B3: 0 0 0 */ {3, 4, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 1 B1: 1 0 0 0 B2: 0 0 0 0 B3: 0 0 0 0 */ {4, 5, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000, PP_TYPE_0000}, /* B0: 1 1 1 1 1 1 1 B1: 1 0 0 0 0 0 0 B2: 0 0 0 0 0 0 0 B3: 0 0 0 0 0 0 0 */ {7, 8, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0000}, /* B0: 1 1 1 1 1 1 1 1 B1: 1 0 0 0 0 0 0 0 B2: 0 0 0 0 0 0 0 0 B3: 0 0 0 0 0 0 0 0 */ {8, 9, PP_TYPE_0011, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001, PP_TYPE_0001} }; /* Puncturing patterns for tailbits */ #define LENGTH_TAIL_BIT_PAT 6 const uint32_t iPunctPatTailbits[12][LENGTH_TAIL_BIT_PAT] = { /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 0 0 0 0 0 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 0 0 0 0 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 0 0 1 0 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0011, PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 0 1 0 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 0 1 1 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0011, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 0 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0011}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 0 0 0 0 0 0 */ {PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 1 0 0 0 0 0 */ {PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_0111}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 1 0 0 1 0 0 */ {PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_0111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_0111}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 1 1 0 1 0 0 */ {PP_TYPE_1111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_0111}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 1 1 0 1 0 1 */ {PP_TYPE_1111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_1111}, /* B0: 1 1 1 1 1 1 B1: 1 1 1 1 1 1 B2: 1 1 1 1 1 1 B3: 1 1 1 1 0 1 */ {PP_TYPE_1111, PP_TYPE_1111, PP_TYPE_1111, PP_TYPE_1111, PP_TYPE_0111, PP_TYPE_1111}, }; /* Code rate combinations --------------------------------------------------- */ /* row-index: protection level */ /* {a, b, c}: a = R_0, b = R_1, c = RY_Icm */ /* {a}: a = R_0 */ const int iCodRateCombMSC4SM = { 6 }; const int iCodRateCombMSC16SM[2][3] = { {2, 7, 3}, {4, 9, 4} }; /* {a, b, c, d}: a = R_0, b = R_1, c = R_2, d = RY_Icm */ const int iCodRateCombMSC64SM[4][4] = { {0, 4, 9, 4}, {2, 7, 10, 15}, {4, 9, 11, 8}, {7, 10, 12, 45} }; /* {a}: a = R_0 */ const int iCodRateCombFDC4SM = { 6 }; /* Interleaver sequence ----------------------------------------------------- */ /* The different coding modes in DRM use bit-interleavers in certain paths. We define the following vectors to store the position and type of the interleaver as described in the DRM-standard Interleaver modules have to be initialized in the way: [0]: t_0 = 13; [1]: t_0 = 21; "-1": no interleaver in this level */ const int iInterlSequ4SM[MC_MAX_NUM_LEVELS] = { 1, -1, -1, -1, -1, -1}; const int iInterlSequ16SM[MC_MAX_NUM_LEVELS] = { 0, 1, -1, -1, -1, -1}; const int iInterlSequ64SM[MC_MAX_NUM_LEVELS] = {-1, 0, 1, -1, -1, -1}; #endif // !defined(_TABLE_MLC_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/tables/TableQAMMapping.h000664 001750 001750 00000005657 12440612574 023143 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Tables for QAM mapping (Mapping is already normalized) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(QAM_MAPPING_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) #define QAM_MAPPING_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_ #include "../GlobalDefinitions.h" /* Definitions ****************************************************************/ /* Input bits are collected in bytes separately for imaginary and real part. The order is: [i_0, i_1, i_2] and [q_0, q_1, q_2] -> {i, q} All entries are normalized according to the DRM-standard */ const _REAL rTableQAM64SM[8][2] = { { 1.0801234497f, 1.0801234497f}, {-0.1543033499f, -0.1543033499f}, { 0.4629100498f, 0.4629100498f}, {-0.7715167498f, -0.7715167498f}, { 0.7715167498f, 0.7715167498f}, {-0.4629100498f, -0.4629100498f}, { 0.1543033499f, 0.1543033499f}, {-1.0801234497f, -1.0801234497f} }; const _REAL rTableQAM64HMsym[8][2] = { { 1.0801234497f, 1.0801234497f}, { 0.4629100498f, 0.4629100498f}, { 0.7715167498f, 0.7715167498f}, { 0.1543033499f, 0.1543033499f}, {-0.1543033499f, -0.1543033499f}, {-0.7715167498f, -0.7715167498f}, {-0.4629100498f, -0.4629100498f}, {-1.0801234497f, -1.0801234497f} }; const _REAL rTableQAM64HMmix[8][2] = { { 1.0801234497f, 1.0801234497f}, { 0.4629100498f, -0.1543033499f}, { 0.7715167498f, 0.4629100498f}, { 0.1543033499f, -0.7715167498f}, {-0.1543033499f, 0.7715167498f}, {-0.7715167498f, -0.4629100498f}, {-0.4629100498f, 0.1543033499f}, {-1.0801234497f, -1.0801234497f} }; const _REAL rTableQAM16[4][2] = { { 0.9486832980f, 0.9486832980f}, {-0.3162277660f, -0.3162277660f}, { 0.3162277660f, 0.3162277660f}, {-0.9486832980f, -0.9486832980f} }; const _REAL rTableQAM4[2][2] = { { 0.7071067811f, 0.7071067811f}, {-0.7071067811f, -0.7071067811f} }; #endif // !defined(QAM_MAPPING_H__3B0_CA63_4344_BB2B_23E7912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/util/Buffer.h000664 001750 001750 00000023176 12440612574 021151 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * Transfer buffer between different modules * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(PUFFER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define PUFFER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include #include "../GlobalDefinitions.h" #include "utils/vector.h" /* Classes ********************************************************************/ /* Buffer base class */ template class CBuffer { public: CBuffer() : iBufferSize(0), bRequestFlag(false) , bNoMoreDataFlag(false){} virtual ~CBuffer() {} void SetRequestFlag(const _BOOLEAN bNewRequestFlag) { bRequestFlag = bNewRequestFlag; } void SetNoMoreDataFlag(const _BOOLEAN bNewNoMoreDataFlag) { bNoMoreDataFlag = bNewNoMoreDataFlag; } _BOOLEAN GetRequestFlag() const {return bRequestFlag;} _BOOLEAN GetNoMoreDataFlag() const {return bNoMoreDataFlag;} /* Virtual function to be declared by the derived object */ virtual void Init(const int iNewBufferSize); virtual CVectorEx* Get(const int iRequestedSize) = 0; virtual CVectorEx* QueryWriteBuffer() = 0; virtual void Put(const int iOfferedSize) = 0; virtual void Clear() = 0; virtual int GetFillLevel() const = 0; CVectorEx &getVecBuffer() {return vecBuffer;} protected: CVectorEx vecBuffer; int iBufferSize; _BOOLEAN bRequestFlag; _BOOLEAN bNoMoreDataFlag; }; /* Single block buffer */ template class CSingleBuffer : public CBuffer { public: CSingleBuffer() : iFillLevel(0) {} CSingleBuffer(const int iNBufSize) {Init(iNBufSize);} virtual ~CSingleBuffer() {} virtual void Init(const int iNewBufferSize); virtual CVectorEx* Get(const int iRequestedSize); virtual CVectorEx* QueryWriteBuffer() {return &(this->vecBuffer);} virtual void Put(const int iOfferedSize); virtual void Clear() {iFillLevel = 0;} virtual int GetFillLevel() const {return iFillLevel;} protected: int iFillLevel; }; /* Cyclic buffer */ template class CCyclicBuffer : public CBuffer { public: enum EBufferState {BS_FULL, BS_EMPTY}; // BS: Buffer Status CCyclicBuffer() {Clear();} CCyclicBuffer(const int iNBufSize) {Init(iNBufSize);} virtual ~CCyclicBuffer() {} virtual void Init(const int iNewBufferSize); virtual CVectorEx* Get(const int iRequestedSize) ; virtual CVectorEx* QueryWriteBuffer() { return &vecInOutBuffer;} virtual void Put(const int iOfferedSize); virtual void Clear(); virtual int GetFillLevel() const; protected: CVectorEx vecInOutBuffer; int iPut; int iGet; EBufferState iBufferState; }; /* Implementation *************************************************************/ template void CBuffer::Init(const int iNewBufferSize) { // printf("init van CBuffer size %d \n", iNewBufferSize); /* Assign buffer size */ iBufferSize = iNewBufferSize; /* Allocate memory for data field */ vecBuffer.Init(iBufferSize); } /******************************************************************************\ * Single block buffer * \******************************************************************************/ template void CSingleBuffer::Init(const int iNewBufferSize) { /* Only initialize buffer when size has changed, otherwise preserve data */ if (iNewBufferSize != this->iBufferSize) { CBuffer::Init(iNewBufferSize); /* Reset buffer parameters (empty buffer) */ iFillLevel = 0; } } template CVectorEx* CSingleBuffer::Get(const int iRequestedSize) { /* Get data */ #ifdef _DEBUG_ if (iRequestedSize > iFillLevel) { DebugError("SingleBuffer Get()", "FillLevel", iFillLevel, "Requested size", iRequestedSize); } #endif /* Block is read, buffer is now empty again */ iFillLevel -= iRequestedSize; return &(this->vecBuffer); } template void CSingleBuffer::Put(const int iOfferedSize) { /* New Block was added, set new fill level */ iFillLevel += iOfferedSize; #ifdef _DEBUG_ if (iFillLevel > this->iBufferSize) { DebugError("SingleBuffer Put()", "FillLevel", iFillLevel, "Buffer size", this->iBufferSize); } #endif } /******************************************************************************\ * Cyclic buffer * \******************************************************************************/ template void CCyclicBuffer::Init(const int iNewBufferSize) { // printf("In Init CCcyclic Buffer size is %d\n", iNewBufferSize); /* Only initialize buffer when size has changed, otherwise preserve data */ if (iNewBufferSize != this->iBufferSize) { CBuffer::Init(iNewBufferSize); /* Make in- and output buffer the same size as the main buffer to make sure that the worst-case is no problem */ vecInOutBuffer.Init(iNewBufferSize); /* Reset buffer parameters (empty buffer) */ iPut = 0; iGet = 0; iBufferState = BS_EMPTY; } } template void CCyclicBuffer::Clear() { /* Clear buffer by resetting the pointer */ iPut = 0; iGet = 0; iBufferState = BS_EMPTY; this->bRequestFlag = false; } template CVectorEx* CCyclicBuffer::Get(const int iRequestedSize) { int i; int iAvailSpace; int iElementCount; /* Test if enough data is available for reading */ // printf("Ccyclicbuffer get iPut %d iGet %d \n", iPut, iGet); iAvailSpace = iPut - iGet; /* Test if wrap is needed */ if ((iAvailSpace < 0) || ((iAvailSpace == 0) && (iBufferState == BS_FULL))) iAvailSpace += this->iBufferSize; #ifdef _DEBUG_ if (iAvailSpace < iRequestedSize) { DebugError("CyclicBuffer Get()", "Availabe space", iAvailSpace, "Requested size", iAvailSpace); } #endif /* Get data ------------------------------------------------------------- */ iElementCount = 0; /* Test if data can be read in one block */ if (this->iBufferSize - iGet < iRequestedSize) { /* Data must be read in two portions */ for (i = iGet; i < this->iBufferSize; i++) { vecInOutBuffer[iElementCount] = this->vecBuffer[i]; iElementCount++; } for (i = 0; i < iRequestedSize - this->iBufferSize + iGet; i++) { vecInOutBuffer[iElementCount] = this->vecBuffer[i]; iElementCount++; } } else { /* Data can be read in one block */ for (i = iGet; i < iGet + iRequestedSize; i++) { vecInOutBuffer[iElementCount] = this->vecBuffer[i]; iElementCount++; } } /* Adjust iGet pointer */ iGet += iRequestedSize; if (iGet >= this->iBufferSize) iGet -= this->iBufferSize; /* Test if buffer is empty. If yes, set empty-flag */ if ((iGet == iPut) && (iRequestedSize > 0)) iBufferState = BS_EMPTY; return &vecInOutBuffer; } template void CCyclicBuffer::Put(const int iOfferedSize) { int iAvailSpace; int i; int iElementCount; /* Test if enough data is available for writing */ iAvailSpace = iGet - iPut; /* Test if wrap is needed */ if ((iAvailSpace < 0) || ((iAvailSpace == 0) && (iBufferState == BS_EMPTY))) iAvailSpace += this->iBufferSize; #ifdef _DEBUG_ if (iAvailSpace < iOfferedSize) { DebugError("CyclicBuffer Put()", "Available space", iAvailSpace, "Offered size", iOfferedSize); } #endif /* Put data ------------------------------------------------------------- */ iElementCount = 0; /* Test if data can be written in one block */ if (this->iBufferSize - iPut < iOfferedSize) { /* Data must be written in two steps */ for (i = iPut; i < this->iBufferSize; i++) { this->vecBuffer[i] = vecInOutBuffer[iElementCount]; iElementCount++; } for (i = 0; i < iOfferedSize - this->iBufferSize + iPut; i++) { this->vecBuffer[i] = vecInOutBuffer[iElementCount]; iElementCount++; } } else { /* Data can be written in one block */ for (i = iPut; i < iPut + iOfferedSize; i++) { this->vecBuffer[i] = vecInOutBuffer[iElementCount]; iElementCount++; } } /* Adjust iPut pointer */ iPut += iOfferedSize; if (iPut >= this->iBufferSize) iPut -= this->iBufferSize; /* Test if buffer is full. If yes, set full-flag */ if ((iGet == iPut) && (iOfferedSize > 0)) iBufferState = BS_FULL; } template int CCyclicBuffer::GetFillLevel() const { int iFillLevel; /* Calculate the available data in the buffer. Test if wrap is needed! Take into account the flag-information (full or empty buffer) */ iFillLevel = iPut - iGet; if ((iFillLevel == 0) && (iBufferState == BS_FULL)) iFillLevel = this->iBufferSize; if (iFillLevel < 0) iFillLevel += this->iBufferSize; /* Wrap around */ return iFillLevel; } #endif // !defined(PUFFER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/util/CRC.cpp000664 001750 001750 00000020050 12440612574 020666 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * adapted for ham sstv use Ties Bos - PA0MBO * Description: NOTE: This code is NOT speed optimized! We should calculate the CRC byte-wise and precalculate the results in a table (TODO!) * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "CRC.h" /* Implementation *************************************************************/ void CCRC::Reset(const int iNewDegree) { /* Build mask of bit, which was shifted out of the shift register */ iBitOutPosMask = 1 << iNewDegree; /* Index of vector storing the polynominals for CRC calculation */ iDegIndex = iNewDegree - 1; /* Init state shift-register with ones. Set all registers to "1" with bit-wise not operation */ iStateShiftReg = ~uint32_t(0); } void CCRC::AddByte(const _BYTE byNewInput) { for (int i = 0; i < SIZEOF__BYTE; i++) { /* Shift bits in shift-register for transistion */ iStateShiftReg <<= 1; /* Take bit, which was shifted out of the register-size and place it at the beginning (LSB) (If condition is not satisfied, implicitely a "0" is added) */ if ((iStateShiftReg & iBitOutPosMask) > 0) iStateShiftReg |= 1; /* Add new data bit to the LSB */ if ((byNewInput & (1 << (SIZEOF__BYTE - i - 1))) > 0) iStateShiftReg ^= 1; /* Add mask to shift-register if first bit is true */ if (iStateShiftReg & 1) iStateShiftReg ^= iPolynMask[iDegIndex]; } } void CCRC::AddBit(const _BINARY biNewInput) { /* Shift bits in shift-register for transistion */ iStateShiftReg <<= 1; /* Take bit, which was shifted out of the register-size and place it at the beginning (LSB) (If condition is not satisfied, implicitely a "0" is added) */ if ((iStateShiftReg & iBitOutPosMask) > 0) iStateShiftReg |= 1; /* Add new data bit to the LSB */ if (biNewInput > 0) iStateShiftReg ^= 1; /* Add mask to shift-register if first bit is true */ if (iStateShiftReg & 1) iStateShiftReg ^= iPolynMask[iDegIndex]; } uint32_t CCRC::GetCRC() { /* Return inverted shift-register (1's complement) */ iStateShiftReg = ~iStateShiftReg; /* Remove bit which where shifted out of the shift-register frame */ return iStateShiftReg & (iBitOutPosMask - 1); } _BOOLEAN CCRC::CheckCRC(const uint32_t iCRC) { if (iCRC == GetCRC()) return true; else return false; } CCRC::CCRC() { /* These polynominals are used in the DRM-standard */ iPolynMask[0] = 0; iPolynMask[1] = 1 << 1; iPolynMask[2] = 1 << 1; iPolynMask[4] = (1 << 1) | (1 << 2) | (1 << 4); iPolynMask[5] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5); iPolynMask[7] = (1 << 2) | (1 << 3) | (1 << 4); iPolynMask[15] = (1 << 5) | (1 << 12); } /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Andreas Dittrich, Torsten Schorr */ /* */ /* Author(s) : Andreas Dittrich (dittrich@eit.uni-kl.de), */ /* Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 27.07.2004 */ /* Last change : 27.07.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* crc16_bytewise.c */ /* */ /******************************************************************************/ /* Description: */ /* CRC-16 checksum calculation of a byte stream */ /* Usage: */ /* */ /* crc16_bytewise(double *checksum, unsigned char *in, long N); */ /* */ /* calculates double checksum of uint8 bytes */ /* */ /******************************************************************************/ /************* * * adjusted for use in own plain C programa * by M.Bos - PA0MBO * * Date Dec 9th 2007 */ /******************************************************************************/ /* function */ /******************************************************************************/ void CCRC::crc16_bytewise(double checksum[], unsigned char in[], long N) { long int i; int j; unsigned int b = 0xFFFF; unsigned int x = 0x1021; /* (1) 0001000000100001 */ unsigned int y=0; for (i = 0; i < N - 2; i++) { for (j = 7; j >= 0; j--) { y = (((b >> 15) + (unsigned int) (in[i] >> j)) & 0x01) & 0x01; /* extra parenth pa0mbo */ if (y == 1) b = ((b << 1) ^ x); else b = (b << 1); } } for (i = N - 2; i < N; i++) { for (j = 7; j >= 0; j--) { y = (((b >> 15) + (unsigned int) ((in[i] >> j) & 0x01)) ^ 0x01) & 0x01; /* extra parent pa0mbo */ if (y == 1) b = ((b << 1) ^ x); else b = (b << 1); } } *checksum = (double) (b & 0xFFFF); } qsstv_8.2.12/qsstv/drmtx/common/util/CRC.h000664 001750 001750 00000003607 12440612574 020344 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * extended for ham sstv use Ties Bos - PA0MBO * * Description: * See CRC.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(CRC_H__3B0BA660_CA63_4VASDGLJNAJ2B_23E7A0D31912__INCLUDED_) #define CRC_H__3B0BA660_CA63_4VASDGLJNAJ2B_23E7A0D31912__INCLUDED_ #include "../GlobalDefinitions.h" /* Classes ********************************************************************/ class CCRC { public: CCRC(); virtual ~CCRC() {} void Reset(const int iNewDegree); void AddByte(const _BYTE byNewInput); void AddBit(const _BINARY biNewInput); _BOOLEAN CheckCRC(const uint32_t iCRC); uint32_t GetCRC(); void crc16_bytewise(double checksum[], unsigned char in[], long N); protected: int iDegIndex; uint32_t iBitOutPosMask; uint32_t iPolynMask[16]; uint32_t iStateShiftReg; }; #endif // !defined(CRC_H__3B0BA660_CA63_4VASDGLJNAJ2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/util/Modul.h000664 001750 001750 00000031233 12440612574 021011 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * High level class for all modules. The common functionality for reading * and writing the transfer-buffers are implemented here. * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(AFX_MODUL_H__41E39CD3_2AEC_400E_907B_148C0EC17A43__INCLUDED_) #define AFX_MODUL_H__41E39CD3_2AEC_400E_907B_148C0EC17A43__INCLUDED_ #include "Buffer.h" #include "utils/vector.h" #include "../Parameter.h" #include /* Classes ********************************************************************/ /* CModul ------------------------------------------------------------------- */ template class CModul { public: CModul(); virtual ~CModul() {} virtual void Init(CParameter& Parameter); virtual void Init(CParameter& Parameter, CBuffer& OutputBuffer); protected: CVectorEx* pvecInputData; CVectorEx* pvecOutputData; /* Max block-size are used to determine the size of the requiered buffer */ int iMaxOutputBlockSize; /* Actual read (or written) size of the data */ int iInputBlockSize; int iOutputBlockSize; void Lock() {Mutex.Lock();} void Unlock() {Mutex.Unlock();} void InitThreadSave(CParameter& Parameter); virtual void InitInternal(CParameter& Parameter) = 0; void ProcessDataThreadSave(CParameter& Parameter); virtual void ProcessDataInternal(CParameter& Parameter) = 0; private: CMutex Mutex; }; /* CTransmitterModul -------------------------------------------------------- */ template class CTransmitterModul : public CModul { public: CTransmitterModul(); virtual ~CTransmitterModul() {} virtual void Init(CParameter& Parameter); virtual void Init(CParameter& Parameter, CBuffer& OutputBuffer); virtual void ReadData(CParameter& Parameter, CBuffer& OutputBuffer); virtual void ProcessData(CParameter& Parameter, CBuffer& OutputBuffer); virtual _BOOLEAN ProcessData(CParameter& Parameter, CBuffer& InputBuffer, CBuffer& OutputBuffer); virtual void ProcessData(CParameter& Parameter, CBuffer& InputBuffer, CBuffer& InputBuffer2, // CBuffer& InputBuffer3, pa0mbo CBuffer& OutputBuffer); virtual _BOOLEAN WriteData(CParameter& Parameter, CBuffer& InputBuffer); protected: /* Additional buffers if the derived class has multiple input streams */ CVectorEx* pvecInputData2; CVectorEx* pvecInputData3; /* Actual read (or written) size of the data */ int iInputBlockSize2; int iInputBlockSize3; }; /* Implementation *************************************************************/ /******************************************************************************\ * CModul * \******************************************************************************/ template CModul::CModul() { /* Initialize everything with zeros */ iMaxOutputBlockSize = 0; iInputBlockSize = 0; iOutputBlockSize = 0; pvecInputData = NULL; pvecOutputData = NULL; } template void CModul::ProcessDataThreadSave(CParameter& Parameter) { /* Get a lock for the resources */ Lock(); /* Call processing routine of derived modul */ ProcessDataInternal(Parameter); /* Unlock resources */ Unlock(); } template void CModul::InitThreadSave(CParameter& Parameter) { /* Get a lock for the resources */ Lock(); try { /* Call init of derived modul */ InitInternal(Parameter); /* Unlock resources */ Unlock(); } catch (CGenErr) { /* Unlock resources */ Unlock(); /* Throws the same error again which was send by the function */ throw; } } template void CModul::Init(CParameter& Parameter) { /* Init some internal variables */ iInputBlockSize = 0; /* Call init of derived modul */ InitThreadSave(Parameter); } template void CModul::Init(CParameter& Parameter, CBuffer& OutputBuffer) { /* Init some internal variables */ iMaxOutputBlockSize = 0; iInputBlockSize = 0; iOutputBlockSize = 0; /* Call init of derived modul */ InitThreadSave(Parameter); /* Init output transfer buffer */ if (iMaxOutputBlockSize != 0) OutputBuffer.Init(iMaxOutputBlockSize); else { if (iOutputBlockSize != 0) OutputBuffer.Init(iOutputBlockSize); } } /******************************************************************************\ * Transmitter modul (CTransmitterModul) * \******************************************************************************/ template CTransmitterModul::CTransmitterModul() { /* Initialize all member variables with zeros */ iInputBlockSize2 = 0; iInputBlockSize3 = 0; pvecInputData2 = NULL; pvecInputData3 = NULL; } template void CTransmitterModul::Init(CParameter& Parameter) { /* Init some internal variables */ iInputBlockSize2 = 0; iInputBlockSize3 = 0; /* Init base-class */ CModul::Init(Parameter); } template void CTransmitterModul::Init(CParameter& Parameter, CBuffer& OutputBuffer) { /* Init some internal variables */ iInputBlockSize2 = 0; iInputBlockSize3 = 0; /* Init base-class */ CModul::Init(Parameter, OutputBuffer); } template _BOOLEAN CTransmitterModul:: ProcessData(CParameter& Parameter, CBuffer& InputBuffer, CBuffer& OutputBuffer) { // printf("Tx Par Inp Outp request is %d\n", OutputBuffer.GetRequestFlag()); /* OUTPUT-DRIVEN modul implementation in the transmitter ---------------- */ /* Look in output buffer if data is requested */ if (OutputBuffer.GetRequestFlag() == true) { // printf("CTransmitterModul Getrequest is true\n"); /* Check, if enough input data is available */ if (InputBuffer.GetFillLevel() < this->iInputBlockSize) { /* Set request flag */ InputBuffer.SetRequestFlag(true); return false; } /* Get vector from transfer-buffer */ this->pvecInputData = InputBuffer.Get(this->iInputBlockSize); /* Query vector from output transfer-buffer for writing */ this->pvecOutputData = OutputBuffer.QueryWriteBuffer(); /* Copy extended data from vectors */ (*(this->pvecOutputData)).SetExData((*(this->pvecInputData)).GetExData()); /* Call the underlying processing-routine */ this->ProcessDataInternal(Parameter); /* Write processed data from internal memory in transfer-buffer */ OutputBuffer.Put(this->iOutputBlockSize); /* Data was provided, clear data request */ OutputBuffer.SetRequestFlag(false); } return true; } template void CTransmitterModul:: ProcessData(CParameter& Parameter, CBuffer& InputBuffer, CBuffer& InputBuffer2, // CBuffer& InputBuffer3, pa0mbo CBuffer& OutputBuffer) { /* OUTPUT-DRIVEN modul implementation in the transmitter ---------------- */ /* Look in output buffer if data is requested */ // printf("Tx Par Inp1 Inp2 Outp request is %d inp1size %d inp2size %d \n", // OutputBuffer.GetRequestFlag(), this->iInputBlockSize, iInputBlockSize2); if (OutputBuffer.GetRequestFlag() == true) { /* Check, if enough input data is available from all sources */ if (InputBuffer.GetFillLevel() < this->iInputBlockSize) { /* Set request flag */ // printf("tx modul 2 inputs setting request on buf1 \n"); InputBuffer.SetRequestFlag(true); return; } if (InputBuffer2.GetFillLevel() < iInputBlockSize2) { /* Set request flag */ // printf("tx modul 2 inputs setting request on buf2 \n"); InputBuffer2.SetRequestFlag(true); return; } /* if (InputBuffer3.GetFillLevel() < iInputBlockSize3) { InputBuffer3.SetRequestFlag(true); return; } */ /* Get vectors from transfer-buffers */ addToLog(QString("ProcesData get %1").arg(this->iInputBlockSize),LOGDRMTX); this->pvecInputData = InputBuffer.Get(this->iInputBlockSize); pvecInputData2 = InputBuffer2.Get(iInputBlockSize2); // pvecInputData3 = InputBuffer3.Get(iInputBlockSize3); pa0mbo /* Query vector from output transfer-buffer for writing */ this->pvecOutputData = OutputBuffer.QueryWriteBuffer(); /* Call the underlying processing-routine */ this->ProcessDataInternal(Parameter); /* Write processed data from internal memory in transfer-buffer */ OutputBuffer.Put(this->iOutputBlockSize); /* Data was provided, clear data request */ OutputBuffer.SetRequestFlag(false); } } template void CTransmitterModul::ProcessData(CParameter& Parameter, CBuffer& OutputBuffer) { // printf("Tx par Outp request flag is %d\n", OutputBuffer.GetRequestFlag()); /* OUTPUT-DRIVEN modul implementation in the transmitter ---------------- */ /* Look in output buffer if data is requested */ if (OutputBuffer.GetRequestFlag() == true) { /* Read data and write it in the transfer-buffer. Query vector from output transfer-buffer for writing */ this->pvecOutputData = OutputBuffer.QueryWriteBuffer(); /* Call the underlying processing-routine */ this->ProcessDataInternal(Parameter); /* Write processed data from internal memory in transfer-buffer */ OutputBuffer.Put(this->iOutputBlockSize); /* Data was provided, clear data request */ OutputBuffer.SetRequestFlag(false); } } template void CTransmitterModul:: ReadData(CParameter& Parameter, CBuffer& OutputBuffer) { // printf("CTransmitterModul entry flag is %d\n", OutputBuffer.GetRequestFlag()); /* OUTPUT-DRIVEN modul implementation in the transmitter ---------------- */ /* Look in output buffer if data is requested */ // printf("Tx ReadData request flag is %d \n", OutputBuffer.GetRequestFlag()); if (OutputBuffer.GetRequestFlag() == true) { /* Read data and write it in the transfer-buffer. Query vector from output transfer-buffer for writing */ this->pvecOutputData = OutputBuffer.QueryWriteBuffer(); /* Call the underlying processing-routine */ this->ProcessDataInternal(Parameter); /* Write processed data from internal memory in transfer-buffer */ OutputBuffer.Put(this->iOutputBlockSize); /* Data was provided, clear data request */ OutputBuffer.SetRequestFlag(false); } } template _BOOLEAN CTransmitterModul:: WriteData(CParameter& Parameter, CBuffer& InputBuffer) { // printf("WriteData fill %d Inpblk size %d \n", // InputBuffer.GetFillLevel(), this->iInputBlockSize); /* OUTPUT-DRIVEN modul implementation in the transmitter */ /* Check, if enough input data is available */ if (InputBuffer.GetFillLevel() < this->iInputBlockSize) { // printf("set request flag transmitter module WriteData \n"); /* Set request flag */ InputBuffer.SetRequestFlag(true); return false; } // printf("Getting the data in TXModul from input buffer\n"); /* Get vector from transfer-buffer */ this->pvecInputData = InputBuffer.Get(this->iInputBlockSize); /* Call the underlying processing-routine */ this->ProcessDataInternal(Parameter); return true; } #endif // !defined(AFX_MODUL_H__41E39CD3_2AEC_400E_907B_148C0EC17A43__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/util/Utilities.cpp000664 001750 001750 00000022636 12440612574 022246 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2004 * * Author(s): * Volker Fischer * * Description: * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "Utilities.h" #include #include #if defined(_WIN32) # ifdef HAVE_SETUPAPI # ifndef INITGUID # define INITGUID 1 # endif # include # include # if defined(_MSC_VER) && (_MSC_VER < 1400) || defined(__MINGW32__) DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73); # endif # endif #elif defined(__APPLE__) #include #include #include #endif /* Implementation *************************************************************/ /******************************************************************************\ * Signal level meter * \******************************************************************************/ //void //CSignalLevelMeter::Update(const _REAL rVal) //{ // /* Search for maximum. Decrease this max with time */ // /* Decrease max with time */ // if (rCurLevel >= METER_FLY_BACK) // rCurLevel -= METER_FLY_BACK; // else // { // if ((rCurLevel <= METER_FLY_BACK) && (rCurLevel > 1)) // rCurLevel -= 2; // } // /* Search for max */ // const _REAL rCurAbsVal = Abs(rVal); // if (rCurAbsVal > rCurLevel) // rCurLevel = rCurAbsVal; //} //void //CSignalLevelMeter::Update(const CVector < _REAL > vecrVal) //{ // /* Do the update for entire vector */ // const int iVecSize = vecrVal.Size(); // for (int i = 0; i < iVecSize; i++) // Update(vecrVal[i]); //} //void //CSignalLevelMeter::Update(const CVector < _SAMPLE > vecsVal) //{ // /* Do the update for entire vector, convert to real */ // const int iVecSize = vecsVal.Size(); // for (int i = 0; i < iVecSize; i++) // Update((_REAL) vecsVal[i]); //} //_REAL CSignalLevelMeter::Level() //{ // const _REAL // rNormMicLevel = rCurLevel / _MAXSHORT; // /* Logarithmic measure */ // if (rNormMicLevel > 0) // return 20.0 * log10(rNormMicLevel); // else // return RET_VAL_LOG_0; //} /******************************************************************************\ * Bandpass filter * \******************************************************************************/ void CDRMBandpassFilt::Process(CVector < _COMPLEX > &veccData) { int i; /* Copy CVector data in CMatlibVector */ for (i = 0; i < iBlockSize; i++) cvecDataTmp[i] = veccData[i]; /* Apply FFT filter */ cvecDataTmp = CComplexVector(FftFilt (cvecB, Real(cvecDataTmp), rvecZReal, FftPlanBP), FftFilt(cvecB, Imag(cvecDataTmp), rvecZImag, FftPlanBP)); /* Copy CVector data in CMatlibVector */ for (i = 0; i < iBlockSize; i++) veccData[i] = cvecDataTmp[i]; } void CDRMBandpassFilt::Init(const int iNewBlockSize, const _REAL rOffsetHz, const ESpecOcc eSpecOcc, const EFiltType eNFiTy) { CReal rMargin = 0.0; /* Set internal parameter */ iBlockSize = iNewBlockSize; /* Init temporary vector */ cvecDataTmp.Init(iBlockSize); /* Choose correct filter for chosen DRM bandwidth. Also, adjust offset frequency for different modes. E.g., 5 kHz mode is on the right side of the DC frequency */ CReal rNormCurFreqOffset = rOffsetHz / SOUNDCRD_SAMPLE_RATE; /* Band-pass filter bandwidth */ CReal rBPFiltBW = ((CReal) 10000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; /* Negative margin for receiver filter for better interferer rejection */ if (eNFiTy == FT_TRANSMITTER) rMargin = (CReal) 0.0; /* Hz was 300 */ else rMargin = (CReal) 0.0; /* Hz */ switch (eSpecOcc) { case SO_0: rBPFiltBW = ((CReal) 2000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; // pa0mbo was 4500.0 moet zijn 2250? /* Completely on the right side of DC */ rNormCurFreqOffset = (rOffsetHz + (CReal) 1100.0) / SOUNDCRD_SAMPLE_RATE; // pa0mbo // ( (CReal) 7100.0 ) / SOUNDCRD_SAMPLE_RATE; // pa0mbo // printf("util Bandpass filt init SO_0 BW %g rNormOffs %g\n", rBPFiltBW, rNormCurFreqOffset); break; case SO_1: rBPFiltBW = ((CReal) 2500.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; // pa0mbo was 5000.0 moet zijn 2500 ? /* Completely on the right side of DC */ rNormCurFreqOffset = (rOffsetHz + (CReal) 1250.0) / SOUNDCRD_SAMPLE_RATE; // pa0mbo // ( (CReal) 7240.0 ) / SOUNDCRD_SAMPLE_RATE; // pa0mbo // printf("util drmbandpass SO_1 BW = %g , Offset = %g \n", rBPFiltBW, rNormCurFreqOffset); break; case SO_2: rBPFiltBW = ((CReal) 9000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; /* Centered */ rNormCurFreqOffset = rOffsetHz / SOUNDCRD_SAMPLE_RATE; break; case SO_3: rBPFiltBW = ((CReal) 10000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; /* Centered */ rNormCurFreqOffset = rOffsetHz / SOUNDCRD_SAMPLE_RATE; break; case SO_4: rBPFiltBW = ((CReal) 18000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; /* Main part on the right side of DC */ rNormCurFreqOffset = (rOffsetHz + (CReal) 4500.0) / SOUNDCRD_SAMPLE_RATE; break; case SO_5: rBPFiltBW = ((CReal) 20000.0 + rMargin) / SOUNDCRD_SAMPLE_RATE; /* Main part on the right side of DC */ rNormCurFreqOffset = (rOffsetHz + (CReal) 5000.0) / SOUNDCRD_SAMPLE_RATE; break; } // printf("Init bandpass BW = %g rNorm %g \n", rBPFiltBW, rNormCurFreqOffset); /* FFT plan is initialized with the long length */ FftPlanBP.Init(iBlockSize * 2); /* State memory (init with zeros) and data vector */ rvecZReal.Init(iBlockSize, (CReal) 0.0); rvecZImag.Init(iBlockSize, (CReal) 0.0); rvecDataReal.Init(iBlockSize); rvecDataImag.Init(iBlockSize); /* "+ 1" because of the Nyquist frequency (filter in frequency domain) */ cvecB.Init(iBlockSize + 1); /* Actual filter design */ CRealVector vecrFilter(iBlockSize); vecrFilter = FirLP(rBPFiltBW, Nuttallwin(iBlockSize)); /* Copy actual filter coefficients. It is important to initialize the vectors with zeros because we also do a zero-padding */ CRealVector rvecB(2 * iBlockSize, (CReal) 0.0); /* Modulate filter to shift it to the correct IF frequency */ for (int i = 0; i < iBlockSize; i++) { rvecB[i] = vecrFilter[i] * Cos((CReal) 2.0 * crPi * rNormCurFreqOffset * i); } /* Transformation in frequency domain for fft filter */ cvecB = rfft(rvecB, FftPlanBP); /* debugging pa0mbo for (i=0; i < iBlockSize; i++) { printf(" vecrFilter[%d] is %g cvecB[%d] real is %g \n", i, vecrFilter[i], i, cvecB[i].real()); } */ // printf("end of init BPfilt, iBlockSize %d rBPFBW %g rOffsetHz %g i rNormFreqoff %g\n", // iBlockSize, rBPFiltBW, rOffsetHz, rNormCurFreqOffset ) ; // printf("Soundcard sample rate is %d \n", SOUNDCRD_SAMPLE_RATE); } /******************************************************************************\ * Modified Julian Date * \******************************************************************************/ void CModJulDate::Set(const uint32_t iModJulDate) { uint32_t iZ, iA, iAlpha, iB, iC, iD, iE; _REAL rJulDate; /* Definition of the Modified Julian Date */ rJulDate = (_REAL) iModJulDate + 2400000.5; /* Get "real" date out of Julian Date (Taken from "http://mathforum.org/library/drmath/view/51907.html") */ // 1. Add .5 to the JD and let Z = integer part of (JD+.5) and F the // fractional part F = (JD+.5)-Z iZ = (uint32_t) (rJulDate + (_REAL) 0.5); // rF = (rJulDate + (_REAL) 0.5) - iZ; // 2. If Z < 2299161, take A = Z // If Z >= 2299161, calculate alpha = INT((Z-1867216.25)/36524.25) // and A = Z + 1 + alpha - INT(alpha/4). if (iZ < 2299161) iA = iZ; else { iAlpha = (int) (((_REAL) iZ - (_REAL) 1867216.25) / (_REAL) 36524.25); iA = iZ + 1 + iAlpha - (int) ((_REAL) iAlpha / (_REAL) 4.0); } // 3. Then calculate: // B = A + 1524 // C = INT( (B-122.1)/365.25) // D = INT( 365.25*C ) // E = INT( (B-D)/30.6001 ) iB = iA + 1524; iC = (int) (((_REAL) iB - (_REAL) 122.1) / (_REAL) 365.25); iD = (int) ((_REAL) 365.25 * iC); iE = (int) (((_REAL) iB - iD) / (_REAL) 30.6001); // The day of the month dd (with decimals) is: // dd = B - D - INT(30.6001*E) + F iDay = iB - iD - (int) ((_REAL) 30.6001 * iE); // + rF; // The month number mm is: // mm = E - 1, if E < 13.5 // or // mm = E - 13, if E > 13.5 if ((_REAL) iE < 13.5) iMonth = iE - 1; else iMonth = iE - 13; // The year yyyy is: // yyyy = C - 4716 if m > 2.5 // or // yyyy = C - 4715 if m < 2.5 if ((_REAL) iMonth > 2.5) iYear = iC - 4716; else iYear = iC - 4715; } qsstv_8.2.12/qsstv/drmtx/common/util/Utilities.h000664 001750 001750 00000006500 12440612574 021703 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2004 * * Author(s): * Volker Fischer * * Description: * Implements: * - Signal level meter * - Bandpass filter * - Modified Julian Date * - Reverberation effect * - Hamlib interface * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(UTILITIES_H__3B0BA660_CA63_4344_B3452345D31912__INCLUDED_) #define UTILITIES_H__3B0BA660_CA63_4344_B3452345D31912__INCLUDED_ #include "../GlobalDefinitions.h" //#include "Settings.h" #include "utils/vector.h" #include "../matlib/Matlib.h" #include #include #ifdef HAVE_LIBHAMLIB # include #endif /* Definitions ****************************************************************/ #define METER_FLY_BACK 15 /* Classes ********************************************************************/ /* Signal level meter ------------------------------------------------------- */ //class CSignalLevelMeter //{ //public: // CSignalLevelMeter() : rCurLevel((_REAL) 0.0) {} // virtual ~CSignalLevelMeter() {} // void Init(_REAL rStartVal) {rCurLevel = Abs(rStartVal);} // void Update(const _REAL rVal); // void Update(const CVector<_REAL> vecrVal); // void Update(const CVector<_SAMPLE> vecsVal); // _REAL Level(); //protected: // _REAL rCurLevel; //}; /* Bandpass filter ---------------------------------------------------------- */ class CDRMBandpassFilt { public: enum EFiltType {FT_TRANSMITTER, FT_RECEIVER}; void Init(const int iNewBlockSize, const _REAL rOffsetHz, const ESpecOcc eSpecOcc, const EFiltType eNFiTy); void Process(CVector<_COMPLEX>& veccData); protected: int iBlockSize; CComplexVector cvecDataTmp; CRealVector rvecZReal; /* State memory real part */ CRealVector rvecZImag; /* State memory imaginary part */ CRealVector rvecDataReal; CRealVector rvecDataImag; CFftPlans FftPlanBP; CComplexVector cvecB; }; /* Modified Julian Date ----------------------------------------------------- */ class CModJulDate { public: CModJulDate() : iYear(0), iDay(0), iMonth(0) {} CModJulDate(const uint32_t iModJulDate) {Set(iModJulDate);} void Set(const uint32_t iModJulDate); int GetYear() {return iYear;} int GetDay() {return iDay;} int GetMonth() {return iMonth;} protected: int iYear, iDay, iMonth; }; struct CHamlib { enum ESMeterState {SS_VALID, SS_NOTVALID, SS_TIMEOUT}; }; #endif // !defined(UTILITIES_H__3B0BA660_CA63_4344_B3452345D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/DRMSignalIO.cpp000664 001750 001750 00000012134 12440612574 021316 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer, Cesco (HB9TLK) * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * Transmit and receive data * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "DRMSignalIO.h" #include #include "qsstvglobal.h" #define pi 4.0*atan(1.0) /******************************************************************************\ * Transmitter * \******************************************************************************/ void CTransmitData::ProcessDataInternal(CParameter&) { int i; const int iNs2 = iInputBlockSize * 2; rNormFactor =1000.0 ; // pa0mbo (was 16000) for (i = 0; i < iNs2; i += 2) { const int iCurIndex = iBlockCnt * iNs2 + i; /* Imaginary, real */ const short sCurOutReal = (short) ((*pvecInputData)[i / 2].real() * rNormFactor); const short sCurOutImag = (short) ((*pvecInputData)[i / 2].imag() * rNormFactor); /* Envelope, phase */ const short sCurOutEnv = (short) (Abs((*pvecInputData)[i / 2]) * (_REAL) 256.0); const short sCurOutPhase = (short) (Angle((*pvecInputData)[i / 2]) * (_REAL) 5000.0); /* 2^15 / pi / 2 -> approx. 5000 */ switch (eOutputFormat) { case OF_REAL_VAL: vecsDataOut[iCurIndex] = vecsDataOut[iCurIndex + 1] = sCurOutReal; // (short) 15000.0*sin(pi*1500.0*i/48000.0) ; // pa0mbo 1500 Hz test signaal // printf("%d %d \n", i/2 , vecsDataOut[iCurIndex]); break; case OF_IQ_POS: /* Send inphase and quadrature (I / Q) signal to stereo sound card output. I: left channel, Q: right channel */ vecsDataOut[iCurIndex] = sCurOutReal; vecsDataOut[iCurIndex + 1] = sCurOutImag; break; case OF_IQ_NEG: /* Send inphase and quadrature (I / Q) signal to stereo sound card output. I: right channel, Q: left channel */ vecsDataOut[iCurIndex] = sCurOutImag; vecsDataOut[iCurIndex + 1] = sCurOutReal; break; case OF_EP: /* Send envelope and phase signal to stereo sound card output. Envelope: left channel, Phase: right channel */ vecsDataOut[iCurIndex] = sCurOutEnv; vecsDataOut[iCurIndex + 1] = sCurOutPhase; break; } } iBlockCnt++; if (iBlockCnt == iNumBlocks) { iBlockCnt = 0; pSound->Write(vecsDataOut); // printf("DRMSignalIO na pSound-> write\n"); addToLog(QString("writing vecsDataOut:%1").arg(vecsDataOut.size()),LOGDRMTX); } } void CTransmitData::InitInternal(CParameter& TransmParam) { /* float* pCurFilt; int iNumTapsTransmFilt; CReal rNormCurFreqOffset; */ const int iSymbolBlockSize = TransmParam.CellMappingTable.iSymbolBlockSize; /* Init vector for storing a complete DRM frame number of OFDM symbols */ iBlockCnt = 0; TransmParam.Lock(); iNumBlocks = TransmParam.CellMappingTable.iNumSymPerFrame; ESpecOcc eSpecOcc = TransmParam.GetSpectrumOccup(); TransmParam.Unlock(); iBigBlockSize = iSymbolBlockSize * 2 * iNumBlocks; /* stereo */ // printf("iBigBlockSize in init Ctransmitdata = %d\n", iBigBlockSize); vecsDataOut.Init(iBigBlockSize); if (pFileTransmitter != NULL) { fclose(pFileTransmitter); } /* Init sound interface */ // pSound->Init(iBigBlockSize, true); /* Init bandpass filter object */ BPFilter.Init(iSymbolBlockSize, rDefCarOffset, eSpecOcc,CDRMBandpassFilt::FT_TRANSMITTER); /* printf("DRMSignalIO BPFilter init Symbolsize %d rDefCaroffset %g eSpecooc %d \n", iSymbolBlockSize, rDefCarOffset, eSpecOcc); */ /* All robustness modes and spectrum occupancies should have the same output power. Calculate the normaization factor based on the average power of symbol (the number 3000 was obtained through output tests) */ rNormFactor = (CReal) 6000.0 / Sqrt(TransmParam.CellMappingTable.rAvPowPerSymbol); // pa0mbo was 3000.0 nu as in ham /* Define block-size for input */ iInputBlockSize = iSymbolBlockSize; } CTransmitData::~CTransmitData() { /* Close file */ if (pFileTransmitter != NULL) fclose(pFileTransmitter); } qsstv_8.2.12/qsstv/drmtx/common/DRMSignalIO.h000664 001750 001750 00000010062 12440612574 020761 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See DRMSignalIO.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DRMSIGNALIO_H__3B0BA660_CA63_4344_B_23E7A0D31912__INCLUDED_) #define DRMSIGNALIO_H__3B0BA660_CA63_4344_B_23E7A0D31912__INCLUDED_ #include "Parameter.h" #include "soundinterface.h" #include #include "matlib/Matlib.h" //#include "IQInputFilter.h" #include "util/Modul.h" #include "util/Utilities.h" /* Definitions ****************************************************************/ /* Number of FFT blocks used for averaging. See next definition ("NUM_SMPLS_4_INPUT_SPECTRUM") for how to set the parameters */ #define NUM_AV_BLOCKS_PSD 16 #define LEN_PSD_AV_EACH_BLOCK 512 /* same but for the rpsd tag */ #define NUM_AV_BLOCKS_PSD_RSI 150 #define LEN_PSD_AV_EACH_BLOCK_RSI 256 #define PSD_OVERLAP_RSI 128 /* power gain of the Hamming window */ #define PSD_WINDOW_GAIN 0.39638 /* Length of vector for input spectrum. We use approx. 0.2 sec of sampled data for spectrum calculation, this is 2^13 = 8192 to make the FFT work more efficient. Make sure that this number is not smaller than the symbol lenght in 48 khz domain of longest mode (which is mode A/B: 1280) */ #define NUM_SMPLS_4_INPUT_SPECTRUM (NUM_AV_BLOCKS_PSD * LEN_PSD_AV_EACH_BLOCK) /* The RSI output needs 400ms with a 50% overlap, so this needs more space I think the RSCI spec is slightly wrong - using 150 windows consumes just over 400ms, 149 would be exact */ #define INPUT_DATA_VECTOR_SIZE (NUM_AV_BLOCKS_PSD_RSI * (LEN_PSD_AV_EACH_BLOCK_RSI-PSD_OVERLAP_RSI)+PSD_OVERLAP_RSI) #define RNIP_SEARCH_RANGE_NARROW 5100.0 #define RNIP_SEARCH_RANGE_WIDE 15100.0 #define RNIP_EXCLUDE_BINS 2 // either side of the peak /* Use raw 16 bit data or in text form for file format for DRM data. Defining the following macro will enable the raw data option */ #define FILE_DRM_USING_RAW_DATA /* Classes ********************************************************************/ class CTransmitData : public CTransmitterModul<_COMPLEX, _COMPLEX> { public: enum EOutFormat {OF_REAL_VAL /* real valued */, OF_IQ_POS, OF_IQ_NEG /* I / Q */, OF_EP /* envelope / phase */}; CTransmitData(CSoundOutInterface* pNS) : pFileTransmitter(NULL), pSound(pNS), eOutputFormat(OF_REAL_VAL), rDefCarOffset((_REAL) VIRTUAL_INTERMED_FREQ) // , strOutFileName("test/TransmittedData.txt") { } virtual ~CTransmitData(); void SetIQOutput(const EOutFormat eFormat) {eOutputFormat = eFormat;} EOutFormat GetIQOutput() {return eOutputFormat;} void SetCarOffset(const CReal rNewCarOffset) {rDefCarOffset = rNewCarOffset;} protected: FILE* pFileTransmitter; CSoundOutInterface* pSound; CVector vecsDataOut; int iBlockCnt; int iNumBlocks; EOutFormat eOutputFormat; CDRMBandpassFilt BPFilter; CReal rDefCarOffset; CReal rNormFactor; int iBigBlockSize; // string strOutFileName; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& Parameter); }; #endif // !defined(DRMSIGNALIO_H__3B0BA660_CA63_4344_B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/DataIO.cpp000664 001750 001750 00000004221 12440612574 020405 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001-2006 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "DataIO.h" #include #include /******************************************************************************\ * FAC data * \******************************************************************************/ /* Transmitter */ void CGenerateFACData::ProcessDataInternal(CParameter& TransmParam) { FACTransmit.FACParam(pvecOutputData, TransmParam); } void CGenerateFACData::InitInternal(CParameter& TransmParam) { FACTransmit.Init(TransmParam); /* Define block-size for output */ iOutputBlockSize = NUM_FAC_BITS_PER_BLOCK; } /******************************************************************************\ * SDC data * \******************************************************************************/ /* Transmitter */ void CGenerateSDCData::ProcessDataInternal(CParameter& TransmParam) { SDCTransmit.SDCParam(pvecOutputData, TransmParam); } void CGenerateSDCData::InitInternal(CParameter& TransmParam) { /* Define block-size for output */ iOutputBlockSize = TransmParam.iNumSDCBitsPerSFrame; } qsstv_8.2.12/qsstv/drmtx/common/DataIO.h000664 001750 001750 00000007735 12440612574 020067 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001-2005 * * Author(s): * Volker Fischer, Andrew Murphy * * Description: * See Data.cpp * * 11/21/2005 Andrew Murphy, BBC Research & Development, 2005 * - Addition GetSDCReceive(), Added CSplit class * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DATA_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define DATA_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ # include "soundinterface.h" #include "Parameter.h" #include "util/Modul.h" #include "FAC/FAC.h" #include "SDC/SDC.h" //#include "TextMessage.h" //#include "util/AudioFile.h" #include "util/Utilities.h" //#include "AMDemodulation.h" // For CMixer /* Definitions ****************************************************************/ /* In case of random-noise, define number of blocks */ #define DEFAULT_NUM_SIM_BLOCKS 50 /* Length of vector for audio spectrum. We use a power-of-two length to make the FFT work more efficient */ #define NUM_SMPLS_4_AUDIO_SPECTRUM 256 /* Time span used for averaging the audio spectrum. Shall be higher than the 400 ms DRM audio block */ #define TIME_AV_AUDIO_SPECT_MS 500 /* ms */ /* Number of blocks for averaging the audio spectrum */ #define NUM_BLOCKS_AV_AUDIO_SPEC Ceil(((_REAL) SOUNDCRD_SAMPLE_RATE * \ TIME_AV_AUDIO_SPECT_MS / 1000 / NUM_SMPLS_4_AUDIO_SPECTRUM)) /* Normalization constant for two mixed signals. If this constant is 2, no overrun of the "short" variable can happen but signal has quite much lower power -> compromise */ #define MIX_OUT_CHAN_NORM_CONST ((_REAL) 1.0 / sqrt((_REAL) 2.0)) class CGenSimData : public CTransmitterModul<_BINARY, _BINARY> { public: CGenSimData() : eCntType(CT_TIME), iNumSimBlocks(DEFAULT_NUM_SIM_BLOCKS), iNumErrors(0), iCounter(0), strFileName("SimTime.dat"), tiStartTime(0) {} virtual ~CGenSimData() {} void SetSimTime(int iNewTi, string strNewFileName); void SetNumErrors(int iNewNE, string strNewFileName); protected: enum ECntType {CT_TIME, CT_ERRORS}; ECntType eCntType; int iNumSimBlocks; int iNumErrors; int iCounter; int iMinNumBlocks; string strFileName; time_t tiStartTime; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; /* FAC ---------------------------------------------------------------------- */ class CGenerateFACData : public CTransmitterModul<_BINARY, _BINARY> { public: CGenerateFACData() {} virtual ~CGenerateFACData() {} protected: CFACTransmit FACTransmit; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; /* SDC ---------------------------------------------------------------------- */ class CGenerateSDCData : public CTransmitterModul<_BINARY, _BINARY> { public: CGenerateSDCData() {} virtual ~CGenerateSDCData() {} protected: CSDCTransmit SDCTransmit; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; #endif // !defined(DATA_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/DrmTransmitter.cpp000664 001750 001750 00000020142 12440612574 022263 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use by Ties Bos - PA0MBO * * Description: * DRM-transmitter * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "DrmTransmitter.h" #include "csoundout.h" #include #include "utils/supportfunctions.h" /* Implementation *************************************************************/ void CDRMTransmitter::Start() { TransmParam.bRunThread = true; // Set run flag // Init(); // Initialization of the modules Run(); } void CDRMTransmitter::Stop() { TransmParam.bRunThread = false; } void CDRMTransmitter::Run() { /* The hand over of data is done via an intermediate-buffer. The calling convention is always "input-buffer, output-buffer". Additional, the DRM-parameters are fed to the function */ while (TransmParam.bRunThread) { addToLog("AudioSourceEncoder",LOGDRMTX); AudioSourceEncoder.ProcessData(TransmParam, AudSrcBuf); //arrayBinDump(QString("audiosrc %1").arg(runCounter++),AudSrcBuf,32,true); addToLog("MSCMLCEncoder",LOGPERFORM); MSCMLCEncoder.ProcessData(TransmParam, AudSrcBuf, MLCEncBuf); addToLog("SymbInterleaver",LOGPERFORM); SymbInterleaver.ProcessData(TransmParam, MLCEncBuf, IntlBuf); addToLog("GenerateFACData",LOGPERFORM); GenerateFACData.ReadData(TransmParam, GenFACDataBuf); addToLog("FACMLCEncoder",LOGPERFORM); FACMLCEncoder.ProcessData(TransmParam, GenFACDataBuf, FACMapBuf); addToLog("OFDMCellMapping",LOGPERFORM); OFDMCellMapping.ProcessData(TransmParam, IntlBuf, FACMapBuf, CarMapBuf); addToLog("OFDMModulation",LOGPERFORM); OFDMModulation.ProcessData(TransmParam, CarMapBuf, OFDMModBuf); addToLog("TransmitData",LOGPERFORM); TransmitData.WriteData(TransmParam, OFDMModBuf); // arrayComplexDump(QString("cd "),OFDMModBuf.getVecBuffer(),8,true); if (stopDRM) { TransmParam.bRunThread=false; addToLog("stopping drm",LOGPERFORM); } } } void CDRMTransmitter::Init() { int PacLen, nr_decoded_bits ; // added pa0mbo OFDMCellMapping.Init(TransmParam, CarMapBuf); // Defines number of cells, important! // SDCMLCEncoder.Init(TransmParam, SDCMapBuf); // Defines number of SDC bits per super-frame MSCMLCEncoder.Init(TransmParam, MLCEncBuf); nr_decoded_bits = TransmParam.iNumDecodedBitsMSC ; PacLen = (nr_decoded_bits/8) - 3 ; // printf("PacLen is %d\n", PacLen); TransmParam.Service[0].DataParam.iPacketLen=PacLen; // added Oct 19th 2011 pa0mbo TransmParam.iNumAudioService=0; TransmParam.iNumDataService =1 ; TransmParam.Service[0].eAudDataFlag = CService::SF_DATA; TransmParam.Service[0].DataParam.iStreamID = 0; TransmParam.Service[0].DataParam.eDataUnitInd = CDataParam::DU_DATA_UNITS; TransmParam.Service[0].DataParam.eAppDomain = CDataParam::AD_DAB_SPEC_APP; // end added block SymbInterleaver.Init(TransmParam, IntlBuf); GenerateFACData.Init(TransmParam, GenFACDataBuf); FACMLCEncoder.Init(TransmParam, FACMapBuf); OFDMModulation.Init(TransmParam, OFDMModBuf); AudioSourceEncoder.Init(TransmParam, AudSrcBuf); TransmitData.Init(TransmParam); } CDRMTransmitter::CDRMTransmitter() : pSoundOutInterface(new CSoundOut), TransmitData(pSoundOutInterface), // UEP only works with Dream receiver, FIXME! -> disabled for now bUseUEP(false) { } void CDRMTransmitter::init_base() { TransmParam.init(); /* Init streams */ TransmParam.ResetServicesStreams(); /* Init frame ID counter (index) */ TransmParam.iFrameIDTransm = 0; /* Date, time. TODO: use computer system time... */ TransmParam.iDay = 0; TransmParam.iMonth = 0; TransmParam.iYear = 0; TransmParam.iUTCHour = 0; TransmParam.iUTCMin = 0; /**************************************************************************/ /* Robustness mode and spectrum occupancy. Available transmission modes: RM_ROBUSTNESS_MODE_A: Gaussian channels, with minor fading, RM_ROBUSTNESS_MODE_B: Time and frequency selective channels, with longer delay spread, RM_ROBUSTNESS_MODE_C: As robustness mode B, but with higher Doppler spread, RM_ROBUSTNESS_MODE_D: As robustness mode B, but with severe delay and Doppler spread. Available bandwidths: SO_0: 4.5 kHz, SO_1: 5 kHz, SO_2: 9 kHz, SO_3: 10 kHz, SO_4: 18 kHz, SO_5: 20 kHz PA0MBO: for ham use now only modes A, B and E */ TransmParam.InitCellMapTable(RM_ROBUSTNESS_MODE_E, SO_1); // was B pa0mbo 21-10-2011 /* Protection levels for MSC. Depend on the modulation scheme. Look at TableMLC.h, iCodRateCombMSC16SM, iCodRateCombMSC64SM, iCodRateCombMSC64HMsym, iCodRateCombMSC64HMmix for available numbers */ TransmParam.MSCPrLe.iPartA = 0; TransmParam.MSCPrLe.iPartB = 0; TransmParam.MSCPrLe.iHierarch = 0; /* Either one audio or one data service can be chosen */ // _BOOLEAN bIsAudio = false; CService Service; /* In the current version only one service and one stream is supported. The stream IDs must be 0 in both cases */ /* Data Service only, no Audio*/ TransmParam.SetNumOfServices(0,1); TransmParam.SetCurSelDataService(0); TransmParam.SetAudDataFlag(0, CService::SF_DATA); CDataParam DataParam; DataParam.iStreamID = 0; /* Init SlideShow application */ DataParam.iPacketLen = 45; /* TEST */ DataParam.eDataUnitInd = CDataParam::DU_DATA_UNITS; DataParam.eAppDomain = CDataParam::AD_DAB_SPEC_APP; TransmParam.SetDataParam(0, DataParam); /* The value 0 indicates that the application details are provided solely by SDC data entity type 5 */ Service.iServiceDescr = 0; /* Init service parameters, 24 bit unsigned integer number */ Service.iServiceID = 0; // Service label data. Up to 16 bytes defining the label using UTF-8 coding Service.strLabel = "MYCALL"; /* Language (see TableFAC.h, "strTableLanguageCode[]") */ Service.iLanguage = 5; /* 5 -> english */ TransmParam.SetServiceParameters(0, Service); /* Interleaver mode of MSC service. Long interleaving (2 s): SI_LONG, short interleaving (400 ms): SI_SHORT */ TransmParam.eSymbolInterlMode = CParameter::SI_LONG; /* MSC modulation scheme. Available modes: 16-QAM standard mapping (SM): CS_2_SM, 64-QAM standard mapping (SM): CS_3_SM, 64-QAM symmetrical hierarchical mapping (HMsym): CS_3_HMSYM, 64-QAM mixture of the previous two mappings (HMmix): CS_3_HMMIX */ TransmParam.eMSCCodingScheme = CS_2_SM; // was CS_3_SM pa0mbo 21-11-2011 /* SDC modulation scheme. Available modes: 4-QAM standard mapping (SM): CS_1_SM, 16-QAM standard mapping (SM): CS_2_SM */ // TransmParam.eSDCCodingScheme = CS_2_SM; pa0mbo /* Set desired intermedia frequency (IF) in Hertz */ SetCarOffset(350.0); /* Default: "VIRTUAL_INTERMED_FREQ" was 12000.0 pa0mbo */ rDefCarOffset=(_REAL) VIRTUAL_INTERMED_FREQ; if (bUseUEP == true) { // TEST TransmParam.SetStreamLen(0, 80, 0); } else { /* Length of part B is set automatically (equal error protection (EEP), if "= 0"). Sets the number of bytes, should not exceed total number of bytes available in MSC block */ TransmParam.SetStreamLen(0, 0, 0); } } qsstv_8.2.12/qsstv/drmtx/common/DrmTransmitter.h000664 001750 001750 00000007312 12440612574 021734 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See DrmTransmitter.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DRMTRANSM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define DRMTRANSM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include #include "util/Buffer.h" #include "Parameter.h" #include "DataIO.h" #include "mlc/MLC.h" #include "interleaver/SymbolInterleaver.h" #include "ofdmcellmapping/OFDMCellMapping.h" #include "OFDM.h" #include "DRMSignalIO.h" #include "sourcedecoders/AudioSourceDecoder.h" #include "soundinterface.h" /* Classes ********************************************************************/ class CDRMTransmitter { public: CDRMTransmitter(); virtual ~CDRMTransmitter() {} void Init(); void init_base(); void Start(); void Stop(); /* Get pointer to internal modules */ // CSoundInInterface* GetSoundInInterface() {return pSoundInInterface;} CSoundOutInterface* GetSoundOutInterface() {return pSoundOutInterface;} CAudioSourceEncoder* GetAudSrcEnc() {return &AudioSourceEncoder;} CTransmitData* GetTransData() {return &TransmitData;} // CReadData* GetReadData() {return &ReadData;} CParameter* GetParameters() {return &TransmParam;} void SetCarOffset(const _REAL rNewCarOffset) { /* Has to be set in OFDM modulation and transmitter filter module */ OFDMModulation.SetCarOffset(rNewCarOffset); TransmitData.SetCarOffset(rNewCarOffset); rDefCarOffset = rNewCarOffset; } _REAL GetCarOffset() {return rDefCarOffset;} protected: void Run(); /* Parameters */ CParameter TransmParam; /* Buffers */ CSingleBuffer<_SAMPLE> DataBuf; CSingleBuffer<_BINARY> AudSrcBuf; CSingleBuffer<_COMPLEX> MLCEncBuf; CCyclicBuffer<_COMPLEX> IntlBuf; CSingleBuffer<_BINARY> GenFACDataBuf; CCyclicBuffer<_COMPLEX> FACMapBuf; CSingleBuffer<_BINARY> GenSDCDataBuf; CCyclicBuffer<_COMPLEX> SDCMapBuf; CSingleBuffer<_COMPLEX> CarMapBuf; CSingleBuffer<_COMPLEX> OFDMModBuf; // CSoundInInterface* pSoundInInterface; CSoundOutInterface* pSoundOutInterface; /* Modules */ // CReadData ReadData; CAudioSourceEncoder AudioSourceEncoder; CMSCMLCEncoder MSCMLCEncoder; CSymbInterleaver SymbInterleaver; CGenerateFACData GenerateFACData; CFACMLCEncoder FACMLCEncoder; CGenerateSDCData GenerateSDCData; CSDCMLCEncoder SDCMLCEncoder; COFDMCellMapping OFDMCellMapping; COFDMModulation OFDMModulation; CTransmitData TransmitData; _REAL rDefCarOffset; _BOOLEAN bUseUEP; }; #define BWs 2 #define MODES 3 #define PROTECTIONS 2 #define QAMS 3 extern int partTable[BWs][MODES][PROTECTIONS][QAMS]; #endif // !defined(DRMTRANSM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/GlobalDefinitions.h000664 001750 001750 00000021363 12440612574 022353 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001-2006 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBo * * Description: * Global definitions * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(DEF_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define DEF_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "qsstvglobal.h" #include "qsstvdefs.h" #include #include #include #include "../config.h" #include "tables/TableDRMGlobal.h" /* Definitions ****************************************************************/ /* When you define the following flag, a directory called "test" MUST EXIST in the windows directory (or linux directory if you use Linux)! */ #define _DEBUG_ #undef _DEBUG_ /* Choose algorithms -------------------------------------------------------- */ /* There are two algorithms available for frequency offset estimation for tracking mode: Using frequency pilots or the guard-interval correlation. In case of guard-interval correlation (which will be chosen if this macro is defined), the Hilbert filter in TimeSync must be used all the time -> more CPU usage. Also, the frequency tracking range is smaller */ #undef USE_FRQOFFS_TRACK_GUARDCORR /* The sample rate offset estimation can be done using the frequency pilots or the movement of the estimated impulse response. Defining this macro will enable the frequency pilot based estimation. Simulations showed that this method is more vulnerable to bad channel situations */ #undef USE_SAMOFFS_TRACK_FRE_PIL /* Using max-log MAP decoder. A lot more memory and CPU is needed for this method. This is just for showing the potential of an improved decoding method and should not be activated for the "regular" version of Dream */ #undef USE_MAX_LOG_MAP /* This method tries to speed up the audio output after a re-synchronization when long symbol interleaver is used. We work with erasure symbols to mark data which is not yet received. We hope that the channel decoder can still decode audio even if not all data is yet received to fill the interleaver history */ #define USE_ERASURE_FOR_FASTER_ACQ /* If the following macro is defined, the Wiener filter for channel estimation in time direction will be a Decision-Directed channel estimation -> additional to the actual pilot cells, hard decisions about the data cells are used as new pilots, too */ #undef USE_DD_WIENER_FILT_TIME #if HAVE_STDINT_H # include #elif HAVE_INTTYPES_H # include #elif defined(_WIN32) # ifndef HAVE_INT8_T # define HAVE_INT8_T 1 typedef signed char int8_t; # endif # ifndef HAVE_INT16_T # define HAVE_INT16_T 1 typedef signed __int16 int16_t; # endif # ifndef HAVE_INT32_T # define HAVE_INT32_T 1 typedef signed __int32 int32_t; # endif typedef unsigned char uint8_t; # ifndef HAVE_U_INT16_T # define HAVE_U_INT16_T 1 typedef unsigned __int16 uint16_t; # endif # ifndef HAVE_U_INT32_T # define HAVE_U_INT32_T 1 typedef unsigned __int32 uint32_t; # endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed int int16_t; typedef unsigned int uint16_t; typedef signed long int32_t; typedef unsigned long uint32_t; typedef signed long long int64_t; typedef unsigned long long uint64_t; #endif /* Define type-specific information */ #define SIZEOF__BYTE 8 #define _MAXSHORT 32767 #define _MAXREAL ((_REAL) 3.4e38) /* Max for float */ #ifdef USE_ERASURE_FOR_FASTER_ACQ /* Use max-value for showing that this is an erasure */ # define ERASURE_TAG_VALUE _MAXREAL #endif /* MAP ---------------------------------------------------------------------- */ #ifdef USE_MAX_LOG_MAP typedef _REAL _DECISION; # define ML_SOFT_INF_MAX_VALUE ((_DECISION) 1e10) inline _BINARY ExtractBit(_DECISION dD) {return dD > 0 ? 1 : 0;} inline _DECISION BitToSoft(_BINARY biB) {return biB == 0 ? -1.0 : 1.0;} #else typedef _BINARY _DECISION; #define ExtractBit(a) (a) #define BitToSoft(a) (a) #endif /* Definitions for window message system ------------------------------------ */ typedef unsigned int _MESSAGE_IDENT; #define MS_FAC_CRC 1 /* MS: Message */ #define MS_SDC_CRC 2 #define MS_MSC_CRC 3 #define MS_FRAME_SYNC 4 #define MS_TIME_SYNC 5 #define MS_IOINTERFACE 6 #define MS_RESET_ALL 7 #define MS_MOT_OBJ_STAT 8 #define GUI_CONTROL_UPDATE_TIME 500 /* Milliseconds */ #define GUI_CONTROL_UPDATE_TIME_FAST 250 /* Milliseconds */ /* Global enumerations ------------------------------------------------------ */ enum ESpecOcc {SO_0, SO_1, SO_2, SO_3, SO_4, SO_5}; /* SO: Spectrum Occupancy */ enum ERobMode {RM_ROBUSTNESS_MODE_A, RM_ROBUSTNESS_MODE_B, RM_ROBUSTNESS_MODE_E, RM_ROBUSTNESS_MODE_D, // pa0mbo was MODE_D RM_NO_MODE_DETECTED}; /* RM: Robustness Mode */ /* Constants ---------------------------------------------------------------- */ const _REAL crPi = ((_REAL) 3.14159265358979323846); #define S9_DBUV 34.0 /* S9 in dBuV for converting HamLib S-meter readings to RSCI format */ /* Define a number for the case: log10(0), which would lead to #inf */ #define RET_VAL_LOG_0 ((_REAL) -200.0) ///* Standard definitions */ //#define true 1 //#define false 0 /* Classes ********************************************************************/ /* For metric */ class CDistance { public: /* Distance towards 0 or towards 1 */ _REAL rTow0; _REAL rTow1; }; /* Viterbi needs information of equalized received signal and channel */ class CEquSig { public: CEquSig() : cSig(_COMPLEX((_REAL) 0.0, (_REAL) 0.0)), rChan((_REAL) 0.0) {} CEquSig(const _COMPLEX cNS, const _REAL rNC) : cSig(cNS), rChan(rNC) {} _COMPLEX cSig; /* Actual signal */ _REAL rChan; /* Channel power at this cell */ }; /* Mutex object to access data safely from different threads */ /* QT mutex */ #ifdef USE_QT_GUI # if #if (QT_VERSION >= QT_VERSION_CHECK(3, 0, 0)) # include # else # include # endif class CMutex { public: void Lock() {Mutex.lock();} void Unlock() {Mutex.unlock();} protected: QMutex Mutex; }; #else /* No GUI and no threads, we do not need mutex in this case */ class CMutex { public: void Lock() {} void Unlock() {} }; #endif class CGenErr { public: CGenErr(string strNE) : strError(strNE) {} string strError; }; // FIXME something nicer than using "MAX_NUM_TAPS_DRM_CHAN" /* For simulation, data from channel simulation */ #define MAX_NUM_TAPS_DRM_CHAN 4 template class CChanSimData { public: T tIn; /* Channel input data */ T tOut; /* Output of the channel (with noise) */ T tRef; /* Channel reference signal (without noise) */ _COMPLEX veccTap[MAX_NUM_TAPS_DRM_CHAN]; /* Tap gains */ _COMPLEX veccTapBackw[MAX_NUM_TAPS_DRM_CHAN]; }; typedef CChanSimData<_REAL> CChanSimDataMod; /* OFDM modulated signals */ typedef CChanSimData<_COMPLEX> CChanSimDataDemod; /* Demodulated signals */ /* Path for simulation output and status files */ #define SIM_OUT_FILES_PATH "test/" /* Prototypes for global functions ********************************************/ /* Posting a window message */ //void PostWinMessage(const _MESSAGE_IDENT MessID, const int iMessageParam = 0); /* Debug error handling */ void DebugError(const char* pchErDescr, const char* pchPar1Descr, const double dPar1, const char* pchPar2Descr, const double dPar2); void ErrorMessage(string strErrorString); /* Global functions ***********************************************************/ /* Converting _REAL to _SAMPLE */ inline _SAMPLE Real2Sample(const _REAL rInput) { /* Lower bound */ if (rInput < -_MAXSHORT) return -_MAXSHORT; /* Upper bound */ if (rInput > _MAXSHORT) return _MAXSHORT; return (_SAMPLE) rInput; } #endif // !defined(DEF_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/OFDM.cpp000664 001750 001750 00000012410 12440612574 020030 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * OFDM modulation; * OFDM demodulation, SNR estimation, PSD estimation * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "OFDM.h" /* Implementation *************************************************************/ /******************************************************************************\ * OFDM-modulation * \******************************************************************************/ void COFDMModulation::ProcessDataInternal(CParameter&) { int i; // printf("In COFDMModul iShiftKmin %d iEndIndex %d , iDFTSize %d iGuardSize %d\n", // iShiftedKmin, iEndIndex, iDFTSize, iGuardSize); /* Copy input vector in matlib vector and place bins at the correct position */ for (i = iShiftedKmin; i < iEndIndex; i++) { // veccFFTInput[150] = _COMPLEX((_REAL) 1.0, (_REAL) -1.0); // test pa0mbo veccFFTInput[i] = (*pvecInputData)[i - iShiftedKmin]; // veccFFTInput[iDFTSize -1 - i] = Conj((*pvecInputData)[i - iShiftedKmin]); // printf(" veccFFTInput %d %g %g\n", i,(veccFFTInput[i]).real(), (veccFFTInput[i]).imag()); } /* Calculate inverse fast Fourier transformation */ veccFFTOutput = Ifft(veccFFTInput, FftPlan); /* Copy complex FFT output in output buffer and scale */ for (i = 0; i < iDFTSize; i++) (*pvecOutputData)[i + iGuardSize] = veccFFTOutput[i] * (CReal) iDFTSize; /* Copy data from the end to the guard-interval (Add guard-interval) */ for (i = 0; i < iGuardSize; i++) (*pvecOutputData)[i] = (*pvecOutputData)[iDFTSize + i]; /* tbv test printout pa0mbo printf("===========\n"); for (i=0; i < iDFTSize + iGuardSize ; i++) printf("%d %g \n",i, ((*pvecOutputData)[i]).real()); printf("=============\n"); */ /* Shift spectrum to desired IF ----------------------------------------- */ /* Only apply shifting if phase is not zero */ if (cExpStep != _COMPLEX((_REAL) 1.0, (_REAL) 0.0)) { for (i = 0; i < iOutputBlockSize; i++) { (*pvecOutputData)[i] = (*pvecOutputData)[i] * Conj(cCurExp); // pa0mbo shift off /* Rotate exp-pointer on step further by complex multiplication with precalculated rotation vector cExpStep. This saves us from calling sin() and cos() functions all the time (iterative calculation of these functions) */ cCurExp *= cExpStep; } } } void COFDMModulation::InitInternal(CParameter& TransmParam) { TransmParam.Lock(); /* Get global parameters */ iDFTSize = TransmParam.CellMappingTable.iFFTSizeN; iGuardSize = TransmParam.CellMappingTable.iGuardSize; iShiftedKmin = TransmParam.CellMappingTable.iShiftedKmin; /* Last index */ iEndIndex = TransmParam.CellMappingTable.iShiftedKmax + 1; /* Normalized offset correction factor for IF shift. Subtract the default IF frequency ("VIRTUAL_INTERMED_FREQ") */ const _REAL rNormCurFreqOffset = (_REAL) -2.0 * crPi * // ((_REAL ) -6751.0)/ SOUNDCRD_SAMPLE_RATE; (rDefCarOffset - VIRTUAL_INTERMED_FREQ) / SOUNDCRD_SAMPLE_RATE; // printf("COFDMMod rDefCarOffset %g Virt IF %g rNormCurFreqoffset %g \n", rDefCarOffset, (_REAL) VIRTUAL_INTERMED_FREQ, rNormCurFreqOffset); /* Rotation vector for exp() calculation */ cExpStep = _COMPLEX(cos(rNormCurFreqOffset), sin(rNormCurFreqOffset)); // printf("COFDMMod cExpStep real %g imag %g \n", cos(rNormCurFreqOffset), sin(rNormCurFreqOffset)); /* Start with phase null (can be arbitrarily chosen) */ cCurExp = (_REAL) 1.0; /* Init plans for FFT (faster processing of Fft and Ifft commands) */ FftPlan.Init(iDFTSize); // printf("In FftPlan.Init iDFTSize is %d \n", iDFTSize); /* Allocate memory for intermediate result of fft. Zero out input vector (because only a few bins are used, the rest has to be zero) */ veccFFTInput.Init(iDFTSize, (CReal) 0.0); veccFFTOutput.Init(iDFTSize); /* Define block-sizes for input and output */ iInputBlockSize = TransmParam.CellMappingTable.iNumCarrier; iOutputBlockSize = TransmParam.CellMappingTable.iSymbolBlockSize; // printf("In COFDMMOd init DFTsize %d Guardsize %d ShiftedKmin %d \n", iDFTSize, iGuardSize, iShiftedKmin); // printf("In COFDMMOd init Inputblcksize %d Outputblocksize %d \n", iInputBlockSize, iOutputBlockSize); TransmParam.Unlock(); } qsstv_8.2.12/qsstv/drmtx/common/OFDM.h000664 001750 001750 00000004436 12440612574 017506 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * See OFDM.cpp * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(OFDM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define OFDM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "Parameter.h" #include "util/Modul.h" #include "matlib/Matlib.h" /* Definitions ****************************************************************/ /* Time constant for IIR averaging of PSD estimation */ #define TICONST_PSD_EST_OFDM ((CReal) 1.0) /* sec */ /* Classes ********************************************************************/ class COFDMModulation : public CTransmitterModul<_COMPLEX, _COMPLEX> { public: COFDMModulation() : rDefCarOffset((_REAL) VIRTUAL_INTERMED_FREQ) {} virtual ~COFDMModulation() {} void SetCarOffset(const _REAL rNewCarOffset) {rDefCarOffset = rNewCarOffset;} protected: CFftPlans FftPlan; CComplexVector veccFFTInput; CComplexVector veccFFTOutput; int iShiftedKmin; int iEndIndex; int iDFTSize; int iGuardSize; _COMPLEX cCurExp; _COMPLEX cExpStep; _REAL rDefCarOffset; virtual void InitInternal(CParameter& TransmParam); virtual void ProcessDataInternal(CParameter& TransmParam); }; #endif // !defined(OFDM_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/Parameter.cpp000664 001750 001750 00000101715 12440612574 021232 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2007 * * Author(s): * Volker Fischer, Andrew Murphy * * Adapter for ham sstv use Ties Bos - PA0MBO * * Description: * DRM Parameters * ****************************************************************************** * * This program is free software(), you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation(), either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY(), without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program(), if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "Parameter.h" //#include "DrmReceiver.h" #include #include #include //#include "util/LogPrint.h" /* Implementation *************************************************************/ CParameter::CParameter(): // pDRMRec(pRx), Stream(MAX_NUM_STREAMS), Service(MAX_NUM_SERVICES), iNumAudioFrames(0), vecbiAudioFrameStatus(0), bMeasurePSD(), vecrPSD(0), matcReceivedPilotValues(), RawSimDa(), eSimType(ST_NONE), iDRMChannelNum(0), iSpecChDoppler(0), rBitErrRate(0.0), rSyncTestParam(0.0), rSINR(0.0), iNumBitErrors(0), iChanEstDelay(0), iNumTaps(0), iPathDelay(MAX_NUM_TAPS_DRM_CHAN), rGainCorr(0.0), iOffUsfExtr(0), ReceiveStatus(), FrontEndParameters(), AltFreqSign(), rMER(0.0), rWMERMSC(0.0), rWMERFAC(0.0), rSigmaEstimate(0.0), rMinDelay(0.0), rMaxDelay(0.0), bMeasureDelay(), vecrRdel(0), vecrRdelThresholds(0), vecrRdelIntervals(0), bMeasureDoppler(0), rRdop(0.0), bMeasureInterference(false), rIntFreq(0.0), rINR(0.0), rICR(0.0), rMaxPSDwrtSig(0.0), rMaxPSDFreq(0.0), rSigStrengthCorrection(0.0), bRunThread(false), bUsingMultimedia(false), CellMappingTable(), rSysSimSNRdB(0.0), iFrequency(0), bValidSignalStrength(false), rSigStr(0.0), rIFSigStr(0.0), iCurSelAudioService(0), iCurSelDataService(0), eRobustnessMode(RM_ROBUSTNESS_MODE_B), eSpectOccup(SO_3), LastAudioService(), LastDataService(), Mutex() { init(); GenerateRandomSerialNumber(); CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); } void CParameter::init() { eSymbolInterlMode=SI_LONG; eMSCCodingScheme=CS_1_SM; eSDCCodingScheme=CS_1_SM; iNumAudioService=0; iNumDataService=0; iAMSSCarrierMode=0; sReceiverID=" "; sSerialNumber=""; sDataFilesDirectory="."; MSCPrLe.init(); iNumBitsHierarchFrameTotal=0; iNumDecodedBitsMSC=0; iNumSDCBitsPerSFrame=0; iNumAudioDecoderBits=0; iNumDataDecoderBits=0; iYear=0; iMonth=0; iDay=0; iUTCHour=0; iUTCMin=0; iFrameIDTransm=0; iFrameIDReceiv=0; rFreqOffsetAcqui=0.0; rFreqOffsetTrack=0.0; rResampleOffset=0.0; iTimingOffsTrack=0; eReceiverMode=RM_NONE; eAcquiState=AS_NO_SIGNAL; } CParameter::~CParameter() { } CParameter::CParameter(const CParameter& p): // pDRMRec(p.pDRMRec), eSymbolInterlMode(p.eSymbolInterlMode), eMSCCodingScheme(p.eMSCCodingScheme), eSDCCodingScheme(p.eSDCCodingScheme), iNumAudioService(p.iNumAudioService), iNumDataService(p.iNumDataService), iAMSSCarrierMode(p.iAMSSCarrierMode), sReceiverID(p.sReceiverID), sSerialNumber(p.sSerialNumber), sDataFilesDirectory(p.sDataFilesDirectory), MSCPrLe(p.MSCPrLe), Stream(p.Stream), Service(p.Service), iNumBitsHierarchFrameTotal(p.iNumBitsHierarchFrameTotal), iNumDecodedBitsMSC(p.iNumDecodedBitsMSC), iNumSDCBitsPerSFrame(p.iNumSDCBitsPerSFrame), iNumAudioDecoderBits(p.iNumAudioDecoderBits), iNumDataDecoderBits(p.iNumDataDecoderBits), iYear(p.iYear), iMonth(p.iMonth), iDay(p.iDay), iUTCHour(p.iUTCHour), iUTCMin(p.iUTCMin), iFrameIDTransm(p.iFrameIDTransm), iFrameIDReceiv(p.iFrameIDReceiv), rFreqOffsetAcqui(p.rFreqOffsetAcqui), rFreqOffsetTrack(p.rFreqOffsetTrack), rResampleOffset(p.rResampleOffset), iTimingOffsTrack(p.iTimingOffsTrack), eReceiverMode(p.eReceiverMode), eAcquiState(p.eAcquiState), iNumAudioFrames(p.iNumAudioFrames), vecbiAudioFrameStatus(p.vecbiAudioFrameStatus), bMeasurePSD(p.bMeasurePSD), vecrPSD(p.vecrPSD), //matcReceivedPilotValues(p.matcReceivedPilotValues), matcReceivedPilotValues(), // OPH says copy constructor for CMatrix not safe yet RawSimDa(p.RawSimDa), eSimType(p.eSimType), iDRMChannelNum(p.iDRMChannelNum), iSpecChDoppler(p.iSpecChDoppler), rBitErrRate(p.rBitErrRate), rSyncTestParam (p.rSyncTestParam), rSINR(p.rSINR), iNumBitErrors(p.iNumBitErrors), iChanEstDelay(p.iChanEstDelay), iNumTaps(p.iNumTaps), iPathDelay(p.iPathDelay), rGainCorr(p.rGainCorr), iOffUsfExtr(p.iOffUsfExtr), ReceiveStatus(p.ReceiveStatus), FrontEndParameters(p.FrontEndParameters), AltFreqSign(p.AltFreqSign), rMER(p.rMER), rWMERMSC(p.rWMERMSC), rWMERFAC(p.rWMERFAC), rSigmaEstimate(p.rSigmaEstimate), rMinDelay(p.rMinDelay), rMaxDelay(p.rMaxDelay), bMeasureDelay(p.bMeasureDelay), vecrRdel(p.vecrRdel), vecrRdelThresholds(p.vecrRdelThresholds), vecrRdelIntervals(p.vecrRdelIntervals), bMeasureDoppler(p.bMeasureDoppler), rRdop(p.rRdop), bMeasureInterference(p.bMeasureInterference), rIntFreq(p.rIntFreq), rINR(p.rINR), rICR(p.rICR), rMaxPSDwrtSig(p.rMaxPSDwrtSig), rMaxPSDFreq(p.rMaxPSDFreq), rSigStrengthCorrection(p.rSigStrengthCorrection), bRunThread(p.bRunThread), bUsingMultimedia(p.bUsingMultimedia), CellMappingTable(), // jfbc CCellMappingTable uses a CMatrix :( // GPSData(p.GPSData), rSysSimSNRdB(p.rSysSimSNRdB), iFrequency(p.iFrequency), bValidSignalStrength(p.bValidSignalStrength), rSigStr(p.rSigStr), rIFSigStr(p.rIFSigStr), iCurSelAudioService(p.iCurSelAudioService), iCurSelDataService(p.iCurSelDataService), eRobustnessMode(p.eRobustnessMode), eSpectOccup(p.eSpectOccup), LastAudioService(p.LastAudioService), LastDataService(p.LastDataService) //, Mutex() // jfbc: I don't think this state should be copied { CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); matcReceivedPilotValues = p.matcReceivedPilotValues; // TODO } CParameter& CParameter::operator=(const CParameter& p) { // pDRMRec = p.pDRMRec; eSymbolInterlMode = p.eSymbolInterlMode; eMSCCodingScheme = p.eMSCCodingScheme; eSDCCodingScheme = p.eSDCCodingScheme; iNumAudioService = p.iNumAudioService; iNumDataService = p.iNumDataService; iAMSSCarrierMode = p.iAMSSCarrierMode; sReceiverID = p.sReceiverID; sSerialNumber = p.sSerialNumber; sDataFilesDirectory = p.sDataFilesDirectory; MSCPrLe = p.MSCPrLe; Stream = p.Stream; Service = p.Service; iNumBitsHierarchFrameTotal = p.iNumBitsHierarchFrameTotal; iNumDecodedBitsMSC = p.iNumDecodedBitsMSC; iNumSDCBitsPerSFrame = p.iNumSDCBitsPerSFrame; iNumAudioDecoderBits = p.iNumAudioDecoderBits; iNumDataDecoderBits = p.iNumDataDecoderBits; iYear = p.iYear; iMonth = p.iMonth; iDay = p.iDay; iUTCHour = p.iUTCHour; iUTCMin = p.iUTCMin; iFrameIDTransm = p.iFrameIDTransm; iFrameIDReceiv = p.iFrameIDReceiv; rFreqOffsetAcqui = p.rFreqOffsetAcqui; rFreqOffsetTrack = p.rFreqOffsetTrack; rResampleOffset = p.rResampleOffset; iTimingOffsTrack = p.iTimingOffsTrack; eReceiverMode = p.eReceiverMode; eAcquiState = p.eAcquiState; iNumAudioFrames = p.iNumAudioFrames; vecbiAudioFrameStatus = p.vecbiAudioFrameStatus; bMeasurePSD = p.bMeasurePSD; vecrPSD = p.vecrPSD; matcReceivedPilotValues = p.matcReceivedPilotValues; RawSimDa = p.RawSimDa; eSimType = p.eSimType; iDRMChannelNum = p.iDRMChannelNum; iSpecChDoppler = p.iSpecChDoppler; rBitErrRate = p.rBitErrRate; rSyncTestParam = p.rSyncTestParam; rSINR = p.rSINR; iNumBitErrors = p.iNumBitErrors; iChanEstDelay = p.iChanEstDelay; iNumTaps = p.iNumTaps; iPathDelay = p.iPathDelay; rGainCorr = p.rGainCorr; iOffUsfExtr = p.iOffUsfExtr; ReceiveStatus = p.ReceiveStatus; FrontEndParameters = p.FrontEndParameters; AltFreqSign = p.AltFreqSign; rMER = p.rMER; rWMERMSC = p.rWMERMSC; rWMERFAC = p.rWMERFAC; rSigmaEstimate = p.rSigmaEstimate; rMinDelay = p.rMinDelay; rMaxDelay = p.rMaxDelay; bMeasureDelay = p.bMeasureDelay; vecrRdel = p.vecrRdel; vecrRdelThresholds = p.vecrRdelThresholds; vecrRdelIntervals = p.vecrRdelIntervals; bMeasureDoppler = p.bMeasureDoppler; rRdop = p.rRdop; bMeasureInterference = p.bMeasureInterference; rIntFreq = p.rIntFreq; rINR = p.rINR; rICR = p.rICR; rMaxPSDwrtSig = p.rMaxPSDwrtSig; rMaxPSDFreq = p.rMaxPSDFreq; rSigStrengthCorrection = p.rSigStrengthCorrection; bRunThread = p.bRunThread; bUsingMultimedia = p.bUsingMultimedia; CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); // don't copy CMatrix // GPSData = p.GPSData; rSysSimSNRdB = p.rSysSimSNRdB; iFrequency = p.iFrequency; bValidSignalStrength = p.bValidSignalStrength; rSigStr = p.rSigStr; rIFSigStr = p.rIFSigStr; iCurSelAudioService = p.iCurSelAudioService; iCurSelDataService = p.iCurSelDataService; eRobustnessMode = p.eRobustnessMode; eSpectOccup = p.eSpectOccup; LastAudioService = p.LastAudioService; LastDataService = p.LastDataService; return *this; } void CParameter::ResetServicesStreams() { int i; if(GetReceiverMode() == RM_DRM) { /* Store informations about last services selected * this for select current service automatically after a resync */ if (iCurSelAudioService > 0) LastAudioService.Save(iCurSelAudioService, Service[iCurSelAudioService].iServiceID); if (iCurSelDataService > 0) LastDataService.Save(iCurSelDataService, Service[iCurSelDataService].iServiceID); /* Reset everything to possible start values */ for (i = 0; i < MAX_NUM_SERVICES; i++) { Service[i].AudioParam.strTextMessage = ""; Service[i].AudioParam.iStreamID = STREAM_ID_NOT_USED; Service[i].AudioParam.eAudioCoding = CAudioParam::AC_AAC; Service[i].AudioParam.eSBRFlag = CAudioParam::SB_NOT_USED; Service[i].AudioParam.eAudioSamplRate = CAudioParam::AS_24KHZ; Service[i].AudioParam.bTextflag = false; Service[i].AudioParam.bEnhanceFlag = false; Service[i].AudioParam.eAudioMode = CAudioParam::AM_MONO; Service[i].AudioParam.iCELPIndex = 0; Service[i].AudioParam.bCELPCRC = false; Service[i].AudioParam.eHVXCRate = CAudioParam::HR_2_KBIT; Service[i].AudioParam.bHVXCCRC = false; Service[i].DataParam.iStreamID = STREAM_ID_NOT_USED; Service[i].DataParam.ePacketModInd = CDataParam::PM_PACKET_MODE; Service[i].DataParam.eDataUnitInd = CDataParam::DU_SINGLE_PACKETS; Service[i].DataParam.iPacketID = 0; Service[i].DataParam.iPacketLen = 0; Service[i].DataParam.eAppDomain = CDataParam::AD_DRM_SPEC_APP; Service[i].DataParam.iUserAppIdent = 0; Service[i].iServiceID = SERV_ID_NOT_USED; Service[i].eCAIndication = CService::CA_NOT_USED; Service[i].iLanguage = 0; Service[i].strCountryCode = ""; Service[i].strLanguageCode = ""; Service[i].eAudDataFlag = CService::SF_AUDIO; Service[i].iServiceDescr = 0; Service[i].strLabel = ""; } for (i = 0; i < MAX_NUM_STREAMS; i++) { Stream[i].iLenPartA = 0; Stream[i].iLenPartB = 0; } } else { // Set up encoded AM audio parameters Service[0].AudioParam.strTextMessage = ""; Service[0].AudioParam.iStreamID = 0; Service[0].AudioParam.eAudioCoding = CAudioParam::AC_AAC; Service[0].AudioParam.eSBRFlag = CAudioParam::SB_NOT_USED; Service[0].AudioParam.eAudioSamplRate = CAudioParam::AS_24KHZ; Service[0].AudioParam.bTextflag = false; Service[0].AudioParam.bEnhanceFlag = false; Service[0].AudioParam.eAudioMode = CAudioParam::AM_MONO; Service[0].AudioParam.iCELPIndex = 0; Service[0].AudioParam.bCELPCRC = false; Service[0].AudioParam.eHVXCRate = CAudioParam::HR_2_KBIT; Service[0].AudioParam.bHVXCCRC = false; Service[0].iServiceID = SERV_ID_NOT_USED; Service[0].eCAIndication = CService::CA_NOT_USED; Service[0].iLanguage = 0; Service[0].strCountryCode = ""; Service[0].strLanguageCode = ""; Service[0].eAudDataFlag = CService::SF_AUDIO; Service[0].iServiceDescr = 0; Service[0].strLabel = ""; Stream[0].iLenPartA = 0; Stream[0].iLenPartB = 1044; } /* Reset alternative frequencies */ AltFreqSign.Reset(); /* Date, time */ iDay = 0; iMonth = 0; iYear = 0; iUTCHour = 0; iUTCMin = 0; } void CParameter::GetActiveServices(set& actServ) { /* Init return vector */ actServ.clear(); /* Get active services */ for (int i = 0; i < MAX_NUM_SERVICES; i++) { if (Service[i].IsActive()) /* A service is active, add ID to set */ actServ.insert(i); } } /* using a set ensures each stream appears only once */ void CParameter::GetActiveStreams(set& actStr) { actStr.clear(); /* Determine which streams are active */ for (int i = 0; i < MAX_NUM_SERVICES; i++) { if (Service[i].IsActive()) { /* Audio stream */ if (Service[i].AudioParam.iStreamID != STREAM_ID_NOT_USED) actStr.insert(Service[i].AudioParam.iStreamID); /* Data stream */ if (Service[i].DataParam.iStreamID != STREAM_ID_NOT_USED) actStr.insert(Service[i].DataParam.iStreamID); } } } _REAL CParameter::GetBitRateKbps(const int iShortID, const _BOOLEAN bAudData) { /* Init lengths to zero in case the stream is not yet assigned */ int iLen = 0; /* First, check if audio or data service and get lengths */ if (Service[iShortID].eAudDataFlag == CService::SF_AUDIO) { /* Check if we want to get the data stream connected to an audio stream */ if (bAudData == true) { iLen = GetStreamLen( Service[iShortID].DataParam.iStreamID); } else { iLen = GetStreamLen( Service[iShortID].AudioParam.iStreamID); } } else { iLen = GetStreamLen( Service[iShortID].DataParam.iStreamID); } /* We have 3 frames with time duration of 1.2 seconds. Bit rate should be returned in kbps (/ 1000) */ return (_REAL) iLen * SIZEOF__BYTE * 3 / (_REAL) 1.2 / 1000; } _REAL CParameter::PartABLenRatio(const int iShortID) { int iLenA = 0; int iLenB = 0; /* Get the length of protection part A and B */ if (Service[iShortID].eAudDataFlag == CService::SF_AUDIO) { /* Audio service */ if (Service[iShortID].AudioParam.iStreamID != STREAM_ID_NOT_USED) { iLenA = Stream[Service[iShortID].AudioParam.iStreamID].iLenPartA; iLenB = Stream[Service[iShortID].AudioParam.iStreamID].iLenPartB; } } else { /* Data service */ if (Service[iShortID].DataParam.iStreamID != STREAM_ID_NOT_USED) { iLenA = Stream[Service[iShortID].DataParam.iStreamID].iLenPartA; iLenB = Stream[Service[iShortID].DataParam.iStreamID].iLenPartB; } } const int iTotLen = iLenA + iLenB; if (iTotLen != 0) return (_REAL) iLenA / iTotLen; else return (_REAL) 0.0; } void CParameter::InitCellMapTable(const ERobMode eNewWaveMode, const ESpecOcc eNewSpecOcc) { /* Set new values and make table */ eRobustnessMode = eNewWaveMode; eSpectOccup = eNewSpecOcc; CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); } _BOOLEAN CParameter::SetWaveMode(const ERobMode eNewWaveMode) { /* First check if spectrum occupancy and robustness mode pair is defined */ if (( (eNewWaveMode == RM_ROBUSTNESS_MODE_E) || (eNewWaveMode == RM_ROBUSTNESS_MODE_D) ) && !( (eSpectOccup == SO_3) || (eSpectOccup == SO_5) )) { /* Set spectrum occupance to a valid parameter */ eSpectOccup = SO_3; } /* Apply changes only if new paramter differs from old one */ if (eRobustnessMode != eNewWaveMode) { /* Set new value */ eRobustnessMode = eNewWaveMode; /* This parameter change provokes update of table */ CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForWaveMode(); /* Signal that parameter has changed */ return true; } else return false; } void CParameter::SetSpectrumOccup(ESpecOcc eNewSpecOcc) { /* First check if spectrum occupancy and robustness mode pair is defined */ if (( (eRobustnessMode == RM_ROBUSTNESS_MODE_E) || (eRobustnessMode == RM_ROBUSTNESS_MODE_D) ) && !( (eNewSpecOcc == SO_3) || (eNewSpecOcc == SO_5) )) { /* Set spectrum occupance to a valid parameter */ eNewSpecOcc = SO_3; } /* Apply changes only if new paramter differs from old one */ if (eSpectOccup != eNewSpecOcc) { /* Set new value */ eSpectOccup = eNewSpecOcc; /* This parameter change provokes update of table */ CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForSpectrumOccup(); } } void CParameter::SetStreamLen(const int iStreamID, const int iNewLenPartA, const int iNewLenPartB) { /* Apply changes only if parameters have changed */ if ((Stream[iStreamID].iLenPartA != iNewLenPartA) || (Stream[iStreamID].iLenPartB != iNewLenPartB)) { /* Use new parameters */ Stream[iStreamID].iLenPartA = iNewLenPartA; Stream[iStreamID].iLenPartB = iNewLenPartB; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSC(); } } int CParameter::GetStreamLen(const int iStreamID) { if(iStreamID != STREAM_ID_NOT_USED) return Stream[iStreamID].iLenPartA + Stream[iStreamID].iLenPartB; else return 0; } void CParameter::SetNumDecodedBitsMSC(const int iNewNumDecodedBitsMSC) { /* Apply changes only if parameters have changed */ if (iNewNumDecodedBitsMSC != iNumDecodedBitsMSC) { iNumDecodedBitsMSC = iNewNumDecodedBitsMSC; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSCDemux(); } } void CParameter::SetNumDecodedBitsSDC(const int iNewNumDecodedBitsSDC) { /* Apply changes only if parameters have changed */ if (iNewNumDecodedBitsSDC != iNumSDCBitsPerSFrame) { iNumSDCBitsPerSFrame = iNewNumDecodedBitsSDC; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForNoDecBitsSDC(); } } void CParameter::SetNumBitsHieraFrTot(const int iNewNumBitsHieraFrTot) { /* Apply changes only if parameters have changed */ if (iNewNumBitsHieraFrTot != iNumBitsHierarchFrameTotal) { iNumBitsHierarchFrameTotal = iNewNumBitsHieraFrTot; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSCDemux(); } } void CParameter::SetNumAudioDecoderBits(const int iNewNumAudioDecoderBits) { /* Apply changes only if parameters have changed */ if (iNewNumAudioDecoderBits != iNumAudioDecoderBits) { iNumAudioDecoderBits = iNewNumAudioDecoderBits; } } void CParameter::SetNumDataDecoderBits(const int iNewNumDataDecoderBits) { /* Apply changes only if parameters have changed */ if (iNewNumDataDecoderBits != iNumDataDecoderBits) { iNumDataDecoderBits = iNewNumDataDecoderBits; } } void CParameter::SetMSCProtLev(const CMSCProtLev NewMSCPrLe, const _BOOLEAN bWithHierarch) { // _BOOLEAN bParamersHaveChanged = false; if ((NewMSCPrLe.iPartA != MSCPrLe.iPartA) || (NewMSCPrLe.iPartB != MSCPrLe.iPartB)) { MSCPrLe.iPartA = NewMSCPrLe.iPartA; MSCPrLe.iPartB = NewMSCPrLe.iPartB; // bParamersHaveChanged = true; } /* Apply changes only if parameters have changed */ if (bWithHierarch == true) { if (NewMSCPrLe.iHierarch != MSCPrLe.iHierarch) { MSCPrLe.iHierarch = NewMSCPrLe.iHierarch; // bParamersHaveChanged = true; } } /* In case parameters have changed, set init flags */ // if (bParamersHaveChanged == true) // if(pDRMRec) pDRMRec->InitsForMSC(); } void CParameter::SetServiceParameters(int iShortID, const CService& newService) { Service[iShortID] = newService; } void CParameter::SetAudioParam(const int iShortID, const CAudioParam& NewAudParam) { /* Apply changes only if parameters have changed */ if (Service[iShortID].AudioParam != NewAudParam) { Service[iShortID].AudioParam = NewAudParam; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForAudParam(); } } CAudioParam CParameter::GetAudioParam(const int iShortID) { return Service[iShortID].AudioParam; } void CParameter::SetDataParam(const int iShortID, const CDataParam& NewDataParam) { CDataParam& DataParam = Service[iShortID].DataParam; /* Apply changes only if parameters have changed */ if (DataParam != NewDataParam) { DataParam = NewDataParam; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForDataParam(); } } CDataParam CParameter::GetDataParam(const int iShortID) { return Service[iShortID].DataParam; } void CParameter::SetInterleaverDepth(const ESymIntMod eNewDepth) { if (eSymbolInterlMode != eNewDepth) { eSymbolInterlMode = eNewDepth; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForInterlDepth(); } } void CParameter::SetMSCCodingScheme(const ECodScheme eNewScheme) { if (eMSCCodingScheme != eNewScheme) { eMSCCodingScheme = eNewScheme; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSCCodSche(); } } void CParameter::SetSDCCodingScheme(const ECodScheme eNewScheme) { if (eSDCCodingScheme != eNewScheme) { eSDCCodingScheme = eNewScheme; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForSDCCodSche(); } } void CParameter::SetCurSelAudioService(const int iNewService) { /* Change the current selected audio service ID only if the new ID does contain an audio service. If not, keep the old ID. In that case it is possible to select a "data-only" service and still listen to the audio of the last selected service */ if ((iCurSelAudioService != iNewService) && (Service[iNewService].AudioParam.iStreamID != STREAM_ID_NOT_USED)) { iCurSelAudioService = iNewService; LastAudioService.Reset(); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForAudParam(); } } void CParameter::SetCurSelDataService(const int iNewService) { /* Change the current selected data service ID only if the new ID does contain a data service. If not, keep the old ID. In that case it is possible to select a "data-only" service and click back to an audio service to be able to decode data service and listen to audio at the same time */ if ((iCurSelDataService != iNewService) && (Service[iNewService].DataParam.iStreamID != STREAM_ID_NOT_USED)) { iCurSelDataService = iNewService; LastDataService.Reset(); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForDataParam(); } } void CParameter::EnableMultimedia(const _BOOLEAN bFlag) { if (bUsingMultimedia != bFlag) { bUsingMultimedia = bFlag; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSCDemux(); } } void CParameter::SetNumOfServices(const size_t iNNumAuSe, const size_t iNNumDaSe) { /* Check whether number of activated services is not greater than the number of services signalled by the FAC because it can happen that a false CRC check (it is only a 8 bit CRC) of the FAC block initializes a wrong service */ set actServ; GetActiveServices(actServ); if (actServ.size() > iNNumAuSe + iNNumDaSe) { /* Reset services and streams and set flag for init modules */ ResetServicesStreams(); // if(pDRMRec) pDRMRec->InitsForMSCDemux(); } if ((iNumAudioService != iNNumAuSe) || (iNumDataService != iNNumDaSe)) { iNumAudioService = iNNumAuSe; iNumDataService = iNNumDaSe; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSCDemux(); } } void CParameter::SetAudDataFlag(const int iShortID, const CService::ETyOServ iNewADaFl) { if (Service[iShortID].eAudDataFlag != iNewADaFl) { Service[iShortID].eAudDataFlag = iNewADaFl; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSC(); } } void CParameter::SetServiceID(const int iShortID, const uint32_t iNewServiceID) { if (Service[iShortID].iServiceID != iNewServiceID) { /* JFBC - what is this for? */ if ((iShortID == 0) && (Service[0].iServiceID > 0)) ResetServicesStreams(); Service[iShortID].iServiceID = iNewServiceID; /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForMSC(); /* If the receiver has lost the sync automatically restore last current service selected */ if ((iShortID > 0) && (iNewServiceID > 0)) { if(LastAudioService.iServiceID == iNewServiceID) { /* Restore last audio service selected */ iCurSelAudioService = LastAudioService.iService; LastAudioService.Reset(); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForAudParam(); } if (LastDataService.iServiceID == iNewServiceID) { /* Restore last data service selected */ iCurSelDataService = LastDataService.iService; LastDataService.Reset(); /* Set init flags */ // if(pDRMRec) pDRMRec->InitsForDataParam(); } } } } /* Implementaions for simulation -------------------------------------------- */ void CRawSimData::Add(uint32_t iNewSRS) { /* Attention, function does not take care of overruns, data will be lost if added to a filled shift register! */ if (iCurWritePos < ciMaxDelBlocks) veciShRegSt[iCurWritePos++] = iNewSRS; } uint32_t CRawSimData::Get() { /* We always use the first value of the array for reading and do a shift of the other data by adding a arbitrary value (0) at the end of the whole shift register */ uint32_t iRet = veciShRegSt[0]; veciShRegSt.AddEnd(0); iCurWritePos--; return iRet; } _REAL CParameter::GetSysSNRdBPilPos() const { /* Get system SNR in dB for the pilot positions. Since the average power of the pilots is higher than the data cells, the SNR is also higher at these positions compared to the total SNR of the DRM signal. */ return (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSysSimSNRdB / 10) / CellMappingTable.rAvPowPerSymbol * CellMappingTable.rAvScatPilPow * (_REAL) CellMappingTable.iNumCarrier); } void CParameter::SetSNR(const _REAL iNewSNR) { SNRstat.addSample(iNewSNR); } _REAL CParameter::GetSNR() { return SNRstat.getCurrent(); } _REAL CParameter::GetNominalSNRdB() { /* Convert SNR from system bandwidth to nominal bandwidth */ return (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSysSimSNRdB / 10) * GetSysToNomBWCorrFact()); } void CParameter::SetNominalSNRdB(const _REAL rSNRdBNominal) { /* Convert SNR from nominal bandwidth to system bandwidth */ rSysSimSNRdB = (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSNRdBNominal / 10) / GetSysToNomBWCorrFact()); } _REAL CParameter::GetNominalBandwidth() { _REAL rNomBW; /* Nominal bandwidth as defined in the DRM standard */ switch (eSpectOccup) { case SO_0: rNomBW = (_REAL) 4500.0; /* Hz */ break; case SO_1: rNomBW = (_REAL) 5000.0; /* Hz */ break; case SO_2: rNomBW = (_REAL) 9000.0; /* Hz */ break; case SO_3: rNomBW = (_REAL) 10000.0; /* Hz */ break; case SO_4: rNomBW = (_REAL) 18000.0; /* Hz */ break; case SO_5: rNomBW = (_REAL) 20000.0; /* Hz */ break; default: rNomBW = (_REAL) 10000.0; /* Hz */ break; } return rNomBW; } _REAL CParameter::GetSysToNomBWCorrFact() { _REAL rNomBW = GetNominalBandwidth(); /* Calculate system bandwidth (N / T_u) */ const _REAL rSysBW = (_REAL) CellMappingTable.iNumCarrier / CellMappingTable.iFFTSizeN * SOUNDCRD_SAMPLE_RATE; return rSysBW / rNomBW; } void CParameter::SetIFSignalLevel(_REAL rNewSigStr) { rIFSigStr = rNewSigStr; } _REAL CParameter::GetIFSignalLevel() { return rIFSigStr; } void CRxStatus::SetStatus(const ETypeRxStatus OK) { status = OK; iNum++; if(OK==RX_OK) iNumOK++; } //void CParameter::GenerateReceiverID() //{ // //Set receiver ID // string sVer; // unsigned int iImplementation = 0;; // unsigned int iMajor = 0; // unsigned int iMinor = 0; // sReceiverID = "drea"; // sVer = dream_version; // size_t pos; // while((pos = sVer.find('.')) != string::npos) // sVer.replace(pos, 1, " "); // if ((pos = sVer.find("cvs")) != string::npos) // sVer.replace(pos, 3, " "); // stringstream ssVer(sVer); // ssVer >> iImplementation >> iMajor >> iMinor; // stringstream ssInfoVer; // ssInfoVer << setw(2) << setfill('0') << iImplementation << setw(2) << setfill('0') << iMajor << setw(2) << setfill('0') << iMinor; // sReceiverID += ssInfoVer.str(); // while (sSerialNumber.length() < 6) // sSerialNumber += "_"; // if (sSerialNumber.length() > 6) // sSerialNumber.erase(6, pDRMRec->GetParameters()->sSerialNumber.length()-6); // sReceiverID += pDRMRec->GetParameters()->sSerialNumber; //} void CParameter::GenerateRandomSerialNumber() { //seed random number generator srand((unsigned int)time(0)); char randomChars[36]; for (size_t q=0; q < 36; q++) { if (q < 26) randomChars[q] = char(q)+97; else randomChars[q] = (char(q)-26)+48; } char serialNumTemp[7]; for (size_t i=0; i < 6; i++) serialNumTemp[i] = randomChars[(int) 35.0*rand()/RAND_MAX]; serialNumTemp[6] = '\0'; sSerialNumber = serialNumTemp; } CMinMaxMean::CMinMaxMean():rSum(0.0),rCur(0.0), rMin(numeric_limits<_REAL>::max()),rMax(numeric_limits<_REAL>::min()),iNum(0) { } void CMinMaxMean::addSample(_REAL r) { rCur = r; rSum += r; iNum++; if(r>rMax) rMax = r; if(r0) rMean = rSum / iNum; rSum = 0.0; iNum = 0; return rMean; } void CMinMaxMean::getMinMax(_REAL& rMinOut, _REAL& rMaxOut) { if(rMin <= rMax) { rMinOut = rMin; rMaxOut = rMax; } else { rMinOut = 0.0; rMaxOut = 0.0; } rMin = numeric_limits<_REAL>::max(); rMax = numeric_limits<_REAL>::min(); } string CServiceDefinition::Frequency(size_t n) const { if(n>=veciFrequencies.size()) return ""; // not in the list stringstream ss; int iFrequency = veciFrequencies[n]; switch (iSystemID) { case 0: case 1: case 2: /* AM or DRM */ ss << iFrequency; break; case 3: case 4: case 5: /* 'FM1 frequency' - 87.5 to 107.9 MHz (100 kHz steps) */ ss << 87.5 + 0.1 * float(iFrequency); break; case 6: case 7: case 8: /* 'FM2 frequency'- 76.0 to 90.0 MHz (100 kHz steps) */ ss << 76.0 + 0.1 * float(iFrequency); break; case 9: case 10: case 11: if(iFrequency<=11) { int chan = iFrequency / 4; char subchan = 'A' + iFrequency % 4; ss << "Band I channel " << (chan+2) << subchan; } else if(64<= iFrequency && iFrequency <=95) { int chan = iFrequency / 4; char subchan = 'A' + iFrequency % 4; ss << "Band III channel " << (chan-11) << subchan; } else if(96<= iFrequency && iFrequency <=101) { int chan = iFrequency / 6; char subchan = 'A' + iFrequency % 6; ss << "Band III+ channel " << (chan-3) << subchan; } else if(128<= iFrequency && iFrequency <=143) { char chan = iFrequency - 128; double m = 1452.96+1.712*double(chan); ss << "European L-Band channel L" << ('A'+chan) << ", " << m << " MHz"; } else if(160<= iFrequency && iFrequency <=182) { int chan = iFrequency - 159; double m = 1451.072+1.744*double(chan); ss << "Canadian L-Band channel " << chan << ", " << m << " MHz"; } else { ss << "unknown channel " << iFrequency; } break; default: break; } return ss.str(); } string CServiceDefinition::FrequencyUnits() const { switch (iSystemID) { case 0: case 1: case 2: return "kHz"; break; case 3: case 4: case 5: case 6: case 7: case 8: return "MHz"; break; default: return ""; break; } } string CServiceDefinition::System() const { switch (iSystemID) { case 0: return "DRM"; break; case 1: case 2: return "AM"; break; case 3: case 4: case 5: case 6: case 7: case 8: return "FM"; break; case 9: case 10: case 11: return "DAB"; break; default: return ""; break; } } string COtherService::ServiceID() const { stringstream ss; /* switch (iSystemID) { case 0: case 1: ss << "ID:" << hex << setw(6) << iServiceID; break; case 3: case 6: ss << "ECC+PI:" << hex << setw(6) << iServiceID; break; case 4: case 7: ss << "PI:" << hex << setw(4) << iServiceID; break; case 9: ss << "ECC+aud:" << hex << setw(6) << iServiceID; break; case 10: ss << "AUDIO:" << hex << setw(4) << iServiceID; break; case 11: ss << "DATA:" << hex << setw(8) << iServiceID; break; break; default: break; } */ return ss.str(); } /* See ETSI ES 201 980 v2.1.1 Annex O */ _BOOLEAN CAltFreqSched::IsActive(const time_t ltime) { int iScheduleStart; int iScheduleEnd; int iWeekDay; /* Empty schedule is always active */ if (iDuration == 0) return true; /* Calculate time in UTC */ struct tm *gmtCur = gmtime(<ime); /* Check day tm_wday: day of week (0 - 6; Sunday = 0) I must normalize so Monday = 0 */ if (gmtCur->tm_wday == 0) iWeekDay = 6; else iWeekDay = gmtCur->tm_wday - 1; /* iTimeWeek minutes since last Monday 00:00 in UTC */ /* the value is in the range 0 <= iTimeWeek < 60 * 24 * 7) */ const int iTimeWeek = (iWeekDay * 24 * 60) + (gmtCur->tm_hour * 60) + gmtCur->tm_min; /* Day Code: this field indicates which days the frequency schedule * (the following Start Time and Duration) applies to. * The msb indicates Monday, the lsb Sunday. Between one and seven bits may be set to 1. */ for (int i = 0; i < 7; i++) { /* Check if day is active */ if ((1 << (6 - i)) & iDayCode) { /* Tuesday -> 1 * 24 * 60 = 1440 */ iScheduleStart = (i * 24 * 60) + iStartTime; iScheduleEnd = iScheduleStart + iDuration; /* the normal check (are we inside start and end?) */ if ((iTimeWeek >= iScheduleStart) && (iTimeWeek <= iScheduleEnd)) return true; /* the wrap-around check */ const int iMinutesPerWeek = 7 * 24 * 60; if (iScheduleEnd > iMinutesPerWeek) { /* our duration wraps into next Monday (or even later) */ if (iTimeWeek < (iScheduleEnd - iMinutesPerWeek)) return true; } } } return false; } qsstv_8.2.12/qsstv/drmtx/common/Parameter.h000664 001750 001750 00000075524 12440612574 020707 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001-2007 * * Author(s): * Volker Fischer, Andrew Murphy, Andrea Russo * * Adapted for ham sstv use Ties Bos - PA0MBO * * Description: * See Parameter.cpp * * 10/01/2007 Andrew Murphy, BBC Research & Development, 2005 * - Additions to include additional RSCI related fields * * 11/21/2005 Andrew Murphy, BBC Research & Development, 2005 * - Additions to include AMSS demodulation (Added class * CAltFreqOtherServicesSign) * * 11/28/2005 Andrea Russo * - Added classes for store alternative frequencies schedules and regions * ******************************************************************************* * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(PARAMETER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) #define PARAMETER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_ #include "GlobalDefinitions.h" #include "ofdmcellmapping/CellMappingTable.h" #include "matlib/Matlib.h" #include //#include "GPSData.h" //#include "ServiceInformation.h" #include #include #include class CDRMReceiver; /* CS: Coding Scheme */ enum ECodScheme { CS_1_SM, CS_2_SM, CS_3_SM, CS_3_HMSYM, CS_3_HMMIX }; /* CT: Channel Type */ enum EChanType { CT_MSC, CT_SDC, CT_FAC }; enum ETypeIntFreq { FLINEAR, FDFTFILTER, FWIENER }; enum ETypeIntTime { TLINEAR, TWIENER }; enum ETypeSNREst { SNR_FAC, SNR_PIL }; enum ETypeRxStatus { NOT_PRESENT, CRC_ERROR, DATA_ERROR, RX_OK }; /* RM: Receiver mode (analog or digital demodulation) */ enum ERecMode { RM_DRM, RM_AM, RM_NONE }; /* Acquisition state of receiver */ enum EAcqStat {AS_NO_SIGNAL, AS_WITH_SIGNAL}; /* Receiver state */ enum ERecState {RS_TRACKING, RS_ACQUISITION}; /* Classes ********************************************************************/ class CAudioParam { public: /* AC: Audio Coding */ enum EAudCod { AC_AAC, AC_CELP, AC_HVXC }; /* SB: SBR */ enum ESBRFlag { SB_NOT_USED, SB_USED }; /* AM: Audio Mode */ enum EAudMode { AM_MONO, AM_P_STEREO, AM_STEREO }; /* HR: HVXC Rate */ enum EHVXCRate { HR_2_KBIT, HR_4_KBIT }; /* AS: Audio Sampling rate */ enum EAudSamRat { AS_8_KHZ, AS_12KHZ, AS_16KHZ, AS_24KHZ }; CAudioParam(): strTextMessage(), iStreamID(STREAM_ID_NOT_USED), eAudioCoding(AC_AAC), eSBRFlag(SB_NOT_USED), eAudioSamplRate(AS_24KHZ), bTextflag(false), bEnhanceFlag(false), eAudioMode(AM_MONO), iCELPIndex(0), bCELPCRC(false), eHVXCRate(HR_2_KBIT), bHVXCCRC(false) { } CAudioParam(const CAudioParam& ap): strTextMessage(ap.strTextMessage), iStreamID(ap.iStreamID), eAudioCoding(ap.eAudioCoding), eSBRFlag(ap.eSBRFlag), eAudioSamplRate(ap.eAudioSamplRate), bTextflag(ap.bTextflag), bEnhanceFlag(ap.bEnhanceFlag), eAudioMode(ap.eAudioMode), iCELPIndex(ap.iCELPIndex), bCELPCRC(ap.bCELPCRC), eHVXCRate(ap.eHVXCRate), bHVXCCRC(ap.bHVXCCRC) { } CAudioParam& operator=(const CAudioParam& ap) { strTextMessage = ap.strTextMessage; iStreamID = ap.iStreamID; eAudioCoding = ap.eAudioCoding; eSBRFlag = ap.eSBRFlag; eAudioSamplRate = ap.eAudioSamplRate; bTextflag = ap.bTextflag; bEnhanceFlag = ap.bEnhanceFlag; eAudioMode = ap.eAudioMode; iCELPIndex = ap.iCELPIndex; bCELPCRC = ap.bCELPCRC; eHVXCRate = ap.eHVXCRate; bHVXCCRC = ap.bHVXCCRC; return *this; } /* Text-message */ string strTextMessage; /* Max length is (8 * 16 Bytes) */ int iStreamID; /* Stream Id of the stream which carries the audio service */ EAudCod eAudioCoding; /* This field indicated the source coding system */ ESBRFlag eSBRFlag; /* SBR flag */ EAudSamRat eAudioSamplRate; /* Audio sampling rate */ _BOOLEAN bTextflag; /* Indicates whether a text message is present or not */ _BOOLEAN bEnhanceFlag; /* Enhancement flag */ /* For AAC: Mono, LC Stereo, Stereo --------------------------------- */ EAudMode eAudioMode; /* Audio mode */ /* For CELP --------------------------------------------------------- */ int iCELPIndex; /* This field indicates the CELP bit rate index */ _BOOLEAN bCELPCRC; /* This field indicates whether the CRC is used or not */ /* For HVXC --------------------------------------------------------- */ EHVXCRate eHVXCRate; /* This field indicates the rate of the HVXC */ _BOOLEAN bHVXCCRC; /* This field indicates whether the CRC is used or not */ /* This function is needed for detection changes in the class */ _BOOLEAN operator!=(const CAudioParam AudioParam) { if (iStreamID != AudioParam.iStreamID) return true; if (eAudioCoding != AudioParam.eAudioCoding) return true; if (eSBRFlag != AudioParam.eSBRFlag) return true; if (eAudioSamplRate != AudioParam.eAudioSamplRate) return true; if (bTextflag != AudioParam.bTextflag) return true; if (bEnhanceFlag != AudioParam.bEnhanceFlag) return true; switch (AudioParam.eAudioCoding) { case AC_AAC: if (eAudioMode != AudioParam.eAudioMode) return true; break; case AC_CELP: if (bCELPCRC != AudioParam.bCELPCRC) return true; if (iCELPIndex != AudioParam.iCELPIndex) return true; break; case AC_HVXC: if (eHVXCRate != AudioParam.eHVXCRate) return true; if (bHVXCCRC != AudioParam.bHVXCCRC) return true; break; } return false; } }; class CDataParam { public: /* PM: Packet Mode */ enum EPackMod { PM_SYNCHRON_STR_MODE, PM_PACKET_MODE }; /* DU: Data Unit */ enum EDatUnit { DU_SINGLE_PACKETS, DU_DATA_UNITS }; /* AD: Application Domain */ enum EApplDomain { AD_DRM_SPEC_APP, AD_DAB_SPEC_APP, AD_OTHER_SPEC_APP }; int iStreamID; /* Stream Id of the stream which carries the data service */ EPackMod ePacketModInd; /* Packet mode indicator */ /* In case of packet mode ------------------------------------------- */ EDatUnit eDataUnitInd; /* Data unit indicator */ int iPacketID; /* Packet Id (2 bits) */ int iPacketLen; /* Packet length */ // "DAB specified application" not yet implemented!!! EApplDomain eAppDomain; /* Application domain */ int iUserAppIdent; /* User application identifier, only DAB */ CDataParam(): iStreamID(STREAM_ID_NOT_USED), ePacketModInd(PM_PACKET_MODE), eDataUnitInd(DU_DATA_UNITS), iPacketID(0), iPacketLen(0), eAppDomain(AD_DAB_SPEC_APP), iUserAppIdent(2) // was 0 ipc 2 (AT_MOTSLISHOW) pa0mbo Nov 7th 2011 { } CDataParam(const CDataParam& DataParam): iStreamID(DataParam.iStreamID), ePacketModInd(DataParam.ePacketModInd), eDataUnitInd(DataParam.eDataUnitInd), iPacketID(DataParam.iPacketID), iPacketLen(DataParam.iPacketLen), eAppDomain(DataParam.eAppDomain), iUserAppIdent(DataParam.iUserAppIdent) { } CDataParam& operator=(const CDataParam& DataParam) { iStreamID = DataParam.iStreamID; ePacketModInd = DataParam.ePacketModInd; eDataUnitInd = DataParam.eDataUnitInd; iPacketID = DataParam.iPacketID; iPacketLen = DataParam.iPacketLen; eAppDomain = DataParam.eAppDomain; iUserAppIdent = DataParam.iUserAppIdent; return *this; } /* This function is needed for detection changes in the class */ _BOOLEAN operator!=(const CDataParam DataParam) { if (iStreamID != DataParam.iStreamID) return true; if (ePacketModInd != DataParam.ePacketModInd) return true; if (DataParam.ePacketModInd == PM_PACKET_MODE) { if (eDataUnitInd != DataParam.eDataUnitInd) return true; if (iPacketID != DataParam.iPacketID) return true; if (iPacketLen != DataParam.iPacketLen) return true; if (eAppDomain != DataParam.eAppDomain) return true; if (DataParam.eAppDomain == AD_DAB_SPEC_APP) if (iUserAppIdent != DataParam.iUserAppIdent) return true; } return false; } }; class CService { public: /* CA: CA system */ enum ECACond { CA_USED, CA_NOT_USED }; /* SF: Service Flag */ enum ETyOServ { SF_AUDIO, SF_DATA }; CService(): iServiceID(SERV_ID_NOT_USED), eCAIndication(CA_NOT_USED), iLanguage(0), eAudDataFlag(SF_AUDIO), iServiceDescr(0), strCountryCode(), strLanguageCode(), strLabel(), AudioParam(), DataParam() { } CService(const CService& s): iServiceID(s.iServiceID), eCAIndication(s.eCAIndication), iLanguage(s.iLanguage), eAudDataFlag(s.eAudDataFlag), iServiceDescr(s.iServiceDescr), strCountryCode(s.strCountryCode), strLanguageCode(s.strLanguageCode), strLabel(s.strLabel), AudioParam(s.AudioParam), DataParam(s.DataParam) { } CService& operator=(const CService& s) { iServiceID = s.iServiceID; eCAIndication = s.eCAIndication; iLanguage = s.iLanguage; eAudDataFlag = s.eAudDataFlag; iServiceDescr = s.iServiceDescr; strCountryCode = s.strCountryCode; strLanguageCode = s.strLanguageCode; strLabel = s.strLabel; AudioParam = s.AudioParam; DataParam = s.DataParam; return *this; } _BOOLEAN IsActive() const { return iServiceID != SERV_ID_NOT_USED; } uint32_t iServiceID; ECACond eCAIndication; int iLanguage; ETyOServ eAudDataFlag; int iServiceDescr; string strCountryCode; string strLanguageCode; /* Label of the service */ string strLabel; /* Audio parameters */ CAudioParam AudioParam; /* Data parameters */ CDataParam DataParam; }; class CStream { public: CStream():iLenPartA(0), iLenPartB(0) { } CStream(const CStream& s):iLenPartA(s.iLenPartA), iLenPartB(s.iLenPartB) { } CStream& operator=(const CStream& Stream) { iLenPartA=Stream.iLenPartA; iLenPartB=Stream.iLenPartB; return *this; } bool operator==(const CStream Stream) { if (iLenPartA != Stream.iLenPartA) return false; if (iLenPartB != Stream.iLenPartB) return false; return true; } int iLenPartA; /* Data length for part A */ int iLenPartB; /* Data length for part B */ }; class CMSCProtLev { public: CMSCProtLev(){init();} void init() { iPartA=iPartB=iHierarch=0; }; CMSCProtLev(const CMSCProtLev& p):iPartA(p.iPartA),iPartB(p.iPartB),iHierarch(p.iHierarch) {} CMSCProtLev& operator=(const CMSCProtLev& NewMSCProtLev) { iPartA = NewMSCProtLev.iPartA; iPartB = NewMSCProtLev.iPartB; iHierarch = NewMSCProtLev.iHierarch; return *this; } int iPartA; /* MSC protection level for part A */ int iPartB; /* MSC protection level for part B */ int iHierarch; /* MSC protection level for hierachical frame */ }; /* Alternative Frequency Signalling ************************************** */ /* Alternative frequency signalling Schedules informations class */ class CAltFreqSched { public: CAltFreqSched():iDayCode(0),iStartTime(0),iDuration(0) { } CAltFreqSched(const CAltFreqSched& nAFS): iDayCode(nAFS.iDayCode), iStartTime(nAFS.iStartTime), iDuration(nAFS.iDuration) { } CAltFreqSched& operator=(const CAltFreqSched& nAFS) { iDayCode = nAFS.iDayCode; iStartTime = nAFS.iStartTime; iDuration = nAFS.iDuration; return *this; } _BOOLEAN operator==(const CAltFreqSched& nAFS) { if (iDayCode != nAFS.iDayCode) return false; if (iStartTime != nAFS.iStartTime) return false; if (iDuration != nAFS.iDuration) return false; return true; } _BOOLEAN IsActive(const time_t ltime); int iDayCode; int iStartTime; int iDuration; }; /* Alternative frequency signalling Regions informations class */ class CAltFreqRegion { public: CAltFreqRegion():veciCIRAFZones(), iLatitude(0), iLongitude(0), iLatitudeEx(0), iLongitudeEx(0) { } CAltFreqRegion(const CAltFreqRegion& nAFR): veciCIRAFZones(nAFR.veciCIRAFZones), iLatitude(nAFR.iLatitude), iLongitude(nAFR.iLongitude), iLatitudeEx(nAFR.iLatitudeEx), iLongitudeEx(nAFR.iLongitudeEx) { } CAltFreqRegion& operator=(const CAltFreqRegion& nAFR) { iLatitude = nAFR.iLatitude; iLongitude = nAFR.iLongitude; iLatitudeEx = nAFR.iLatitudeEx; iLongitudeEx = nAFR.iLongitudeEx; veciCIRAFZones = nAFR.veciCIRAFZones; return *this; } _BOOLEAN operator==(const CAltFreqRegion& nAFR) { if (iLatitude != nAFR.iLatitude) return false; if (iLongitude != nAFR.iLongitude) return false; if (iLatitudeEx != nAFR.iLatitudeEx) return false; if (iLongitudeEx != nAFR.iLongitudeEx) return false; /* Vector sizes */ if (veciCIRAFZones.size() != nAFR.veciCIRAFZones.size()) return false; /* Vector contents */ for (size_t i = 0; i < veciCIRAFZones.size(); i++) if (veciCIRAFZones[i] != nAFR.veciCIRAFZones[i]) return false; return true; } vector veciCIRAFZones; int iLatitude; int iLongitude; int iLatitudeEx; int iLongitudeEx; }; class CServiceDefinition { public: CServiceDefinition():veciFrequencies(), iRegionID(0), iScheduleID(0),iSystemID(0) { } CServiceDefinition(const CServiceDefinition& nAF): veciFrequencies(nAF.veciFrequencies), iRegionID(nAF.iRegionID), iScheduleID(nAF.iScheduleID), iSystemID(nAF.iSystemID) { } CServiceDefinition& operator=(const CServiceDefinition& nAF) { veciFrequencies = nAF.veciFrequencies; iRegionID = nAF.iRegionID; iScheduleID = nAF.iScheduleID; iSystemID = nAF.iSystemID; return *this; } bool operator==(const CServiceDefinition& sd) const { size_t i; /* Vector sizes */ if (veciFrequencies.size() != sd.veciFrequencies.size()) return false; /* Vector contents */ for (i = 0; i < veciFrequencies.size(); i++) if (veciFrequencies[i] != sd.veciFrequencies[i]) return false; if (iRegionID != sd.iRegionID) return false; if (iScheduleID != sd.iScheduleID) return false; if (iSystemID != sd.iSystemID) return false; return true; } bool operator!=(const CServiceDefinition& sd) const { return !(*this==sd); } string Frequency(size_t) const; string FrequencyUnits() const; string System() const; vector veciFrequencies; int iRegionID; int iScheduleID; int iSystemID; }; class CMultiplexDefinition: public CServiceDefinition { public: CMultiplexDefinition():CServiceDefinition(), veciServRestrict(4), bIsSyncMultplx(false) { } CMultiplexDefinition(const CMultiplexDefinition& nAF):CServiceDefinition(nAF), veciServRestrict(nAF.veciServRestrict), bIsSyncMultplx(nAF.bIsSyncMultplx) { } CMultiplexDefinition& operator=(const CMultiplexDefinition& nAF) { CServiceDefinition(*this) = nAF; veciServRestrict = nAF.veciServRestrict; bIsSyncMultplx = nAF.bIsSyncMultplx; return *this; } bool operator==(const CMultiplexDefinition& md) const { if (CServiceDefinition(*this) != md) return false; /* Vector sizes */ if (veciServRestrict.size() != md.veciServRestrict.size()) return false; /* Vector contents */ for (size_t i = 0; i < veciServRestrict.size(); i++) if (veciServRestrict[i] != md.veciServRestrict[i]) return false; if (bIsSyncMultplx != md.bIsSyncMultplx) return false; return true; } vector veciServRestrict; _BOOLEAN bIsSyncMultplx; }; class COtherService: public CServiceDefinition { public: COtherService(): CServiceDefinition(), bSameService(true), iShortID(0), iServiceID(SERV_ID_NOT_USED) { } COtherService(const COtherService& nAF): CServiceDefinition(nAF), bSameService(nAF.bSameService), iShortID(nAF.iShortID), iServiceID(nAF.iServiceID) { } COtherService& operator=(const COtherService& nAF) { CServiceDefinition(*this) = nAF; bSameService = nAF.bSameService; iShortID = nAF.iShortID; iServiceID = nAF.iServiceID; return *this; } bool operator==(const COtherService& nAF) { if (CServiceDefinition(*this) != nAF) return false; if (bSameService != nAF.bSameService) return false; if (iShortID != nAF.iShortID) return false; if (iServiceID != nAF.iServiceID) return false; return true; } string ServiceID() const; _BOOLEAN bSameService; int iShortID; uint32_t iServiceID; }; /* Alternative frequency signalling class */ class CAltFreqSign { public: CAltFreqSign():vecRegions(16),vecSchedules(16),vecMultiplexes(),vecOtherServices(), bRegionVersionFlag(false),bScheduleVersionFlag(false), bMultiplexVersionFlag(false),bOtherServicesVersionFlag(false) { } CAltFreqSign(const CAltFreqSign& a):vecRegions(a.vecRegions), vecSchedules(a.vecSchedules), vecMultiplexes(a.vecMultiplexes), bRegionVersionFlag(a.bRegionVersionFlag), bScheduleVersionFlag(a.bScheduleVersionFlag), bMultiplexVersionFlag(a.bMultiplexVersionFlag), bOtherServicesVersionFlag(a.bOtherServicesVersionFlag) { } CAltFreqSign& operator=(const CAltFreqSign& a) { vecRegions = a.vecRegions; vecSchedules = a.vecSchedules; vecMultiplexes = a.vecMultiplexes; bRegionVersionFlag = a.bRegionVersionFlag; bScheduleVersionFlag = a.bScheduleVersionFlag; bMultiplexVersionFlag = a.bMultiplexVersionFlag; bOtherServicesVersionFlag = a.bOtherServicesVersionFlag; return *this; } void ResetRegions(_BOOLEAN b) { vecRegions.clear(); vecRegions.resize(16); bRegionVersionFlag=b; } void ResetSchedules(_BOOLEAN b) { vecSchedules.clear(); vecSchedules.resize(16); bScheduleVersionFlag=b; } void ResetMultiplexes(_BOOLEAN b) { vecMultiplexes.clear(); bMultiplexVersionFlag=b; } void ResetOtherServices(_BOOLEAN b) { vecOtherServices.clear(); bOtherServicesVersionFlag=b; } void Reset() { ResetRegions(false); ResetSchedules(false); ResetMultiplexes(false); ResetOtherServices(false); } vector < vector > vecRegions; // outer vector indexed by regionID vector < vector > vecSchedules; // outer vector indexed by scheduleID vector < CMultiplexDefinition > vecMultiplexes; vector < COtherService > vecOtherServices; _BOOLEAN bRegionVersionFlag; _BOOLEAN bScheduleVersionFlag; _BOOLEAN bMultiplexVersionFlag; _BOOLEAN bOtherServicesVersionFlag; }; /* Class to store information about the last service selected ------------- */ class CLastService { public: CLastService():iService(0), iServiceID(SERV_ID_NOT_USED) { } CLastService(const CLastService& l):iService(l.iService), iServiceID(l.iServiceID) { } CLastService& operator=(const CLastService& l) { iService = l.iService; iServiceID = l.iServiceID; return *this; } void Reset() { iService = 0; iServiceID = SERV_ID_NOT_USED; }; void Save(const int iCurSel, const int iCurServiceID) { if (iCurServiceID != SERV_ID_NOT_USED) { iService = iCurSel; iServiceID = iCurServiceID; } }; /* store only fac parameters */ int iService; uint32_t iServiceID; }; /* Classes to keep track of status flags for RSCI rsta tag and log file */ class CRxStatus { public: CRxStatus():status(NOT_PRESENT),iNum(0),iNumOK(0) {} CRxStatus(const CRxStatus& s):status(s.status),iNum(s.iNum),iNumOK(s.iNumOK) {} CRxStatus& operator=(const CRxStatus& s) { status = s.status; iNum = s.iNum; iNumOK = s.iNumOK; return *this;} void SetStatus(const ETypeRxStatus); ETypeRxStatus GetStatus() { return status; } int GetCount() { return iNum; } int GetOKCount() { return iNumOK; } void ResetCounts() { iNum=0; iNumOK = 0; } private: ETypeRxStatus status; int iNum, iNumOK; }; class CReceiveStatus { public: CReceiveStatus():FSync(),TSync(),Interface(), FAC(),SDC(),Audio(),LLAudio(),MOT() { } CReceiveStatus(const CReceiveStatus& s):FSync(s.FSync), TSync(s.TSync), Interface(s.Interface), FAC(s.FAC), SDC(s.SDC), Audio(s.Audio),LLAudio(s.LLAudio),MOT(s.MOT) { } CReceiveStatus& operator=(const CReceiveStatus& s) { FSync = s.FSync; TSync = s.TSync; Interface = s.Interface; FAC = s.FAC; SDC = s.SDC; Audio = s.Audio; LLAudio = s.LLAudio; MOT = s.MOT; return *this; } CRxStatus FSync; CRxStatus TSync; CRxStatus Interface; CRxStatus FAC; CRxStatus SDC; CRxStatus Audio; CRxStatus LLAudio; CRxStatus MOT; }; /* Simulation raw-data management. We have to implement a shift register with varying size. We do that by adding a variable for storing the current write position. */ class CRawSimData { /* We have to implement a shift register with varying size. We do that by adding a variable for storing the current write position. We use always the first value of the array for reading and do a shift of the other data by adding a arbitrary value (0) at the end of the whole shift register */ public: /* Here, the maximal size of the shift register is set */ CRawSimData():ciMaxDelBlocks(50), iCurWritePos(0) { veciShRegSt.Init(ciMaxDelBlocks); } void Add(uint32_t iNewSRS); uint32_t Get(); void Reset() { iCurWritePos = 0; } protected: /* Max number of delayed blocks */ int ciMaxDelBlocks; CShiftRegister < uint32_t > veciShRegSt; int iCurWritePos; }; class CFrontEndParameters { public: enum ESMeterCorrectionType {S_METER_CORRECTION_TYPE_CAL_FACTOR_ONLY, S_METER_CORRECTION_TYPE_AGC_ONLY, S_METER_CORRECTION_TYPE_AGC_RSSI}; // Constructor CFrontEndParameters(): eSMeterCorrectionType(S_METER_CORRECTION_TYPE_CAL_FACTOR_ONLY), rSMeterBandwidth(10000.0), rDefaultMeasurementBandwidth(10000.0), bAutoMeasurementBandwidth(true), rCalFactorAM(0.0), rCalFactorDRM(0.0), rIFCentreFreq(12000.0) {} CFrontEndParameters(const CFrontEndParameters& p): eSMeterCorrectionType(p.eSMeterCorrectionType), rSMeterBandwidth(p.rSMeterBandwidth), rDefaultMeasurementBandwidth(p.rDefaultMeasurementBandwidth), bAutoMeasurementBandwidth(p.bAutoMeasurementBandwidth), rCalFactorAM(p.rCalFactorAM), rCalFactorDRM(p.rCalFactorDRM), rIFCentreFreq(p.rIFCentreFreq) {} CFrontEndParameters& operator=(const CFrontEndParameters& p) { eSMeterCorrectionType = p.eSMeterCorrectionType; rSMeterBandwidth = p.rSMeterBandwidth; rDefaultMeasurementBandwidth = p.rDefaultMeasurementBandwidth; bAutoMeasurementBandwidth = p.bAutoMeasurementBandwidth; rCalFactorAM = p.rCalFactorAM; rCalFactorDRM = p.rCalFactorDRM; rIFCentreFreq = p.rIFCentreFreq; return *this; } ESMeterCorrectionType eSMeterCorrectionType; _REAL rSMeterBandwidth; // The bandwidth the S-meter uses to do the measurement _REAL rDefaultMeasurementBandwidth; // Bandwidth to do measurement if not synchronised _BOOLEAN bAutoMeasurementBandwidth; // true: use the current FAC bandwidth if locked, false: use default bandwidth always _REAL rCalFactorAM; _REAL rCalFactorDRM; _REAL rIFCentreFreq; }; class CMinMaxMean { public: CMinMaxMean(); void addSample(_REAL); _REAL getCurrent(); _REAL getMean(); void getMinMax(_REAL&, _REAL&); protected: _REAL rSum, rCur, rMin, rMax; int iNum; }; class CParameter { public: CParameter(); void init(); CParameter(const CParameter& p); //CParameter(CDRMReceiver *pRx, CParameter *pParameter); // OPH - just copy some of the members virtual ~CParameter(); CParameter& operator=(const CParameter&); /* Enumerations --------------------------------------------------------- */ /* AS: AFS in SDC is valid or not */ enum EAFSVali { AS_VALID, AS_NOT_VALID }; /* SI: Symbol Interleaver */ enum ESymIntMod { SI_LONG, SI_SHORT }; /* ST: Simulation Type */ enum ESimType { ST_NONE, ST_BITERROR, ST_MSECHANEST, ST_BER_IDEALCHAN, ST_SYNC_PARAM, ST_SINR }; /* Misc. Functions ------------------------------------------------------ */ void GenerateRandomSerialNumber(); // void GenerateReceiverID(); void ResetServicesStreams(); void GetActiveServices(set& actServ); void GetActiveStreams(set& actStr); void InitCellMapTable(const ERobMode eNewWaveMode, const ESpecOcc eNewSpecOcc); void SetNumDecodedBitsMSC(const int iNewNumDecodedBitsMSC); void SetNumDecodedBitsSDC(const int iNewNumDecodedBitsSDC); void SetNumBitsHieraFrTot(const int iNewNumBitsHieraFrTot); void SetNumAudioDecoderBits(const int iNewNumAudioDecoderBits); void SetNumDataDecoderBits(const int iNewNumDataDecoderBits); _BOOLEAN SetWaveMode(const ERobMode eNewWaveMode); ERobMode GetWaveMode() const { return eRobustnessMode; } void SetFrequency(int iNewFrequency) { iFrequency = iNewFrequency; } int GetFrequency() { return iFrequency; } void SetServiceParameters(int iShortID, const CService& newService); void SetCurSelAudioService(const int iNewService); int GetCurSelAudioService() const { return iCurSelAudioService; } void SetCurSelDataService(const int iNewService); int GetCurSelDataService() const { return iCurSelDataService; } void ResetCurSelAudDatServ() { iCurSelAudioService = 0; iCurSelDataService = 0; } void EnableMultimedia(const _BOOLEAN bFlag); _BOOLEAN GetEnableMultimedia() const { return bUsingMultimedia; } _REAL GetDCFrequency() const { return SOUNDCRD_SAMPLE_RATE * (rFreqOffsetAcqui + rFreqOffsetTrack); } _REAL GetBitRateKbps(const int iShortID, const _BOOLEAN bAudData); _REAL PartABLenRatio(const int iShortID); /* Parameters controlled by FAC ----------------------------------------- */ void SetInterleaverDepth(const ESymIntMod eNewDepth); ESymIntMod GetInterleaverDepth() { return eSymbolInterlMode; } void SetMSCCodingScheme(const ECodScheme eNewScheme); void SetSDCCodingScheme(const ECodScheme eNewScheme); void SetSpectrumOccup(ESpecOcc eNewSpecOcc); ESpecOcc GetSpectrumOccup() const { return eSpectOccup; } void SetNumOfServices(const size_t iNNumAuSe, const size_t iNNumDaSe); size_t GetTotNumServices() { return iNumAudioService + iNumDataService; } void SetAudDataFlag(const int iShortID, const CService::ETyOServ iNewADaFl); void SetServiceID(const int iShortID, const uint32_t iNewServiceID); // CDRMReceiver* pDRMRec; joma removed rx /* Symbol interleaver mode (long or short interleaving) */ ESymIntMod eSymbolInterlMode; ECodScheme eMSCCodingScheme; /* MSC coding scheme */ ECodScheme eSDCCodingScheme; /* SDC coding scheme */ size_t iNumAudioService; size_t iNumDataService; /* AMSS */ int iAMSSCarrierMode; /* Serial number and received ID */ string sReceiverID; string sSerialNumber; string sDataFilesDirectory; /* Parameters controlled by SDC ----------------------------------------- */ void SetAudioParam(const int iShortID, const CAudioParam& NewAudParam); CAudioParam GetAudioParam(const int iShortID); CDataParam GetDataParam(const int iShortID); void SetDataParam(const int iShortID, const CDataParam& NewDataParam); void SetMSCProtLev(const CMSCProtLev NewMSCPrLe, const _BOOLEAN bWithHierarch); void SetStreamLen(const int iStreamID, const int iNewLenPartA, const int iNewLenPartB); void GetStreamLen(const int iStreamID, int& iLenPartA, int& iLenPartB); int GetStreamLen(const int iStreamID); /* Protection levels for MSC */ CMSCProtLev MSCPrLe; vector Stream; vector Service; /* information about services gathered from SDC, EPG and web schedules */ // map ServiceInformation; /* These values are used to set input and output block sizes of some modules */ int iNumBitsHierarchFrameTotal; int iNumDecodedBitsMSC; int iNumSDCBitsPerSFrame; /* Number of SDC bits per super-frame */ int iNumAudioDecoderBits; /* Number of input bits for audio module */ int iNumDataDecoderBits; /* Number of input bits for data decoder module */ /* Date */ int iYear; int iMonth; int iDay; /* UTC (hours and minutes) */ int iUTCHour; int iUTCMin; /* Identifies the current frame. This parameter is set by FAC */ int iFrameIDTransm; int iFrameIDReceiv; /* Synchronization ------------------------------------------------------ */ _REAL rFreqOffsetAcqui; _REAL rFreqOffsetTrack; _REAL rResampleOffset; int iTimingOffsTrack; ERecMode GetReceiverMode() { return eReceiverMode; } ERecMode eReceiverMode; EAcqStat GetAcquiState() { return eAcquiState; } EAcqStat eAcquiState; int iNumAudioFrames; CVector <_BINARY> vecbiAudioFrameStatus; _BOOLEAN bMeasurePSD; /* vector to hold the PSD valued for the rpsd tag. */ CVector <_REAL> vecrPSD; CMatrix <_COMPLEX> matcReceivedPilotValues; /* Simulation ----------------------------------------------------------- */ CRawSimData RawSimDa; ESimType eSimType; int iDRMChannelNum; int iSpecChDoppler; _REAL rBitErrRate; _REAL rSyncTestParam; /* For any other simulations, used with "ST_SYNC_PARAM" type */ _REAL rSINR; int iNumBitErrors; int iChanEstDelay; int iNumTaps; vector iPathDelay; _REAL rGainCorr; int iOffUsfExtr; void SetSNR(const _REAL); _REAL GetSNR(); void SetNominalSNRdB(const _REAL rSNRdBNominal); _REAL GetNominalSNRdB(); void SetSystemSNRdB(const _REAL rSNRdBSystem) { rSysSimSNRdB = rSNRdBSystem; } _REAL GetSystemSNRdB() const { return rSysSimSNRdB; } _REAL GetSysSNRdBPilPos() const; CReceiveStatus ReceiveStatus; CFrontEndParameters FrontEndParameters; CAltFreqSign AltFreqSign; void Lock() { Mutex.Lock(); } void Unlock() { Mutex.Unlock(); } /* Channel Estimation */ _REAL rMER; _REAL rWMERMSC; _REAL rWMERFAC; _REAL rSigmaEstimate; _REAL rMinDelay; _REAL rMaxDelay; _BOOLEAN bMeasureDelay; CRealVector vecrRdel; CRealVector vecrRdelThresholds; CRealVector vecrRdelIntervals; _BOOLEAN bMeasureDoppler; _REAL rRdop; /* interference (constellation-based measurement rnic)*/ _BOOLEAN bMeasureInterference; _REAL rIntFreq, rINR, rICR; /* peak of PSD - for PSD-based interference measurement rnip */ _REAL rMaxPSDwrtSig; _REAL rMaxPSDFreq; /* the signal level as measured at IF by dream */ void SetIFSignalLevel(_REAL); _REAL GetIFSignalLevel(); _REAL rSigStrengthCorrection; /* General -------------------------------------------------------------- */ _REAL GetNominalBandwidth(); _REAL GetSysToNomBWCorrFact(); _BOOLEAN bRunThread; _BOOLEAN bUsingMultimedia; CCellMappingTable CellMappingTable; // CGPSData GPSData; CMinMaxMean SNRstat, SigStrstat; protected: _REAL rSysSimSNRdB; int iFrequency; _BOOLEAN bValidSignalStrength; _REAL rSigStr; _REAL rIFSigStr; /* Current selected audio service for processing */ int iCurSelAudioService; int iCurSelDataService; ERobMode eRobustnessMode; /* E.g.: Mode A, B, C or D */ ESpecOcc eSpectOccup; /* For resync to last service------------------------------------------- */ CLastService LastAudioService; CLastService LastDataService; CMutex Mutex; }; #endif // !defined(PARAMETER_H__3B0BA660_CA63_4344_BB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/drmtx/common/csoundout.cpp000664 001750 001750 00000000771 12440612574 021335 0ustar00jomajoma000000 000000 #include "csoundout.h" #include "qsstvglobal.h" #include "dsp/synthes.h" #include "utils/vector.h" CSoundOut::CSoundOut() { } CSoundOut::~CSoundOut() { } //void CSoundOut::Init(int iNewBufferSize, bool bNewBlocking) //{ //} bool CSoundOut::Write(CVector< _SAMPLE >& psData) { // addToLog(QString("csize start %1").arg(psData.Size()/2),LOGSOUND); synthesPtr->writeBuffer((quint32 *)&psData[0],psData.Size()/2); // addToLog(QString("csize end %1").arg(psData.Size()/2),LOGSOUND); return false; } qsstv_8.2.12/qsstv/drmtx/common/csoundout.h000664 001750 001750 00000000463 12440612574 021000 0ustar00jomajoma000000 000000 #ifndef CSOUNDOUT_H #define CSOUNDOUT_H #include "GlobalDefinitions.h" #include "soundinterface.h" class CSoundOut: public CSoundOutInterface { public: CSoundOut(); ~CSoundOut(); // void Init(int iNewBufferSize, bool bNewBlocking); bool Write(CVector< _SAMPLE >& psData); }; #endif // CSOUNDOUT_H qsstv_8.2.12/qsstv/drmtx/common/soundinterface.h000664 001750 001750 00000003361 12440612574 021766 0ustar00jomajoma000000 000000 /******************************************************************************\ * British Broadcasting Corporation * Copyright (c) 2007 * * Author(s): * Julian Cable * * Decription: * sound interfaces * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #ifndef _SOUNDINTERFACE_H #define _SOUNDINTERFACE_H #include "qsstvglobal.h" #include "utils/vector.h" //class CSoundInInterface : public CSelectionInterface //{ //public: // virtual ~CSoundInInterface() {} // /* sound card interface - used by ReadData */ // virtual void Init(int iNewBufferSize, _BOOLEAN bNewBlocking = true)=0; // virtual _BOOLEAN Read(CVector& psData)=0; // virtual void Close()=0; //}; class CSoundOutInterface { public: virtual ~CSoundOutInterface() {} /* sound card interface - used by WriteData */ // virtual void Init(int iNewBufferSize, _BOOLEAN bNewBlocking = true)=0; virtual _BOOLEAN Write(CVector& psData)=0; }; #endif qsstv_8.2.12/qsstv/sstv/modes/modeavt.cpp000664 001750 001750 00000017401 12440612574 020427 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "modeavt.h" #include "configparams.h" // one number is 1 startbit + 16 databits. #define WORDTIME (5.3108/32.) #define BITTIME (WORDTIME/17) modeAVT::modeAVT(esstvMode m,unsigned int len, bool tx):modeBase(m,len,tx) { avtTrailerDetect=true; trailerState=D1900; code=0; duration=0; } modeAVT:: ~modeAVT() { } void modeAVT::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock))/3.; } modeBase::eModeBase modeAVT::process(int *demod,unsigned int syncPos,bool goToSync) { unsigned int i=0; unsigned char a,b; if(goToSync) { if(syncPos >=length) { addToLog(QString("modebase:process: syncPos: %1 > length %2").arg(syncPos).arg(length),LOGMODES); return MBENDOFIMAGE; } else { for(i=0;i0) count --; else duration=0; } if(count>50) { count=10; trailerState=D1900END; } break; case D1900END: if(fabs(avgSample-1900.) <50.) { if(count<10) count++; } else { debugState=st1900E; if (count >0) count --; } if (count==0) { duration-=5; if((duration<(unsigned int)(0.011*rxClock)) && (duration>(unsigned int)(0.009*rxClock))) { bitCounter=0; count=10; trailerState=DELAYHALF; } else { duration=0; trailerState=D1900; } } break; case DELAYHALF: debugState=stHALF; count++; code=0; if(count>=(unsigned int)(round((BITTIME/2)*rxClock))) trailerState=BITS; break; case BITS: debugState=stBITS+bitCounter; code=code<<1; if(avgSample>1900.) code|=0x0001; bitCounter++; if (bitCounter==16) trailerState=CALCDELAY; else { count=0; trailerState=DELAYFULL; } break; case DELAYFULL: debugState=stFULL; count++; if(count>=(unsigned int)(round(BITTIME*rxClock))) trailerState=BITS; break; case CALCDELAY: //check if a=code>>8; b=(code&0xFF)^0xFF; addToLog(QString("avtcode =%1 mode=%1,pos=%1").arg(QString::number(code,16)).arg((code&0xE000)>>13).arg((code&0x1F00)>>8),LOGMODES); count=0; duration=0; if(a!=b) { trailerState=D1900; break; } a&=0x1F; delay=(unsigned int)(((31-a)*WORDTIME+BITTIME/2)*rxClock); trailerState=WAITSTART; break; case WAITSTART: debugState=stWAIT; delay--; if(delay==0) { avtTrailerDetect=false; debugState=stColorLine0; return modeBase::process(demod,i,true); } break; } } } else { return modeBase::process(demod); } return MBRUNNING; } modeBase::embState modeAVT::rxSetupLine() { start=lineTimeTableRX[lineCounter]; // addToLog(QString("modeAVT: subLine %1").arg(subLine),LOGMODES); switch(subLine) { case 0: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 1: calcPixelPositionTable(GREENLINE,false); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 2: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; return MBPIXELS; break; default: return MBENDOFLINE; } } void modeAVT::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; debugState=stColorLine0+colorLine; switch (colorLine) { case REDLINE: break; case GREENLINE: start+=(visibleLineLength); break; case BLUELINE: start+=(2.*visibleLineLength); break; } for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } } modeBase::embState modeAVT::txSetupLine() { switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 2: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 3: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 4: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 5: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 6: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; default: return MBENDOFLINE; } } qsstv_8.2.12/qsstv/sstv/modes/modeavt.h000664 001750 001750 00000004346 12440612574 020100 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef MODEAVT_H #define MODEAVT_H #include "modebase.h" /** @author Johan Maes */ class modeAVT : public modeBase { enum eTrailerState {D1900,D1900END,DELAYHALF,DELAYFULL,BITS,CALCDELAY,WAITSTART}; public: modeAVT(esstvMode m,unsigned int len,bool tx); ~modeAVT(); eModeBase process(int *demod, unsigned int syncPos=0, bool goToSync=false); protected: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); embState txSetupLine(); bool avtTrailerDetect; unsigned int duration; unsigned int bitCounter; unsigned int code; unsigned int count; eTrailerState trailerState; DSPFLOAT avgSample; unsigned int delay; }; #endif qsstv_8.2.12/qsstv/sstv/modes/modebase.cpp000664 001750 001750 00000036540 12505545767 020567 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "modebase.h" #include "qsstvglobal.h" #include "configparams.h" #include "dispatcher.h" #include "dsp/synthes.h" #include "rxwidget.h" #include "txwidget.h" #include modeBase::modeBase(esstvMode m,unsigned int len,bool tx) { mode=m; transmit=tx; length=len; greenArrayPtr=NULL; blueArrayPtr=NULL; redArrayPtr=NULL; yArrayPtr=NULL; pixelArrayPtr=NULL; pixelPositionTable=NULL; debugStatePtr=NULL; addToLog(QString("mb constructor mode=%1").arg((int) m),LOGMODES); if(transmit) { localClock=txClock; activeSSTVParam=&txSSTVParam; } else { localClock=rxClock; activeSSTVParam=&rxSSTVParam; } } modeBase::~modeBase() { deleteBuffers(); } /** \brief delete existing buffers Deletes all buffers, and sets the pointers to NULL; */ void modeBase::deleteBuffers() { if(pixelPositionTable) delete [] pixelPositionTable; if(greenArrayPtr) delete [] greenArrayPtr; if(blueArrayPtr) delete [] blueArrayPtr; if(redArrayPtr) delete [] redArrayPtr; if(yArrayPtr) delete [] yArrayPtr; if(debugStatePtr) delete [] debugStatePtr; greenArrayPtr=blueArrayPtr=redArrayPtr=yArrayPtr=NULL; } /** \brief initialize the selected mode This function initializes all buffers and mode parameters. The localClock will be set to rxClk if rxClk is not zero in receive mode, else the rxClock of the configuration will be used. The localClock is always equal to the txClock from the configuration while in transmit mode; \param[in] rxClk adjusted receive clock */ void modeBase::init(DSPFLOAT clk) { if(!transmit) { if(clk==0.) localClock=clk; else localClock=clk; } lineCounter=0; displayLineCounter=0; subLine=0; sampleCounter=0; setupSSTVLineTimeTable(mode,localClock,transmit); state=MBSETUPLINE; debugState=stHUNT; deleteBuffers(); pixelPositionTable=new unsigned int[activeSSTVParam->numberOfPixels]; greenArrayPtr=new unsigned char[activeSSTVParam->numberOfPixels]; blueArrayPtr=new unsigned char[activeSSTVParam->numberOfPixels]; redArrayPtr=new unsigned char[activeSSTVParam->numberOfPixels]; yArrayPtr=new unsigned char[activeSSTVParam->numberOfPixels]; debugStatePtr=new unsigned char [length]; for(unsigned int i=0;ifpt*localClock; bp=activeSSTVParam->bpt*localClock; blank=activeSSTVParam->blankt*localClock; } else { fp=activeSSTVParam->fp*localClock; bp=activeSSTVParam->bp*localClock; blank=activeSSTVParam->blank*localClock; } syncDuration=activeSSTVParam->sync*localClock; setupParams(localClock); activeSSTVParam->pixelDuration=visibleLineLength/(double)activeSSTVParam->numberOfPixels; // if(transmit) // { // txWidgetPtr->getImageViewerPtr()->createImage(QSize(activeSSTVParam->numberOfPixels,activeSSTVParam->numberOfDisplayLines),QColor(128,128,128)); // } // else // { // rxWidgetPtr->getImageViewerPtr()->createImage(QSize(activeSSTVParam->numberOfPixels,activeSSTVParam->numberOfDisplayLines),QColor(128,128,128)); // } } void modeBase::redrawFast(bool r) { fastRedraw=r; if (!fastRedraw) { lineDisplayEvent *ce= new lineDisplayEvent(displayLineCounter); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done } } modeBase::eModeBase modeBase::process(int *demod,unsigned int syncPos,bool goToSync) { unsigned int i=0; if(goToSync) { if(syncPos >=length) { addToLog(QString("modebase:process: syncPos: %1 > length %2").arg(syncPos).arg(length),LOGMODES); return MBENDOFIMAGE; } else { for(i=0;i=activeSSTVParam->numberOfDisplayLines) { state=MBEOIMAGE; } else { subLine=0; state=rxSetupLine(); } } pixelCounter=0; subLine++; } sample=demod[i]; debugStatePtr[i]=debugState; // pos=(++pos&DSPINPUTINDEXMASK); switch(state) { case MBPIXELS: if(getPixels()) { state=MBSETUPLINE; } break; case MBEOIMAGE: return MBENDOFIMAGE; break; case MBRXWAIT: if(sampleCounter>=marker) { // addToLog(QString("modebase:mbrxwait =%1").arg(sampleCounter+rxSampleCounter),LOGMODES); state=MBSETUPLINE; } break; case MBSYNC: { if(sampleCounter>=syncPosition) { // addToLog(QString("modebase:mbsync =%1").arg(sampleCounter+rxSampleCounter),LOGMODES); state=MBSETUPLINE; } } break; default: addToLog(QString("unknown state in modeBase: %1 receive").arg((int)state),LOGMODES); break; } sampleCounter++; } return MBRUNNING; } /** \brief transfer pixels to pixelArrayPtr This function checks the sampleCounter and stores the pixel in the pixelArray \return true if end of line (all pixels stored) */ bool modeBase::getPixels() { int color; double dev=activeSSTVParam->deviation*2; double fc=activeSSTVParam->subcarrier; if(sampleCounter>=pixelPositionTable[pixelCounter]+(activeSSTVParam->pixelDuration/2)) { // addToLog(QString("modebase:getPixels[0] =%1").arg(sampleCounter+rxSampleCounter),LOGMODES); color=128+(int)round(((double)sample-fc)*255./dev); if(color<0) color=0; if (color>255) color=255; pixelArrayPtr[pixelCounter]=(unsigned char)color; pixelCounter++; if(pixelCounter>=activeSSTVParam->numberOfPixels) return true; } return false; // indicate, it's not the end of the line } /** \brief tranfer data to rxImage (mode depended) This function is the default behaviour. it calls combineColors(). This function must be reimplemented in the derived classes for all other colour modes. */ void modeBase::showLine() { combineColors(); } /** \brief tranfer data to rxImage in RGB mode Combine R, G and B arrays (like in Martin mode) into the rxImage and advances the displayCounter */ void modeBase::combineColors() { unsigned int i; QRgb *pixelArray=rxWidgetPtr->getImageViewerPtr()->getScanLineAddress(displayLineCounter); for(i=0;inumberOfPixels;i++) { pixelArray[i]=qRgb(redArrayPtr[i],greenArrayPtr[i],blueArrayPtr[i]); // pixelArray[i]=qRgb(255,0,0); } displayLineCounter++; } /** \brief tranfer data to rxImage in grayscale Black and White image transfer. greenArray contains the luminance info. */ void modeBase::grayConversion() { unsigned int i; QRgb *pixelArray=rxWidgetPtr->getImageViewerPtr()->getScanLineAddress(displayLineCounter); for(i=0;inumberOfPixels;i++) { pixelArray[i]=qRgb(greenArrayPtr[i],greenArrayPtr[i],greenArrayPtr[i]); } displayLineCounter++; } /** \brief tranfer data to rxImage in YUV mode Combine Y, U and V arrays (like in PD modes) into the rxImage and advances the displayCounter */ void modeBase::yuvConversion(unsigned char *array) { unsigned int i; int r,g,b; QRgb *pixelArray=rxWidgetPtr->getImageViewerPtr()->getScanLineAddress(displayLineCounter); for (i=0;inumberOfPixels;i++) { r=(100*array[i]+140*redArrayPtr[i]-17850)/100; b=(100*array[i]+178*blueArrayPtr[i]-22695)/100; g=(100*array[i]- 71*redArrayPtr[i]-33*blueArrayPtr[i]+13260)/100; r=(r>255 ? 255 : r); r=(r<0 ? 0 : r); b=(b>255 ? 255 : b); b=(b<0 ? 0 : b); g=(g>255 ? 255 : g); g=(g<0 ? 0 : g); pixelArray[i]=qRgb(r,g,b); } displayLineCounter++; } modeBase::eModeBase modeBase::transmitImage(imageViewer *iv) { txImPtr=iv; if(!iv->hasValidImage()) return MBENDOFIMAGE; displayLineCounter=0; lineCounter=0; getLine(); state=MBSETUPLINE; start=0; abortRun=false; while(!abortRun) { if(state==MBSETUPLINE) { state=txSetupLine(); subLine++; pixelCounter=0; } switch (state) { case MBPIXELS: { addToLog(QString("MBPIXELS: samplcntr=%1").arg(sampleCounter),LOGMODES); sendPixelBuffer(); state=MBSETUPLINE; // check for end of subline } break; case MBTXGAP: { // addToLog(QString("MBTXGAP: samplcntr=%1").arg(sampleCounter),LOGMODES); synthesPtr->sendSamples(txDur,txFreq); //expressed in samples; sampleCounter+=txDur; state=MBSETUPLINE; } break; case MBENDOFLINE: { // addToLog(QString("MBENDOFLINE samplcntr=%1 line: %2").arg(sampleCounter).arg(lineCounter),LOGMODES); if(++lineCounter>=activeSSTVParam->numberOfDataLines) state=MBEOIMAGE; else { getLine(); state=MBSETUPLINE; subLine=0; } } break; default: // addToLog(QString("default: samplcntr=%1").arg(sampleCounter),LOGMODES); sampleCounter=0; return MBENDOFIMAGE; } } addToLog("abortrun detected",LOGMODES); return MBENDOFIMAGE; } /** \brief abort tx Only used for aborting a transmission */ void modeBase::abort() { addToLog("modebase: abort received",LOGMODES); abortRun=true; } /** \brief send pixels in the pixelArray This function sends one subLine of colour information contained in the pixelArray. */ void modeBase::sendPixelBuffer() { double f; // addToLog (QString(" sendPixelBuffer: pixelBuffer: %1").arg(QString::number((ulong)pixelArrayPtr,16)),LOGMODES); do { f=1500.+((double)pixelArrayPtr[pixelCounter]*(2300.-1500.)/255.); while(sampleCounter2300.) f=2300.; if (f<1500.) f=1500.; synthesPtr->sendSample(f); sampleCounter++; } pixelCounter++; } while(pixelCounternumberOfPixels); // addToLog(QString("modebase: lpw=%1").arg(sampleCounter),LOGMODES); } /** \brief get YUV information Get the YUV information from the image and setup the colour arrays. The displayCounter is incremented by 1 or 2, depending on the mode (e.g. 1 if Robot24 and 2 if Robot36). */ void modeBase::getLineY(bool evenodd) { // we will process 2 lines at a time // QColor c; int tO,tE; int r,yo,ye,b; if ((displayLineCounter&1) && (evenodd)) return; // only even lines accepted // txImPtr->createImage(QSize(activeSSTVParam->numberOfPixels,activeSSTVParam->numberOfDisplayLines),QColor(128,128,128)); unsigned int *pixelArrayE=txImPtr->getScanLineAddress(displayLineCounter); if (evenodd) { unsigned int *pixelArrayO=txImPtr->getScanLineAddress(displayLineCounter+1); for (unsigned int i=0;inumberOfPixels;i++) { tE=pixelArrayE[i]; ye=(59*qGreen(tE)+30*qRed(tE)+11*qBlue(tE))/100; tO=pixelArrayO[i]; yo=(59*qGreen(tO)+30*qRed(tO)+11*qBlue(tO))/100; r=(qRed(tO)+qRed(tE))/2; b=(qBlue(tO)+qBlue(tE))/2; r=(10*r-5*(yo+ye)+7*255)/14; b=(100*b-50*(yo+ye)+89*255)/178; redArrayPtr[i]=(r>255 ? 255 : r); redArrayPtr[i]=(r<0 ? 0 : r); blueArrayPtr[i]=(b>255 ? 255 : b); blueArrayPtr[i]=(b<0 ? 0 : b); yArrayPtr[i]=(ye>255 ? 255 : ye); yArrayPtr[i]=(ye<0 ? 0 : ye); greenArrayPtr[i]=(yo>255 ? 255 : yo); greenArrayPtr[i]=(yo<0 ? 0 : yo); } displayLineCounter++; } else { // addToLog(QString("getline=%1").arg(lineCounter),LOGMODES); for (unsigned int i=0;inumberOfPixels;i++) { tE=pixelArrayE[i]; ye=(59*qGreen(tE)+30*qRed(tE)+11*qBlue(tE))/100; r=qRed(tE); b=qBlue(tE); r=(10*r-10*(ye)+7*255)/14; b=(100*b-100*(ye)+89*255)/178; redArrayPtr[i]=(r>255 ? 255 : r<0 ? 0 : r); blueArrayPtr[i]=(b>255 ? 255 : b<0 ? 0 : b); yArrayPtr[i]=(ye>255 ? 255 : ye<0 ? 0 : ye); } } displayLineCounter++; } /** \brief get luminance (B&W) information Get the luminance information from the image and setup the colour array. The displayCounter is incremented */ void modeBase::getLineBW() { unsigned int t; // txImPtr->createImage(QSize(activeSSTVParam->numberOfPixels,activeSSTVParam->numberOfDisplayLines),QColor(128,128,128)); unsigned int *pixelArray=txImPtr->getScanLineAddress(displayLineCounter); for (unsigned int i=0;inumberOfPixels;i++) { t=pixelArray[i]; greenArrayPtr[i]=qGray(t); } displayLineCounter++; } /** \brief get RGB information Get the RGB information from the image and setup the colour arrays. The displayCounter is incremented */ void modeBase::getLine() { unsigned int t; // txImPtr->createImage(QSize(activeSSTVParam->numberOfPixels,activeSSTVParam->numberOfDisplayLines),QColor(128,128,128)); // addToLog (QString(" Bufferpointers: green: %1 red %2, blue %3") // .arg(QString::number((ulong)greenArrayPtr,16)) // .arg(QString::number((ulong)redArrayPtr,16)) // .arg(QString::number((ulong)blueArrayPtr,16)),LOGMODES); unsigned int *pixelArray=txImPtr->getScanLineAddress(displayLineCounter); for (unsigned int i=0;inumberOfPixels;i++) { t=pixelArray[i]; greenArrayPtr[i]=qGreen(t); redArrayPtr[i]=qRed(t); blueArrayPtr[i]=qBlue(t); // greenArrayPtr[i]=255; // redArrayPtr[i]=0; // blueArrayPtr[i]=0; } displayLineCounter++; } qsstv_8.2.12/qsstv/sstv/modes/modebase.h000664 001750 001750 00000011733 12440612574 020216 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef MODEBASE_H #define MODEBASE_H #include "../sstvparam.h" #include "widgets/imageviewer.h" #include #define stHUNT 0 #define stColorLine0 1 #define stColorLine1 2 #define stColorLine2 3 #define stColorLine3 4 #define stColorLine4 5 #define stG1 6 #define stG2 7 #define stRepTone 8 #define stWaitVIS 9 #define stSTART 10 #define stWaitSync 11 #define stFP 12 #define stBP 13 #define stSync 14 #define st1900B 15 #define st1900E 16 #define stWAIT 17 #define stHALF 18 #define stFULL 19 #define stBITS 20 class imageViewer; class modeBase { public: enum embState {MBERROR,MBSETUPLINE,MBPIXELS,MBSYNC,MBENDOFLINE,MBEOIMAGE,MBRXWAIT,MBTXGAP,MBTXGAPROBOT}; enum eModeBase {MBRUNNING,MBENDOFIMAGE}; modeBase(esstvMode m,unsigned int len,bool tx); virtual ~modeBase(); /*! \brief initialize mode specific items This function is called by modeInit(), and can overwrite some or all of the local parameters. At least it should set the visible length. \param[in] clock can be the rxClock or the txClock */ virtual void setupParams(double clock)=0; virtual bool getPixels(); virtual unsigned long adjustSyncPosition(unsigned long syncPos) { return syncPos; } void redrawFast(bool r); virtual eModeBase process(int *demod,unsigned int syncPos=0,bool goToSync=false); void init(DSPFLOAT clk); unsigned char *debugStatePtr; void abort(); esstvMode getMode() { return mode;} eModeBase transmitImage(imageViewer *iv); void setRxSampleCounter(int sc) { rxSampleCounter=sc;} void saveImage(); int receivedLines() {return displayLineCounter;} int imageLines() {return activeSSTVParam->numberOfDisplayLines;} int imagePixels() {return activeSSTVParam->numberOfPixels;} protected: DSPFLOAT visibleLineLength; esstvMode mode; bool transmit; bool fastRedraw; DSPFLOAT fp; DSPFLOAT bp; DSPFLOAT blank; DSPFLOAT syncDuration; DSPFLOAT localClock; int sample; DSPFLOAT start; sSSTVParam *activeSSTVParam; unsigned int marker; unsigned int syncPosition; unsigned int syncEndPosition; unsigned int lineCounter; unsigned int displayLineCounter; unsigned int pixelCounter; unsigned int sampleCounter; embState state; unsigned int subLine; unsigned int length; unsigned char *greenArrayPtr; unsigned char *blueArrayPtr; unsigned char *redArrayPtr; unsigned char *yArrayPtr; unsigned char *pixelArrayPtr; unsigned int *pixelPositionTable; unsigned char debugState; DSPFLOAT txFreq; unsigned int txDur; void deleteBuffers(); virtual void showLine(); void combineColors(); void yuvConversion(unsigned char *array); void grayConversion(); /*! \brief setup the rx mode timing for one subline at a time. Each line is subdivided in subLines. A subLine can be a pixel line, a delay or a sync. This function is called from the receive function in the modebase. \param subLine active phase in the reception of a image line */ virtual embState rxSetupLine()=0; /** \brief setup the tx mode timing for one subline at a time. Each line is subdivided in subLines. A subLine can be a pixel line, a delay or a sync. This function is called from transmit function in the modebase. \param subln active phase in the reception of a image line */ virtual embState txSetupLine()=0; virtual void getLine(); void getLineY(bool evenodd); void getLineBW(); int rxSampleCounter; private: void sendPixelBuffer(); bool abortRun; imageViewer *txImPtr; }; #endif qsstv_8.2.12/qsstv/sstv/modes/modebw.cpp000664 001750 001750 00000007617 12440612574 020255 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "modebw.h" #include "math.h" modeBW::modeBW(esstvMode m,unsigned int len, bool tx) : modeBase(m,len,tx) { } modeBW::~modeBW() { } void modeBW::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-syncDuration); } modeBase::embState modeBW::rxSetupLine() { start=lineTimeTableRX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,false); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: debugState=stSync; syncPosition=(unsigned int)round(lineTimeTableRX[lineCounter+1]); return MBSYNC; break; default: return MBENDOFLINE; } } void modeBW::showLine() { grayConversion(); } void modeBW::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; double start; if(tx) start=lineTimeTableTX[lineCounter]; else start=lineTimeTableRX[lineCounter]; debugState=colorLine; start+=bp; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } } modeBase::embState modeBW::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 2: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 3: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; default: return MBENDOFLINE; } } /** \brief get the pixel information for transmission in B&W */ void modeBW::getLine() { getLineBW(); } qsstv_8.2.12/qsstv/sstv/modes/modebw.h000664 001750 001750 00000005123 12440612574 017710 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODEBW_H #define MODEBW_H #include "modebase.h" /** @author Johan Maes */ class modeBW : public modeBase { public: modeBW(esstvMode m,unsigned int len, bool tx); ~modeBW(); protected: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); void showLine(); embState txSetupLine(); void getLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/modegbr.cpp000664 001750 001750 00000010737 12440612574 020414 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "modegbr.h" modeGBR::modeGBR(esstvMode m,unsigned int len, bool tx):modeBase(m,len,tx) { } modeGBR::~modeGBR() { } void modeGBR::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-2*blank-syncDuration)/3.; } modeBase::embState modeGBR::rxSetupLine() { start=lineTimeTableRX[lineCounter]; //if(subLine==0) addToLog(QString("modeGBR: subLine %1, line=%2, absSampleCounter %3").arg(subLine).arg(lineCounter).arg(start+rxSampleCounter),DBMODES); switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,false); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: debugState=stG1; marker=(unsigned int)round(start+bp+blank+visibleLineLength); return MBRXWAIT; case 2: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 3: debugState=stG2; marker=(unsigned int)round(start+bp+2*blank+2*visibleLineLength); return MBRXWAIT; case 4: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 5: debugState=stSync; syncPosition=(unsigned int) round(lineTimeTableRX[lineCounter+1]); return MBSYNC; break; default: return MBENDOFLINE; } } void modeGBR::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; debugState=stColorLine0+colorLine; switch (colorLine) { case GREENLINE: start+=bp; // addToLog(QString("calcPixelPosition: startGreen %1").arg(start+rxSampleCounter),DBMODES); break; case BLUELINE: start+=(bp+visibleLineLength+blank); // addToLog(QString("calcPixelPosition: startBlue %1").arg(start+rxSampleCounter),DBMODES); break; case REDLINE: start+=(bp+2.*visibleLineLength+2.*blank); // addToLog(QString("calcPixelPosition: startRed %1").arg(start+rxSampleCounter),DBMODES); break; } for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } } modeBase::embState modeGBR::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 2: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 3: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 4: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 5: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 6: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 7: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; default: return MBENDOFLINE; } } qsstv_8.2.12/qsstv/sstv/modes/modegbr.h000664 001750 001750 00000003600 12440612574 020050 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef MODEGBR_H #define MODEGBR_H #include "modebase.h" /** @author Johan Maes */ class modeGBR : public modeBase { public: modeGBR(esstvMode m,unsigned int len,bool tx); ~modeGBR(); protected: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); embState txSetupLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/modegbr2.cpp000664 001750 001750 00000013466 12440612574 020500 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "modegbr2.h" modeGBR2::modeGBR2(esstvMode m,unsigned int len, bool tx):modeBase(m,len,tx) { } modeGBR2::~modeGBR2() { } void modeGBR2::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-2*blank-syncDuration)/3.; } modeBase::embState modeGBR2::rxSetupLine() { // the start of the Scottie mode is always at the start of the green line start=lineTimeTableRX[lineCounter]; // if(subLine==0) addToLog(QString("modeGBR2: subLine %1, line=%2").arg(subLine).arg(lineCounter),DBMODES); switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,false); debugState=stColorLine0; pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: debugState=stG1; marker=(unsigned int)round(start+blank+visibleLineLength); return MBRXWAIT; case 2: calcPixelPositionTable(BLUELINE,false); debugState=stColorLine1; pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 3: debugState=stFP; marker=(unsigned int)round(start+blank+fp+2*visibleLineLength); return MBRXWAIT; case 4: debugState=stSync; syncPosition=syncEndPosition; return MBSYNC; case 5: debugState=stBP; marker=(unsigned int)round(syncEndPosition+bp); return MBRXWAIT; case 6: calcPixelPositionTable(REDLINE,false); debugState=stColorLine2; pixelArrayPtr=redArrayPtr; return MBPIXELS; case 7: debugState=stG1; marker=(unsigned int)round(lineTimeTableRX[lineCounter]); return MBRXWAIT; break; default: return MBENDOFLINE; } } void modeGBR2::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; debugState=colorLine; switch (colorLine) { case GREENLINE: start+=bp; // addToLog(QString("gbr2: greenstart=%1").arg(start),DBMODES); break; case BLUELINE: start+=(bp+blank+visibleLineLength); syncEndPosition=(unsigned int)(start+visibleLineLength+fp+syncDuration); // addToLog(QString("gbr2: bluestart=%1").arg(start),DBMODES); break; case REDLINE: start+=bp+fp+syncDuration+bp+blank+2.*visibleLineLength; // addToLog(QString("gbr2: redstart=%1").arg(start),DBMODES); break; } for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } } unsigned long modeGBR2::adjustSyncPosition(unsigned long syncPos) { if(syncPos<(unsigned long)(fp+2*visibleLineLength+2*blank+syncDuration)) { return syncPos+(unsigned long)(bp+visibleLineLength); } else { return syncPos-(unsigned long)(fp+2*visibleLineLength+2*blank+syncDuration); } } modeBase::embState modeGBR2::txSetupLine() { start=lineTimeTableTX[lineCounter]; // if(subLine==0) addToLog(QString("modeGBR2: subLine %1, line=%2").arg(subLine).arg(lineCounter),DBMODES); switch(subLine) { case 0: calcPixelPositionTable(GREENLINE,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 2: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 3: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 4: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 5: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; case 6: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 7: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; default: return MBENDOFLINE; } } qsstv_8.2.12/qsstv/sstv/modes/modegbr2.h000664 001750 001750 00000005231 12440612574 020134 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODEGBR2_H #define MODEGBR2_H #include "modebase.h" /** @author Johan Maes */ class modeGBR2 : public modeBase { public: modeGBR2(esstvMode m,unsigned int len,bool tx); ~modeGBR2(); protected: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); unsigned long adjustSyncPosition(unsigned long syncPos); // int adaptStartPosition(bool vertRetrace); embState txSetupLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/modepd.cpp000664 001750 001750 00000015165 12440612574 020245 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "modepd.h" modePD::modePD(esstvMode m,unsigned int len,bool tx): modeBase(m,len,tx) { } modePD::~modePD() { } void modePD::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-3*blank-syncDuration)/4; } modeBase::embState modePD::rxSetupLine() { start=lineTimeTableRX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(YLINEODD,false); addToLog(QString("yOdd %1").arg(pixelPositionTable[0]),LOGMODES); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 1: debugState=stG1; start=lineTimeTableRX[lineCounter]; marker=(unsigned int)round(start+bp+blank+visibleLineLength); addToLog(QString("mrk1 %1").arg(marker),LOGMODES); return MBRXWAIT; case 2: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; addToLog(QString("red %1").arg(pixelPositionTable[0]),LOGMODES); return MBPIXELS; case 3: debugState=stG1; start=lineTimeTableRX[lineCounter]; marker=(unsigned int)round(start+bp+2*blank+2*visibleLineLength); addToLog(QString("mrk2 %1").arg(marker),LOGMODES); return MBRXWAIT; case 4: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; addToLog(QString("blue %1").arg(pixelPositionTable[0]),LOGMODES); return MBPIXELS; case 5: debugState=stG1; start=lineTimeTableRX[lineCounter]; marker=(unsigned int)round(start+bp+3*blank+3*visibleLineLength); addToLog(QString("mrk3 %1").arg(marker),LOGMODES); return MBRXWAIT; case 6: calcPixelPositionTable(YLINEEVEN,false); pixelArrayPtr=greenArrayPtr; addToLog(QString("yEven %1").arg(pixelPositionTable[0]),LOGMODES); return MBPIXELS; case 7: debugState=stSync; syncPosition=(unsigned int)round(lineTimeTableRX[lineCounter+1]); return MBSYNC; default: return MBENDOFLINE; } } void modePD::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; double start; if(tx) start=lineTimeTableTX[lineCounter]; else start=lineTimeTableRX[lineCounter]; debugState=colorLine; switch (colorLine) { case YLINEODD: start+=bp; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case REDLINE: start+=(bp+blank+visibleLineLength); for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case BLUELINE: start+=bp+2*blank+2*visibleLineLength; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case YLINEEVEN: start+=bp+(3*blank+3*visibleLineLength); for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; } } void modePD::showLine() { yuvConversion(yArrayPtr); yuvConversion(greenArrayPtr); } modeBase::embState modePD::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(YLINEODD,true); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 2: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 3: txFreq=1500; txDur=(unsigned int)rint(blank); return MBTXGAP; case 4: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 5: txFreq=1500; txDur=(unsigned int)rint(blank); return MBTXGAP; case 6: calcPixelPositionTable(YLINEEVEN,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 7: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 8: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 9: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; default: // lineCounter++; return MBENDOFLINE; } } void modePD::getLine() { getLineY(true); } qsstv_8.2.12/qsstv/sstv/modes/modepd.h000664 001750 001750 00000005114 12440612574 017703 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODEPD_H #define MODEPD_H #include "modebase.h" /** @author Johan Maes */ class modePD : public modeBase { public: modePD(esstvMode m,unsigned int len,bool tx); ~modePD(); protected: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); void showLine(); embState txSetupLine(); void getLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/modergb.cpp000664 001750 001750 00000011635 12440612574 020412 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "modergb.h" modeRGB::modeRGB(esstvMode m,unsigned int len, bool tx):modeBase(m,len,tx) { } #define MODERGBDEBUG modeRGB::~modeRGB() { } void modeRGB::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-2*blank-syncDuration)/3.; } modeBase::embState modeRGB::rxSetupLine() { start=lineTimeTableRX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 1: debugState=stG1; marker=(unsigned int)round(start+blank+visibleLineLength); return MBRXWAIT; case 2: calcPixelPositionTable(GREENLINE,false); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 3: debugState=stG1; marker=(unsigned int)round(start+2*blank+2*visibleLineLength); return MBRXWAIT; case 4: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 5: debugState=stFP; marker=(unsigned int)round(start+2*blank+3*visibleLineLength+fp); return MBRXWAIT; case 6: debugState=stSync; syncPosition=(unsigned int)round(lineTimeTableRX[lineCounter+1]-bp); return MBSYNC; case 7: debugState=stBP; marker=(unsigned int)round(lineTimeTableRX[lineCounter+1]); return MBRXWAIT; default: return MBENDOFLINE; } } void modeRGB::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; debugState=colorLine; switch (colorLine) { case REDLINE: start+=bp; break; case GREENLINE: start+=bp+blank+visibleLineLength; break; case BLUELINE: start+=bp+2.*blank+2.*visibleLineLength; break; } for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } } modeBase::embState modeRGB::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 2: calcPixelPositionTable(GREENLINE,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 3: txFreq=1500.; txDur=(unsigned int)rint(blank); return MBTXGAP; case 4: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 5: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 6: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 7: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; default: return MBENDOFLINE; } } qsstv_8.2.12/qsstv/sstv/modes/modergb.h000664 001750 001750 00000005052 12440612574 020053 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODERGB_H #define MODERGB_H #include "modebase.h" /** @author Johan Maes */ class modeRGB : public modeBase { public: modeRGB(esstvMode m,unsigned int len,bool tx); ~modeRGB(); private: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); embState txSetupLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/moderobot1.cpp000664 001750 001750 00000015331 12440612574 021043 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "moderobot1.h" modeRobot1::modeRobot1(esstvMode m,unsigned int len, bool tx):modeBase(m,len,tx) { } modeRobot1::~modeRobot1() { } void modeRobot1::setupParams(double clock) { visibleLineLength=(lineLength(mode,clock)-fp-bp-blank-syncDuration)/3.; } modeBase::embState modeRobot1::rxSetupLine() { start=lineTimeTableRX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(YLINEODD,false); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 1: debugState=stG1; marker=(unsigned int)round(start+blank+2*visibleLineLength); return MBRXWAIT; case 2: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 3: debugState=stFP; marker=(unsigned int)round(start+blank+3*visibleLineLength+fp); return MBRXWAIT; case 4: debugState=stSync; syncPosition=(unsigned int)round(lineTimeTableRX[lineCounter+1]-bp); return MBSYNC; case 5: debugState=stBP; marker=(unsigned int)round(lineTimeTableRX[lineCounter]); lineCounter++; return MBRXWAIT; case 6: calcPixelPositionTable(YLINEEVEN,false); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 7: debugState=stG1; marker=(unsigned int)round(lineTimeTableRX[lineCounter]+blank+2*visibleLineLength); return MBRXWAIT; case 8: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 9: debugState=stFP; marker=(unsigned int)round(start+blank+3*visibleLineLength+fp); return MBRXWAIT; case 10: debugState=stSync; syncPosition=(unsigned int)round(lineTimeTableRX[lineCounter+1]-bp); return MBSYNC; case 11: debugState=stBP; marker=(unsigned int)round(lineTimeTableRX[lineCounter+1]); return MBRXWAIT; default: return MBENDOFLINE; } } void modeRobot1::showLine() { yuvConversion(yArrayPtr); yuvConversion(greenArrayPtr); } void modeRobot1::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; double start; if(tx) start=lineTimeTableTX[lineCounter]; else start=lineTimeTableRX[lineCounter]; debugState=colorLine; switch (colorLine) { case YLINEODD: case YLINEEVEN: start+=bp; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength*2)/activeSSTVParam->numberOfPixels)); } break; case REDLINE: start+=bp+blank+visibleLineLength*2; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]= (unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case BLUELINE: start+=bp+blank+visibleLineLength*2; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]= (unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; } } /** \todo resync odd/even line via frequency detection */ modeBase::embState modeRobot1::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: calcPixelPositionTable(YLINEODD,true); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 1: txFreq=1500.; txDur=(unsigned int)rint((2*blank)/3); return MBTXGAP; case 2: txFreq=1900.; txDur=(unsigned int)rint(blank/3); return MBTXGAP; case 3: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 4: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 5: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 6: txFreq=1500; txDur=(unsigned int)rint(bp); lineCounter++; return MBTXGAP; case 7: calcPixelPositionTable(YLINEEVEN,true); pixelArrayPtr=greenArrayPtr; return MBPIXELS; case 8: txFreq=2300.; txDur=(unsigned int)rint((2*blank)/3); return MBTXGAP; case 9: txFreq=1900.; txDur=(unsigned int)rint(blank/3); return MBTXGAP; case 10: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 11: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 12: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; case 13: txFreq=1500; txDur=(unsigned int)rint(bp); return MBTXGAP; default: return MBENDOFLINE; } } void modeRobot1::getLine() { getLineY(true); } qsstv_8.2.12/qsstv/sstv/modes/moderobot1.h000664 001750 001750 00000005140 12440612574 020505 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODEROBOT1_H #define MODEROBOT1_H #include "modebase.h" /** @author Johan Maes */ class modeRobot1 : public modeBase { public: modeRobot1 (esstvMode m,unsigned int len,bool tx); ~modeRobot1(); private: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); void showLine(); embState txSetupLine(); void getLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/moderobot2.cpp000664 001750 001750 00000013652 12440612574 021050 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "moderobot2.h" modeRobot2::modeRobot2(esstvMode m,unsigned int len,bool tx): modeBase(m,len,tx) { } modeRobot2::~modeRobot2() { } void modeRobot2::setupParams(double clock) { //double tmp=(activeSSTVParam->imageTime/(double)activeSSTVParam->numberOfDataLines)*clock; //visibleLineLength=(tmp-fp-bp-2*blank-syncDuration)/4; visibleLineLength=(lineLength(mode,clock)-fp-bp-2*blank-syncDuration)/4.; } modeBase::embState modeRobot2::rxSetupLine() { start=lineTimeTableRX[lineCounter]; switch(subLine) { case 0: debugState=stBP; // marker=(unsigned int)round(lineTimeTable[lineCounter])-1; marker=(unsigned int)rint(start+bp); return MBRXWAIT; case 1: calcPixelPositionTable(YLINEODD,false); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 2: debugState=stG1; marker=(unsigned int)rint(start+bp+blank+2*visibleLineLength); return MBRXWAIT; case 3: calcPixelPositionTable(REDLINE,false); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 4: debugState=stG1; marker=(unsigned int)rint(start+bp+2*blank+3*visibleLineLength); return MBRXWAIT; case 5: calcPixelPositionTable(BLUELINE,false); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 6: debugState=stFP; marker=(unsigned int)rint(start+bp+2*blank+4*visibleLineLength+fp); return MBRXWAIT; case 7: debugState=stSync; syncPosition=(unsigned int)rint(lineTimeTableRX[lineCounter+1]); return MBSYNC; default: return MBENDOFLINE; } } void modeRobot2::showLine() { yuvConversion(yArrayPtr); } void modeRobot2::calcPixelPositionTable(unsigned int colorLine,bool tx) { unsigned int i; int ofx=0; if(tx) ofx=1; double start; if (tx) start=lineTimeTableTX[lineCounter]; else start=lineTimeTableRX[lineCounter]; debugState=colorLine; if (tx) start+=9; switch (colorLine) { case YLINEODD: start+=bp; for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*2*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case REDLINE: start+=(bp+blank+2*visibleLineLength); for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)round(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; case BLUELINE: start+=(bp+2*blank+3*visibleLineLength); for(i=0;inumberOfPixels;i++) { pixelPositionTable[i]=(unsigned int)(round)(start+(((float)(i+ofx)*visibleLineLength)/activeSSTVParam->numberOfPixels)); } break; } } modeBase::embState modeRobot2::txSetupLine() { start=lineTimeTableTX[lineCounter]; switch(subLine) { case 0: txFreq=1500; txDur=(unsigned int)rint(bp+6); return MBTXGAP; case 1: calcPixelPositionTable(YLINEODD,true); pixelArrayPtr=yArrayPtr; return MBPIXELS; case 2: txFreq=1500.; txDur=(unsigned int)rint((2*blank)/3); return MBTXGAP; case 3: txFreq=1900.; txDur=(unsigned int)rint(blank/3); return MBTXGAP; case 4: calcPixelPositionTable(REDLINE,true); pixelArrayPtr=redArrayPtr; return MBPIXELS; case 5: txFreq=2300.; txDur=(unsigned int)rint((2*blank)/3); return MBTXGAP; case 6: txFreq=1900.; txDur=(unsigned int)rint(blank/3); return MBTXGAP; case 7: calcPixelPositionTable(BLUELINE,true); pixelArrayPtr=blueArrayPtr; return MBPIXELS; case 8: txFreq=1500; txDur=(unsigned int)rint(fp); return MBTXGAP; case 9: txFreq=1200; txDur=(unsigned int)rint(syncDuration); return MBTXGAP; default: return MBENDOFLINE; } } void modeRobot2::getLine() { getLineY(false); } qsstv_8.2.12/qsstv/sstv/modes/moderobot2.h000664 001750 001750 00000005135 12440612574 020512 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef MODEROBOT2_H #define MODEROBOT2_H #include "modebase.h" /** @author Johan Maes */ class modeRobot2 : public modeBase { public: modeRobot2(esstvMode m,unsigned int len,bool tx); ~modeRobot2(); private: embState rxSetupLine(); void calcPixelPositionTable(unsigned int colorLine,bool tx); void setupParams(double clock); void showLine(); embState txSetupLine(); void getLine(); }; #endif qsstv_8.2.12/qsstv/sstv/modes/modes.h000664 001750 001750 00000003331 12440612574 017541 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef MODES_H #define MODES_H #include "modegbr.h" #include "modegbr2.h" #include "modergb.h" #include "moderobot1.h" #include "moderobot2.h" #include "modepd.h" #include "modebw.h" #include "modeavt.h" #endif qsstv_8.2.12/qsstv/drmrx/bits2bytes.cpp000664 001750 001750 00000007322 12440612574 020111 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 23.07.2004 */ /* Last change : 23.07.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* bits2bytes.c */ /* */ /******************************************************************************/ /* Description: */ /* Deinterleaver/Interleaver generation for DRM frames */ /* Usage: */ /* */ /* bytes = bits2bytes(bits); */ /* */ /* converts a serial double bit-stream into a uint8 byte-stream */ /******************************************************************************/ /* * modified for use directly in C-language without Matlab interface * M.Bos - PA0MBO * Date Nov 15th 2007 * */ #include #include #include #include void bits2bytes(double *inbits, int N, unsigned char /*@out@ */ *outbytes) { unsigned char single_byte; int m, n; if (N % 8 != 0) { return; } for (m = 0; m < N / 8; m++) { single_byte = '\0'; for (n = 7; n >= 0; n--) { single_byte |= ((fabs(inbits[8 * m + 7 - n]) > DBL_EPSILON) & 0x01) << n; } outbytes[m] = single_byte; } return; } qsstv_8.2.12/qsstv/drmrx/channeldecode.cpp000664 001750 001750 00000103056 12440612574 020574 0ustar00jomajoma000000 000000 /* * file channeldecode.c * * Author M.Bos - PA0MBO * Date Feb 21st 2009 * * superframe sync of drm demapping * deinterleaving channel decoding of FAC and MSC frame * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include #include #include "structtemplates.h" #include "drmproto.h" #include "drmdefs.h" #include #include "configparams.h" #define PI (4.0*atan(1.0)) #define CHANNELDECODING 1 char localDrmCallsign[9]= {0, 0, 0, 0, 0, 0, 0, 0, 0}; //changed joma #define MSD_ITER 4 extern int transmission_frame_buffer_data_valid; extern int fac_valid; extern int robustness_mode; extern int spectrum_occupancy; extern int symbols_per_frame; extern int K_modulo; extern int K_dc; extern float mean_energy_of_used_cells; extern int FAC_cells_k[65]; extern float transmission_frame_buffer[82980]; extern float channel_transfer_function_buffer[82980]; extern int transmission_frame_buffer_wptr; extern int lFAC; extern int runstate; extern struct mplex_desc multiplex_description; extern struct audio_info audio_information; extern struct appl_info application_information; extern struct stream_info stream_information; extern struct time_info time_and_date; extern int channel_decoded_data_buffer_data_valid; extern double channel_decoded_data_buffer[110000]; extern int audio_data_flag; extern int length_decoded_data; extern int MSC_Demapper[6][2959]; int lMSC; // joma float MSC_cells_sequence[2 * 2959]; //joma bool MSCAvailable; int spectrum_occupancy_new; int msc_mode_new; int interleaver_depth_new; bool callsignValid; char getfacchar(double *); void channel_decoding(void) { static int /*@only@ */ *FAC_Deinterleaver; static double RX[13] = { 1, 3, 1, 4, 1, 4, 3, 2, 8, 3, 4, 7, 8 }; static double RY[13] = { 4, 10, 3, 11, 2, 7, 5, 3, 11, 4, 5, 8, 9 }; // static int RYlcmSM16[2] = { 3, 4 }; // static int RYlcmSM64[4] = { 4, 15, 8, 45 }; static int RatesSM16[2][2] = { {3, 8}, {5, 10} }; static int RatesSM64[4][3] = { {1, 5, 10}, {3, 8, 11}, {5, 10, 12}, {8, 11, 13} }; static int frame_index; static int enough_frames; static int frame_count; static int msc_parameters_valid; static int robustness_mode_old; // static int sdc_mode; static int msc_mode; static int interleaver_depth; // static float z_SDC[2]; static int MSC_Demapper_symbolwise[6][2959]; static double SNR_estimation[2959]; static double squared_noise_signal_buffer[121490]; static double noise_power_density[461]; static int SNR_estimation_valid; // int audio_service_index; int i, j, k, n; // int iterations; static int msc_parameters_changed; // static int sdc_parameters_changed; int symbol_period; int trxfrmbufptr; double received_real[3000], received_imag[3000], snr[3000]; float transfer_function_FAC[3000]; /* complex */ static double L[6]; static double L_FAC[4]; static int PL[6]; static int PL_FAC[4]; static double fac_data[72]; double checksum; static double channel_parameters[20]; // static double service_parameters[44]; double facblock[72]; double temp; static int identity; static int identityCount; static int old_ptr; static int MSC_carrier_usage[288]; static int cnt_MSC_used_carriers; static int MSC_used_carriers[288]; static int min_index_equal_samples; static int max_index_equal_samples; static int /*@only@ */ *Part_Deinterleaver = NULL; static int Deinterleaver[18000]; int no_of_streams = 1; static int N_MUX; // static int rylcm; static int N1, N2; static int ratesA[3], ratesB[3], Lvspp, xin1, xin2; float sum1; float transfer_function_MSC[2 * 2959]; /* complex nrs */ static int rowdimL, coldimL; double SPPhard[10628]; int n_SPPhard; double VSPPhard[100]; static double res_iters, calc_variance; static double noise_signal[2 * 2959]; static double squared_noise_signal[2959]; // static double calc_weighted_variance; double sum2; double weighted_noise_power_density[288]; // double signal_to_noise_ratio[288]; // static int cnt_npwrpos; // static int noise_power_positions[288]; double samples_resorted[288][15]; int posrow, poscolumn, totindex; int VSPPlength, HPPlength; int Tu_list[] = { Tu_A, Tu_B, Tu_C, Tu_D }; double part1, part2; if (runstate == RUN_STATE_POWER_ON) { if (FAC_Deinterleaver != NULL) free(FAC_Deinterleaver); FAC_Deinterleaver = deinterleaver(0, 1, 90, 21); return; } if (runstate == RUN_STATE_INIT) { transmission_frame_buffer_wptr = 0; frame_index = 1; enough_frames = 0; frame_count = 0; msc_parameters_valid = 0; robustness_mode_old = -1; // sdc_mode = -1; msc_mode = -1; interleaver_depth = -1; // z_SDC[0] = 0.0; /* complex */ // z_SDC[1] = 1.0E-12; fac_valid = -1; multiplex_description.HM_length = 0; callsignValid=false; return; } channel_decoded_data_buffer_data_valid = 0; if (transmission_frame_buffer_data_valid == 0) { MSCAvailable=false; /* clear various datastructures */ frame_index = 1; enough_frames = 0; frame_count = 0; msc_parameters_valid = 0; transmission_frame_buffer_wptr = 0; multiplex_description.PL_PartA = -1; multiplex_description.PL_PartB = -1; multiplex_description.HM_length = 0; multiplex_description.PL_HM = -1; audio_information.ID[0] = 0; audio_information.ID[1] = 0; audio_information.ID[2] = 0; audio_information.ID[3] = 0; audio_information.stream_ID[0] = -1; audio_information.stream_ID[1] = -1; audio_information.stream_ID[2] = -1; audio_information.stream_ID[3] = -1; audio_information.audio_coding[0] = 0; audio_information.audio_coding[1] = 0; audio_information.audio_coding[2] = 0; audio_information.audio_coding[3] = 0; audio_information.SBR_flag[0] = 0; audio_information.SBR_flag[1] = 0; audio_information.SBR_flag[2] = 0; audio_information.SBR_flag[3] = 0; audio_information.audio_mode[0] = 0; audio_information.audio_mode[1] = 0; audio_information.audio_mode[2] = 0; audio_information.audio_mode[3] = 0; audio_information.sampling_rate[0] = 0; audio_information.sampling_rate[1] = 0; audio_information.sampling_rate[2] = 0; audio_information.sampling_rate[3] = 0; audio_information.text_flag[0] = 0; audio_information.text_flag[1] = 0; audio_information.text_flag[2] = 0; audio_information.text_flag[3] = 0; audio_information.enhancement_flag[0] = 0; audio_information.enhancement_flag[1] = 0; audio_information.enhancement_flag[2] = 0; audio_information.enhancement_flag[3] = 0; audio_information.coder_field[0] = 0; audio_information.coder_field[1] = 0; audio_information.coder_field[2] = 0; audio_information.coder_field[3] = 0; audio_information.bytes_per_frame[0] = 0; audio_information.bytes_per_frame[1] = 0; audio_information.bytes_per_frame[2] = 0; audio_information.bytes_per_frame[3] = 0; application_information.ID[0] = 0; application_information.ID[1] = 0; application_information.ID[2] = 0; application_information.ID[3] = 0; application_information.stream_ID[0] = -1; application_information.stream_ID[1] = -1; application_information.stream_ID[2] = -1; application_information.stream_ID[3] = -1; application_information.packet_mode[0] = 0; application_information.packet_mode[1] = 0; application_information.packet_mode[2] = 0; application_information.packet_mode[3] = 0; application_information.data_unit_indicator[0] = 0; application_information.data_unit_indicator[1] = 0; application_information.data_unit_indicator[2] = 0; application_information.data_unit_indicator[3] = 0; application_information.packet_ID[0] = 0; application_information.packet_ID[1] = 0; application_information.packet_ID[2] = 0; application_information.packet_ID[3] = 0; application_information.enhancement_flag[0] = 0; application_information.enhancement_flag[1] = 0; application_information.enhancement_flag[2] = 0; application_information.enhancement_flag[3] = 0; application_information.application_domain[0] = 0; application_information.application_domain[1] = 0; application_information.application_domain[2] = 0; application_information.application_domain[3] = 0; application_information.packet_length[0] = 0; application_information.packet_length[1] = 0; application_information.packet_length[2] = 0; application_information.packet_length[3] = 0; application_information.user_application_type[0] = 0; application_information.user_application_type[1] = 0; application_information.user_application_type[2] = 0; application_information.user_application_type[3] = 0; application_information.user_application_identifier[0] = 0; application_information.user_application_identifier[1] = 0; application_information.user_application_identifier[2] = 0; application_information.user_application_identifier[3] = 0; application_information.label[0][0] = '\0'; application_information.label[1][0] = '\0'; application_information.label[2][0] = '\0'; application_information.label[3][0] = '\0'; application_information.country[0][0] = '\0'; application_information.country[1][0] = '\0'; application_information.country[2][0] = '\0'; application_information.country[3][0] = '\0'; application_information.language_code[0] = 0; application_information.language_code[1] = 0; application_information.language_code[2] = 0; application_information.language_code[3] = 0; application_information.programme_type_code[0] = 0; application_information.programme_type_code[1] = 0; application_information.programme_type_code[2] = 0; application_information.programme_type_code[3] = 0; application_information.bytes_per_frame[0] = 0;; application_information.bytes_per_frame[1] = 0;; application_information.bytes_per_frame[2] = 0;; application_information.bytes_per_frame[3] = 0;; stream_information.number_of_audio_services = 0; stream_information.number_of_data_services = 0; stream_information.number_of_streams = 0; stream_information.number_of_audio_streams = 0; stream_information.number_of_data_streams = 0; time_and_date.day = -1; time_and_date.month = -1; time_and_date.year = -1; time_and_date.hours = -1; time_and_date.minutes = -1; // sdc_mode = -1; msc_mode = -1; robustness_mode_old = -1; interleaver_depth = -1; for (i = 0; i < 41490; i++) squared_noise_signal_buffer[i] = 0.0; for (i = 0; i < 461; i++) noise_power_density[i] = 0.0; SNR_estimation_valid = 0; fac_valid = -1; // audio_service_index = 1; return; } symbol_period = Tu_list[robustness_mode]; if (CHANNELDECODING == 0) { frame_index = (frame_index % 6) + 1; /* in matlab check for existence of symbol_period & symbols_per_frame */ if ((symbol_period != -1) & (symbols_per_frame != -1)) { transmission_frame_buffer_wptr = (transmission_frame_buffer_wptr + symbol_period * symbols_per_frame) % (symbol_period * symbols_per_frame * 6); } SNR_estimation_valid = 0; return; } // iterations = 0; calc_variance = -0.05; msc_parameters_changed = 0; if (robustness_mode != robustness_mode_old) { if (robustness_mode < 0) return; symbol_period = Tu_list[robustness_mode]; lFAC = mkfacmap(robustness_mode, K_dc, K_modulo, FAC_cells_k); } /* FAC decoding */ fac_valid = 1; for (i = 0; i < lFAC; i++) { trxfrmbufptr = (frame_index - 1) * symbol_period * symbols_per_frame + FAC_cells_k[i]; received_real[i] = (double) transmission_frame_buffer[2 * trxfrmbufptr]; received_imag[i] = (double) transmission_frame_buffer[2 * trxfrmbufptr + 1]; transfer_function_FAC[i * 2] = channel_transfer_function_buffer[2 * trxfrmbufptr]; transfer_function_FAC[i * 2 + 1] = channel_transfer_function_buffer[2 * trxfrmbufptr + 1]; snr[i] = sqrt(transfer_function_FAC[i * 2] * transfer_function_FAC[i * 2] + transfer_function_FAC[i * 2 + 1] * transfer_function_FAC[i * 2 + 1]); } received_real[9] = 0.0; received_imag[9] = 0.0; L_FAC[0] = 0.0; L_FAC[1] = 48.0; PL_FAC[0] = 0; PL_FAC[1] = 6; (void) msdhardfac(received_real, received_imag, lFAC, snr, 0, L_FAC, 2, 0, FAC_Deinterleaver, PL_FAC, 4, 0, fac_data); for (i = 0; i < 40; i++) { facblock[i] = fac_data[i]; } for (i = 40; i < 48; i++) { facblock[i] = 1.0 - fac_data[i]; } for (i = 0; i < 10; i++) { channel_parameters[i] = fac_data[i]; } crc8_c(&checksum, facblock, 48); if (fabs(checksum) > DBL_EPSILON) { spectrum_occupancy = -1; fac_valid = 0; identityCount=0; msc_parameters_valid = 0 ; /* added pa0mbo 23 nov 2011 */ return; } msc_parameters_valid = 1; /* frame alignment */ temp = 2.0 * channel_parameters[0] + channel_parameters[1]; identity = (int) temp % 3; if (identity != ((frame_index - 1) % 3)) { old_ptr = transmission_frame_buffer_wptr; transmission_frame_buffer_wptr = identity * symbol_period * symbols_per_frame; for (i = 0; i < symbol_period * symbols_per_frame; i++) { trxfrmbufptr = transmission_frame_buffer_wptr + i; transmission_frame_buffer[2 * trxfrmbufptr] = transmission_frame_buffer[2 * (old_ptr + i)]; transmission_frame_buffer[2 * trxfrmbufptr + 1] = transmission_frame_buffer[2 * (old_ptr + i) + 1]; channel_transfer_function_buffer[2 * trxfrmbufptr] = channel_transfer_function_buffer[2 * (old_ptr + i)]; channel_transfer_function_buffer[2 * trxfrmbufptr + 1] = channel_transfer_function_buffer[2 * (old_ptr + i) + 1]; } frame_index = identity + 1; } interleaver_depth_new = (int) channel_parameters[3]; msc_mode_new = (int) channel_parameters[4]; if (fabs(channel_parameters[6] - 1.0) < DBL_EPSILON) { msc_mode_new = msc_mode_new + 2 * (int) channel_parameters[9]; } spectrum_occupancy_new = (int) channel_parameters[2]; if (spectrum_occupancy_new > 1) { spectrum_occupancy = -1; fac_valid = 0; identityCount=0; return; } identityCount++; audio_data_flag = (int) channel_parameters[6]; // we need 3 consequetive valid fac's to have a complete call /* decoding of text in fac data */ localDrmCallsign[3*identity] = getfacchar(&facblock[10]); localDrmCallsign[3*identity+1] = getfacchar(&facblock[17]); localDrmCallsign[3*identity+2] = getfacchar(&facblock[24]); localDrmCallsign[3*identity+3] = '\0'; if ((identity == 2) && (identityCount>=3)) { identityCount=0; drmCallsign=localDrmCallsign; callsignValid=true; } if ((spectrum_occupancy != spectrum_occupancy_new) || (robustness_mode_old != robustness_mode)) { spectrum_occupancy = spectrum_occupancy_new; interleaver_depth = interleaver_depth_new; lMSC = mkmscmap(robustness_mode, spectrum_occupancy, interleaver_depth, K_dc, K_modulo); for (j = 0; j < 6; j++) { for (i = 0; i < lMSC; i++) { MSC_Demapper_symbolwise[j][i] = MSC_Demapper[j][i] % symbol_period; } } /* do the binning and calc carrier usage */ for (i = 0; i < symbol_period; i++) { MSC_carrier_usage[i] = 0; for (j = 0; j < 6; j++) { for (k = 0; k < lMSC; k++) { if (MSC_Demapper_symbolwise[j][k] == i) { (MSC_carrier_usage[i])++; } } } } cnt_MSC_used_carriers = 0; for (i = 0; i < symbol_period; i++) { if (MSC_carrier_usage[i] != 0) { MSC_used_carriers[cnt_MSC_used_carriers++] = i; } } msc_parameters_changed = 1; // sdc_parameters_changed = 1; } else { if (interleaver_depth != interleaver_depth_new) { interleaver_depth = interleaver_depth_new; lMSC = mkmscmap(robustness_mode, spectrum_occupancy, interleaver_depth,K_dc, K_modulo); /* do the binning and calc carrier usage */ for (i = 0; i < symbol_period; i++) { MSC_carrier_usage[i] = 0; for (j = 0; j < 6; j++) { for (k = 0; k < lMSC; k++) { if (MSC_Demapper_symbolwise[j][k] == i) { (MSC_carrier_usage[i])++; } } } } cnt_MSC_used_carriers = 0; for (i = 0; i < symbol_period; i++) { if (MSC_carrier_usage[i] != 0) { MSC_used_carriers[cnt_MSC_used_carriers++] = i; } } msc_parameters_changed = 1; } } robustness_mode_old = robustness_mode; interleaver_depth = interleaver_depth_new; /* frame count : deinterleaving possible after 2 received frames for short and after 6 received frames for long interleaving */ frame_count++; if (frame_count >= 6 - 4 * interleaver_depth) { enough_frames = 1; } else { if (frame_count == 1) { min_index_equal_samples = transmission_frame_buffer_wptr; max_index_equal_samples = transmission_frame_buffer_wptr + symbol_period * symbols_per_frame; } else { if (transmission_frame_buffer_wptr < min_index_equal_samples) { min_index_equal_samples = transmission_frame_buffer_wptr; } if (transmission_frame_buffer_wptr + symbol_period * symbols_per_frame > max_index_equal_samples) { max_index_equal_samples = transmission_frame_buffer_wptr + symbol_period * symbols_per_frame; } } } if (msc_mode != msc_mode_new) { msc_mode = msc_mode_new; msc_parameters_changed = 1; msc_parameters_valid = 1; } multiplex_description.HM_length = 0; multiplex_description.PL_HM = 0; if (fabs(fac_data[5] - 1.0) < DBL_EPSILON) { multiplex_description.PL_PartA = 1; multiplex_description.PL_PartB = 1; } else { multiplex_description.PL_PartA = 0; multiplex_description.PL_PartB = 0; } application_information.stream_ID[0] = 0; application_information.stream_ID[1] = -1; application_information.stream_ID[2] = -1; application_information.stream_ID[3] = -1; application_information.packet_mode[0] = 1; application_information.packet_mode[1] = 0; application_information.packet_mode[2] = 0; application_information.packet_mode[3] = 0; application_information.data_unit_indicator[0] = 1; application_information.data_unit_indicator[1] = 0; application_information.data_unit_indicator[2] = 0; application_information.data_unit_indicator[3] = 0; application_information.application_domain[0] = 1; application_information.application_domain[1] = 0; application_information.application_domain[2] = 0; application_information.application_domain[3] = 0; for (i = 0; i < 16; i++) application_information.application_data[0][i] = 0; /* *** MSC DECODING *** */ N_MUX = lMSC; /* MSC parameters settings */ if ((msc_parameters_changed == 1) && (msc_parameters_valid == 1)) { if (msc_mode == 0) /* 64-QAM SM */ { // rylcm = RYlcmSM64[multiplex_description.PL_PartA]; for (i = 0; i < 3; i++) { ratesA[i] = RatesSM64[multiplex_description.PL_PartA][i] - 1; } N1 = 0; N2 = N_MUX - N1; for (i = 0; i < 3; i++) { ratesB[i] = RatesSM64[multiplex_description.PL_PartB][i] - 1; } for (i = 0; i < 3; i++) { L[i] = 2 * N1 * (RX[ratesA[i]] / RY[ratesA[i]]); L[i + 3] = (RX[ratesB[i]] * floor((2 * N2 - 12) / RY[ratesB[i]])); } Lvspp = 0; rowdimL = 3; coldimL = 2; xin1 = 2 * N1; xin2 = 2 * N2; for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i] = i; if (Part_Deinterleaver != NULL) free(Part_Deinterleaver); Part_Deinterleaver = deinterleaver(xin1, 13, xin2, 13); for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i + xin1 + xin2] = Part_Deinterleaver[i]; free(Part_Deinterleaver); Part_Deinterleaver = deinterleaver(xin1, 21, xin2, 21); for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i + 2 * (xin1 + xin2)] = Part_Deinterleaver[i]; for (i = 0; i < 3; i++) { PL[i] = ratesA[i]; PL[i + 3] = ratesB[i]; } } else if (msc_mode == 1) /* 16-QAM SM */ { // rylcm = RYlcmSM16[multiplex_description.PL_PartA]; for (i = 0; i < 2; i++) //joma { ratesA[i] = RatesSM16[multiplex_description.PL_PartA][i] - 1; } N1 = 0; N2 = N_MUX - N1; for (i = 0; i < 2; i++) //joma { ratesB[i] = RatesSM16[multiplex_description.PL_PartB][i] - 1; } for (i = 0; i < 2; i++) { L[i] = 2 * N1 * (RX[ratesA[i]] / RY[ratesA[i]]); L[i + 2] = (RX[ratesB[i]] * floor((2 * N2 - 12) / RY[ratesB[i]])); } rowdimL = 2; coldimL = 2; Lvspp = 0; xin1 = 2 * N1; xin2 = 2 * N2; if (Part_Deinterleaver != NULL) free(Part_Deinterleaver); Part_Deinterleaver = deinterleaver(xin1, 13, xin2, 13); for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i] = Part_Deinterleaver[i]; free(Part_Deinterleaver); Part_Deinterleaver = deinterleaver(xin1, 21, xin2, 21); for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i + (xin1 + xin2)] = Part_Deinterleaver[i]; for (i = 0; i < 2; i++) { PL[i] = ratesA[i]; PL[i + 2] = ratesB[i]; } } else if (msc_mode == 3) /* 4-QAM */ { // rylcm = (int) RY[multiplex_description.PL_PartA]; ratesA[0] = (int) RX[multiplex_description.PL_PartA] - 1; N1 = 0; N2 = N_MUX - N1; ratesB[0] = (int) RX[multiplex_description.PL_PartB] - 1; if (robustness_mode == 0) { if (spectrum_occupancy == 0) { L[0] = 0; L[1] = 768; } else { L[0] = 0; L[1] = 837; } } if (robustness_mode == 1) { if (spectrum_occupancy == 0) { L[0] = 0; L[1] = 537; } else { L[0] = 0; L[1] = 627; } } if (robustness_mode == 2) { if (spectrum_occupancy == 0) { L[0] = 0; L[1] = 399; } else { L[0] = 0; L[1] = 435; } } Lvspp = 0; xin1 = 2 * N1; xin2 = 2 * N2; if (Part_Deinterleaver != NULL) free(Part_Deinterleaver); Part_Deinterleaver = deinterleaver(xin1, 21, xin2, 21); for (i = 0; i < xin1 + xin2; i++) Deinterleaver[i] = Part_Deinterleaver[i]; PL[0] = 0; PL[1] = 6; rowdimL = 1; coldimL = 2; } } if (msc_parameters_valid != 0) { for (i = 0; i < lMSC; i++) { trxfrmbufptr = MSC_Demapper[frame_index - 1][i]; received_real[i] = (double) transmission_frame_buffer[2 * trxfrmbufptr]; received_imag[i] = (double) transmission_frame_buffer[2 * trxfrmbufptr + 1]; MSC_cells_sequence[2 * i] = (float) received_real[i]; MSC_cells_sequence[2 * i + 1] = (float) received_imag[i]; transfer_function_MSC[i * 2] = channel_transfer_function_buffer[2 * trxfrmbufptr]; transfer_function_MSC[i * 2 + 1] = channel_transfer_function_buffer[2 * trxfrmbufptr + 1]; } if (enough_frames == 0) { for (i = 0; i < lMSC; i++) { if ((MSC_Demapper[frame_index - 1][i] > max_index_equal_samples) || (MSC_Demapper[frame_index - 1][i] < min_index_equal_samples)) { transfer_function_MSC[2 * i] = 0.0; transfer_function_MSC[2 * i + 1] = 0.0; } SNR_estimation[i] = sqrt(transfer_function_MSC[2 * i] * transfer_function_MSC[i * 2] + transfer_function_MSC[i * 2 + 1] * transfer_function_MSC[i * 2 + 1]); } n_SPPhard = msdhardmsc(received_real, received_imag, lMSC, SNR_estimation, N1, L, rowdimL, coldimL, Lvspp, Deinterleaver, PL, MSD_ITER, 1, SPPhard, VSPPhard, &res_iters, &calc_variance, noise_signal); channel_decoded_data_buffer_data_valid = 2; length_decoded_data = n_SPPhard; } else { MSCAvailable=true; SNR_estimation_valid = 0; if (SNR_estimation_valid < 1) { for (i = 0; i < lMSC; i++) { SNR_estimation[i] = sqrt(transfer_function_MSC[2 * i] * transfer_function_MSC[i * 2] + transfer_function_MSC[i * 2 + 1] * transfer_function_MSC[i * 2 + 1]); } } else { for (i = 0; i < 461; i++) { if (fabs(noise_power_density[i] - 0.0) < DBL_EPSILON) noise_power_density[i] = 1.0; } for (i = 0; i < lMSC; i++) { if (noise_power_density [MSC_Demapper_symbolwise[frame_index - 1][i]] <= 0.0) { exit(EXIT_FAILURE); } part1 = sqrt(transfer_function_MSC[i * 2] * transfer_function_MSC[i * 2] + transfer_function_MSC[i * 2 + 1] * transfer_function_MSC[i * 2 + 1]); part2 = sqrt(noise_power_density [MSC_Demapper_symbolwise[frame_index - 1][i]]); SNR_estimation[i] = part1 / part2; } } n_SPPhard = msdhardmsc(received_real, received_imag, lMSC, SNR_estimation, N1, L, rowdimL, coldimL, Lvspp, Deinterleaver, PL, MSD_ITER, 1, SPPhard, VSPPhard, &res_iters, &calc_variance, noise_signal); length_decoded_data = n_SPPhard; sum1 = 0.0; sum2 = 0.0; for (i = 0; i < lMSC; i++) { squared_noise_signal[i] = noise_signal[2 * i] * noise_signal[2 * i] + noise_signal[2 * i + 1] * noise_signal[2 * i + 1]; sum1 += (transfer_function_MSC[2 * i] * transfer_function_MSC[2 * i] + transfer_function_MSC[2 * i + 1] * transfer_function_MSC[2 * i + 1]) * squared_noise_signal[i]; sum2 += (transfer_function_MSC[2 * i] * transfer_function_MSC[2 * i] + transfer_function_MSC[2 * i + 1] * transfer_function_MSC[2 * i + 1]) * mean_energy_of_used_cells; } // calc_weighted_variance = sum1 / sum2; for (i = 0; i < lMSC; i++) { squared_noise_signal_buffer[MSC_Demapper[frame_index - 1][i]] = squared_noise_signal[i]; } /* now calc the sum of the reshaped "symbol_period" number of columns */ for (i = 0; i < symbol_period; i++) { weighted_noise_power_density[i] = 0.0; for (j = 0; j < 6 * symbols_per_frame; j++) { weighted_noise_power_density[i] += squared_noise_signal_buffer[i + j * symbol_period]; } } // cnt_npwrpos = 0; // for (i = 0; i < symbol_period; i++) // { // if (fabs(weighted_noise_power_density[i]) > DBL_EPSILON) // { // noise_power_positions[cnt_npwrpos++] = i; // } // } // for (i = 0; i < symbol_period; i++) // { // signal_to_noise_ratio[i] = 0.0; // } // for (i = 0; i < cnt_npwrpos; i++) // { // signal_to_noise_ratio[noise_power_positions[i]] = MSC_carrier_usage[noise_power_positions[i]] /weighted_noise_power_density[noise_power_positions[i]]; // } for (i = 0; i < symbol_period; i++) /* rows */ for (j = 0; j < symbols_per_frame; j++) /* columns */ samples_resorted[i][j] = 0.0; for (i = 0; i < lMSC; i++) { totindex = (MSC_Demapper[frame_index - 1][i]) % (symbol_period * symbols_per_frame); posrow = totindex % symbol_period; poscolumn = totindex / symbol_period; samples_resorted[posrow][poscolumn] = squared_noise_signal[i] * (transfer_function_MSC[i * 2] * transfer_function_MSC[i * 2] + transfer_function_MSC[i * 2 + 1] * transfer_function_MSC[i * 2 + 1]); } for (i = 0; i < cnt_MSC_used_carriers; i++) { sum1 = 0.0; for (j = 0; j < symbols_per_frame; j++) sum1 += samples_resorted[MSC_used_carriers[i]][j]; noise_power_density[MSC_used_carriers[i]] = noise_power_density[MSC_used_carriers[i]] * (1.0 - 0.2) + 0.2 * sum1 / MSC_carrier_usage[MSC_used_carriers[i]]; } if (SNR_estimation_valid < 1) { SNR_estimation_valid++; } channel_decoded_data_buffer_data_valid = 1; } if (Lvspp != 0) { VSPPlength = multiplex_description.stream_lengths[0][0] * 8 + multiplex_description.stream_lengths[1][0] * 8; HPPlength = 0; for (i = 0; i < no_of_streams; i++) { HPPlength += 8 * multiplex_description.stream_lengths[0][i]; } n = 0; for (i = 0; i < HPPlength; i++) channel_decoded_data_buffer[n++] = SPPhard[i]; for (i = 0; i < VSPPlength; i++) channel_decoded_data_buffer[n++] = VSPPhard[i]; for (i = 0; i < n_SPPhard - HPPlength; i++) channel_decoded_data_buffer[n++] = SPPhard[HPPlength + i]; } else { for (i = 0; i < n_SPPhard; i++) { channel_decoded_data_buffer[i] = SPPhard[i]; } } } frame_index = (frame_index % 6) + 1; transmission_frame_buffer_wptr =((transmission_frame_buffer_wptr +symbol_period * symbols_per_frame) % (symbol_period *symbols_per_frame * 6)); return; } char getfacchar(double *facdata) { char karakter; int macht, i; macht=64; karakter =0; for (i=0; i < 7 ; i++) { if (facdata[i] == 1.0) { karakter += macht; } macht /= 2; } return(karakter); } qsstv_8.2.12/qsstv/drmrx/crc16_bytewise.cpp000664 001750 001750 00000010650 12440612574 020646 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Andreas Dittrich, Torsten Schorr */ /* */ /* Author(s) : Andreas Dittrich (dittrich@eit.uni-kl.de), */ /* Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 27.07.2004 */ /* Last change : 27.07.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* crc16_bytewise.c */ /* */ /******************************************************************************/ /* Description: */ /* CRC-16 checksum calculation of a byte stream */ /* Usage: */ /* */ /* crc16_bytewise(double *checksum, unsigned char *in, long N); */ /* */ /* calculates double checksum of uint8 bytes */ /* */ /******************************************************************************/ /************* * * adjusted for use in own plain C programa * by M.Bos - PA0MBO * * Date Dec 9th 2007 */ #include #include /******************************************************************************/ /* function */ /******************************************************************************/ void crc16_bytewise(double /*@out@ */ checksum[],unsigned char in[], long N) { long int i; int j; unsigned int b = 0xFFFF; unsigned int x = 0x1021; /* (1) 0001000000100001 */ unsigned int y; for (i = 0; i < N - 2; i++) { for (j = 7; j >= 0; j--) { y = (((b >> 15) + (unsigned int) (in[i] >> j)) & 0x01) & 0x01; /* extra parenth pa0mbo */ if (y == 1) b = ((b << 1) ^ x); else b = (b << 1); } } for (i = N - 2; i < N; i++) { for (j = 7; j >= 0; j--) { y = (((b >> 15) + (unsigned int) ((in[i] >> j) & 0x01)) ^ 0x01) & 0x01; /* extra parent pa0mbo */ if (y == 1) b = ((b << 1) ^ x); else b = (b << 1); } } *checksum = (double) (b & 0xFFFF); } qsstv_8.2.12/qsstv/drmrx/crc8_c.cpp000664 001750 001750 00000000763 12440612574 017162 0ustar00jomajoma000000 000000 /* * File crc8_c.c * * from diorama-1.1.1 by A. Dittrich & T. Schorr * * */ #include #include #include void crc8_c( /*@out@ */ double checksum[], double in[], int N) { int i; unsigned int b = 0xFF; unsigned int x = 0x1D; /* (1) 00011101 */ unsigned int y; for (i = 0; i < N; i++) { y = ((b >> 7) + (int) floor(in[i] + 0.5)) & 0x01; if (y == 1) b = ((b << 1) ^ x); else b = (b << 1); } *checksum = (double) (b & 0xFF); } qsstv_8.2.12/qsstv/drmrx/deflate_uncompress.cpp000664 001750 001750 00000022352 12440612574 021701 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 15.07.2004 */ /* Last change : 03.08.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* deflate_uncompress.c */ /* */ /******************************************************************************/ /* Description: */ /* Decompressor for data in gzip file format (RFC 1952) */ /* compressed with the DEFLATE compressed data format */ /* (RFC 1951). Used for Broadcast Web-Site application */ /* ETSI TS 101 498 */ /* */ /* Usage: */ /* */ /* [data, origname, zerror] = deflate_uncompress(input); */ /* */ /* uncompresses uint8 input bytes into uint8 data with original filename */ /* origname. zerror: error during decompression */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* This program is based on the 'zlib' general purpose compression library */ /* version 1.1.3, July 9th, 1998 Jean-loup Gailly and Mark Adler */ /* */ /* */ /* The data format used by the zlib library is described by RFCs (Request for*/ /* Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt */ /* (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).*/ /* */ /******************************************************************************/ /* code adjusted for use outside MATLAB * * by M.Bos - PA0MBO * * date Jan 18th 2008 */ #include #include #include #include #define Nargs_rhs_str "1" #define Nargs_rhs 1 #define PROGNAME "deflate_uncompress" static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ int deflate_uncompress(unsigned char *input, int l_in, char /*@out@ */ *origname, int , unsigned char /*@out@ */ *data, int *, double /*@out@ */ *lhs2) { unsigned char *compressed_data, *uncompressed_data; int N, zerror; // int dims[2]; int expected_size, len, method, flags, startpos, i; uLong crc; z_stream stream, *streamp = &stream; /* in */ N = l_in; compressed_data = input; if (N < 10) { printf("not enough input data\n"); exit(EXIT_FAILURE); } streamp->zalloc = (alloc_func) NULL; streamp->zfree = (free_func) NULL; streamp->opaque = (voidpf) 0; streamp->next_out = Z_NULL; streamp->avail_in = 0; streamp->next_in = compressed_data; zerror = inflateInit2(streamp, -MAX_WBITS); /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are * present after the compressed stream. */ if (zerror != Z_OK) { inflateEnd(streamp); printf("Error using inflateInit2\n"); exit(1); } /* Check the gzip magic header */ for (len = 0; len < 2; len++) { if (compressed_data[len] != gz_magic[len]) { printf("No gzip format\n"); exit(1); } } method = compressed_data[2]; flags = compressed_data[3]; if (method != Z_DEFLATED || (flags & RESERVED) != 0) { inflateEnd(streamp); printf("No deflate format or reserved flags!\n"); exit(1); } /* Discard time, xflags and OS code: */ startpos = 10; if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ len = compressed_data[startpos] + (compressed_data[startpos + 1] << 8); startpos += len + 2; } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ i = 0; { origname[i] = compressed_data[startpos]; } while ((compressed_data[startpos++] != 0) && (startpos < N)); } else { origname[0] = '\0'; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ while ((compressed_data[startpos++] != 0) && (startpos < N)); } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ startpos += 2; } if (startpos > N - 8) { inflateEnd(streamp); printf("not enough input data\n"); exit(1); } expected_size = ((int) compressed_data[N - 1] << 24) + ((int) compressed_data[N - 2] << 16) + ((int) compressed_data[N - 3] << 8) + ((int) compressed_data[N - 4]); if (expected_size > (0x01 << 30)) { inflateEnd(streamp); printf ("error in expected file size or file too large (support for 1GB files)\n"); exit(1); } uncompressed_data = (unsigned char *) malloc(expected_size * sizeof(unsigned char)); if (uncompressed_data == NULL) { inflateEnd(streamp); printf("error allocating memory\n"); exit(1); } /* prepare z_stream data structure */ streamp->avail_in = N - startpos; streamp->next_in = compressed_data + startpos; streamp->avail_out = expected_size; streamp->next_out = uncompressed_data; /* uncompress data */ zerror = inflate(streamp, Z_FINISH); *lhs2 = 0.0; if (zerror == Z_STREAM_END) { /* check crc over uncompressed data: */ crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, uncompressed_data, (uInt) (streamp->next_out - uncompressed_data)); if ((((int) compressed_data[N - 5] << 24) + ((int) compressed_data[N - 6] << 16) + ((int) compressed_data[N - 7] << 8) + ((uLong) compressed_data[N - 8]) != crc) | (expected_size != streamp->next_out - uncompressed_data)) { *lhs2 = -1.0; } // dims[0] = 1; // dims[1] = streamp->next_out - uncompressed_data; memcpy(data, uncompressed_data, (streamp->next_out - uncompressed_data) * sizeof(unsigned char)); } else { *data = (double) zerror; } inflateEnd(streamp); free(uncompressed_data); return zerror; } qsstv_8.2.12/qsstv/drmrx/deinterleaver.cpp000664 001750 001750 00000004725 12440612574 020654 0ustar00jomajoma000000 000000 /* * File deinterleaver.c * * follows deinterleaver.m by * Torsten Schorr * * Author M.Bos - PA0MBO * Date Feb 21st 2009 * * * N.B. separate routines for different return arguments */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include int *deinterleaver(int xinA, int tA, int xinB, int tB) { int *deinterl; int i; int sA, sB, qA, qB; int PIofi; double part1, part2; double part3; deinterl = (int *) malloc((xinA + xinB) * sizeof(int)); if (deinterl == NULL) { printf("Cannot malloc space for deinterl in routine deinterleaver\n"); exit(EXIT_FAILURE); } if (xinA < 0) { printf("deinterleaver: xinA must be > = 0!\n"); free(deinterl); exit(EXIT_FAILURE); } if (tA < 1) { printf("deinterleaver: tA must be a natural number!\n"); free(deinterl); exit(EXIT_FAILURE); } if (xinB < 6) { printf("deinterleaver: xinB must be >= 6!\n"); free(deinterl); exit(EXIT_FAILURE); } if (tB < 1) { printf("deinterleaver: tB must be a natural number\n"); free(deinterl); exit(EXIT_FAILURE); } if (xinA == 0) sA = 0; else { part1 = log((double) xinA); part2 = log(2.0); part3 = ceil(part1 / part2); sA = (int) pow(2, part3); } qA = sA / 4 - 1; if (xinB == 0) sB = 0; else { part1 = log((double) xinB); part2 = log(2.0); part3 = ceil(part1 / part2); sB = (int) pow(2, part3); } qB = sB / 4 - 1; deinterl[0] = 0; PIofi = 0; for (i = 1; i <= xinA - 1; i++) { PIofi = (tA * PIofi + qA) % sA; while (PIofi >= xinA) { PIofi = (tA * PIofi + qA) % sA; } deinterl[PIofi] = i; } deinterl[xinA] = xinA; PIofi = 0; for (i = 1; i <= xinB - 1; i++) { PIofi = (tB * PIofi + qB) % sB; while (PIofi >= xinB) { PIofi = (tB * PIofi + qB) % sB; } deinterl[PIofi + xinA] = i + xinA; } return (deinterl); } qsstv_8.2.12/qsstv/drmrx/demodulator.cpp000664 001750 001750 00000122367 12440612574 020345 0ustar00jomajoma000000 000000 #include "demodulator.h" #include "qsstvglobal.h" #include "drm.h" #include #include #include "nrutil.h" #include "utils/supportfunctions.h" demodulator *demodulatorPtr; void ludcmp(float **, int, int *, float *); void lubksb(float **, int, int *, float *); int Ts_list[DRMNUMMODES] = { Ts_A, Ts_B, Ts_C, Ts_D }; int Tu_list[DRMNUMMODES] = { Tu_A, Tu_B, Tu_C, Tu_D }; int Tg_list[DRMNUMMODES] = { Tg_A, Tg_B, Tg_C, Tg_D }; float FAC_cells_sequence[200]; bool FACAvailable; float deltaFS; float freqOffset; float tempbuf[30000]; demodulator::demodulator() { srcDecoder.init(); } demodulator::~demodulator() { fftwf_destroy_plan(p1); } void demodulator::init() { int i,j,k; FACAvailable=false; N_symbols_mode_detection = 20; N_symbols_frequency_pilot_search = 15; time_offset_log_last = 0; symbol_counter = 0; N_samples_needed = N_symbols_mode_detection * 320; input_samples_buffer_request = N_samples_needed; SNR_time_out_counter = SNR_TIMEOUT; fac_not_valid_counter = FACVALIDCNTR; mode_and_occupancy_code_last = -1; timeSyncFlag = false; frequencySyncFlag = false; frameSyncFlag = false; doSynchronize=false; rsbufwidx = 0; symbufwidx = 0; iterationCounter=0; samplerate_offset_estimation = 0; samplerate_offset=0; smp_rate_conv_fft_phase_diff = 0; smp_rate_conv_fft_phase_offset = 0; smp_rate_conv_in_out_delay = 0; transmission_frame_buffer_data_valid = 0; p1 = fftwf_plan_dft_1d(256,(fftwf_complex *)ss,(fftwf_complex *)S, FFTW_FORWARD, FFTW_PATIENT); counter=0; k = 0; for (i = 0; i < 4; i++) // number of robustness modes { for (j = 0; j < 6; j++) /* number of spectrumoccupancies */ { no_of_used_cells_per_frame_list[k++] = (K_min_K_max_list[1][j + i * 6] - K_min_K_max_list[0][j + i * 6] + 1 - no_of_unused_carriers_list[i]) * symbols_per_frame_list[i]; } } sigmaq_noise_list[0] = (float) pow(10.0, -16.0 / 10.0); sigmaq_noise_list[1] = (float) pow(10.0, -14.0 / 10.0); sigmaq_noise_list[2] = (float) pow(10.0, -14.0 / 10.0); sigmaq_noise_list[3] = (float) pow(10.0, -12.0 / 10.0); SNR_timeout_counter=0; delta_freq_offset=0; } bool demodulator::demodulate(float *sigin,int numSamples) { int i; numberOfSamples=numSamples; transmission_frame_buffer_data_valid = 0; // fac_valid can be -1,0,1 addToLog(QString("block %1 samples %2" ).arg(iterationCounter).arg(numSamples),LOGDRMDEMOD); // if(iterationCounter<40) arrayDump(QString("DEM %1").arg(iterationCounter),sigin,128,true); // arrayDump(QString("bl%1").arg(iterationCounter),sigin,32,true); // logfile->addToAux(QString("block %1").arg(iterationCounter)); // arrayDump(QString("rs"),sigin,numSamples*2,true); // if (fac_valid == 0) // { // fac_not_valid_counter--; // if (fac_not_valid_counter <= 0) // { // doSynchronize = true; // fac_not_valid_counter = FACVALIDCNTR; // } // } // else // { // if (fac_valid == 1) // { // fac_not_valid_counter = FACVALIDCNTR; // } // } if (doSynchronize) { doSynchronize = false; init(); } if (numberOfSamples> 0) { ++iterationCounter; // logfile->addToAux(QString("iterationCounter %1").arg(iterationCounter)); // arrayDump("sig1",sigin,RXSTRIPE,true); // logfile->addToAux(QString("rsbufwidx %1 offset %2").arg(rsbufwidx).arg(320 * N_symbols_mode_detection/2)); // arrayDump("sigD",&rs_buffer[320 * N_symbols_mode_detection],16,true); for(i=0;i20) { for(i=0;i<(256*block);i++)tempbuf[i]=rs_buffer[2*i]; psdmean(tempbuf, psd, 256, block); /* globals pa0mbo */ for(i=0;i<(256*block);i++)tempbuf[i]=rs_buffer[2*i+1]; psdmean(tempbuf, cpsd, 256, block); /* globals pa0mbo */ } } if(!timeSync()) return false; if(!frequencySync()) return false; if(!frameSync()) return false; if(channelEstimation()) { channel_decoding(); srcDecoder.decode(); } if(doSynchronize) { // see if we have to save the data (for BSR and endOfImage) // srcDecoder.checkSaveImage(); } return true; } bool demodulator::timeSync() { int i; samplerate_offset= samplerate_offset_estimation; if (!timeSyncFlag) { frequencySyncFlag=false; // enough data for time sync ? N_samples_needed = N_symbols_mode_detection * 320 - rsbufwidx; if (N_samples_needed > 0) { input_samples_buffer_request = N_samples_needed; return false; } spectrum_occupancy = -1; /* -1 denotes unknown */ getmode(rs_buffer, N_symbols_mode_detection * 320, &mode_block); robustness_mode = mode_block.mode_indx; time_offset = mode_block.time_offset; samplerate_offset_estimation = mode_block.sample_rate_offset; frequency_offset_fractional_init = mode_block.freq_offset_fract; time_offset_integer = (int) floor(time_offset + 0.5); if(robustness_mode!=99) { addToLog(QString("numSamples %1, robustmode %2,timeoffset %3,smplrateOffsetEst %4,freqOffsetFracInit %5,timeOffsetInteger %6") .arg(numberOfSamples).arg( robustness_mode).arg(time_offset).arg(samplerate_offset_estimation).arg(frequency_offset_fractional_init).arg(time_offset_integer),LOGDRMDEMOD); } if ((fabsf(samplerate_offset_estimation) > 200.0E-5) && (robustness_mode != 99)) { // sample_rate offset too large N_samples_needed = N_symbols_mode_detection * 320; input_samples_buffer_request = N_samples_needed; rsbufwidx = 0; // samplerate_offset_estimation=0; return false; } if (robustness_mode != 99) { // logfile->addToAux("timesync found"); addToLog(QString("found robustness_mode: %1").arg(robustness_mode),LOGDRMDEMOD); timeSyncFlag = true; Ts = Ts_list[robustness_mode]; Tu = Tu_list[robustness_mode]; Tg = Tg_list[robustness_mode]; Tgh = (int) floor(Tg / 2 + 0.5); symbols_per_frame = symbols_per_frame_list[robustness_mode]; K_dc = Tu / 2; K_modulo = Tu; for (i = 0; i < 21; i++) time_ref_cells_k[i] = time_ref_cells_k_list[robustness_mode][i]; for (i = 0; i < 21; i++) time_ref_cells_theta_1024[i] = time_ref_cells_theta_1024_list[robustness_mode][i]; y = y_list[robustness_mode]; symbols_per_2D_window = symbols_per_2D_window_list[robustness_mode]; symbols_to_delay = symbols_to_delay_list[robustness_mode]; // symbol align rs_buffer rsbufwidx = rsbufwidx - time_offset_integer; for (i = 0; i < rsbufwidx; i++) { rs_buffer[i * 2] = rs_buffer[(i + time_offset_integer) * 2]; rs_buffer[i * 2 + 1] =rs_buffer[(i + time_offset_integer) * 2 + 1]; } counter++; (void) getofdm(NULL, 0.0, 0.0, 0.0, Ts, Tu, NULL, NULL, 1, 1, 1); /* initialisation */ } else { samplerate_offset_estimation = 0.0; int shift=320 * N_symbols_mode_detection; // int shift=512; memmove(rs_buffer,&rs_buffer[shift*2],sizeof(float)*2*(rsbufwidx-shift)); rsbufwidx -= shift; // arrayDump("sig2",rs_buffer,16,true); // for (i = 0; i < rsbufwidx; i++) /* pa0mbo was rsbufwidx-1 ? */ // { // rs_buffer[i * 2] = rs_buffer[(shift + i) * 2]; // rs_buffer[i * 2 + 1] = rs_buffer[(shift + i) * 2 + 1]; // } N_samples_needed = N_symbols_mode_detection * 320 - rsbufwidx; if (N_samples_needed > 0) { input_samples_buffer_request = N_samples_needed; } else { input_samples_buffer_request = 0; } return false; } addToLog(QString("timeSync found robustness mode:%1").arg(robustness_mode),LOGDRMDEMOD); } return true; } bool demodulator::frequencySync() { int i,j; int sp_idx, K_min_, K_max_, K_dc_indx, K_dc_plus2_indx; int K_min_indx, K_min_minus4_indx, K_max_indx, K_max_plus1_indx; float tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; // float energy_ratio_K2_to_K0; float energy_ratio_K_max_to_K_max_p1; float energy_ratio_K_min_to_K_min_m4; float spectrum_occupancy_indicator[6]; int t_smp; struct drmComplex S_buffer[288][20]; /* pa0mbo check */ if (!frequencySyncFlag) { frameSyncFlag=false; // enough f=date for pilot search? N_samples_needed = (N_symbols_frequency_pilot_search + 1) * Ts - (rsbufwidx); if (N_samples_needed > 0) { input_samples_buffer_request = N_samples_needed; return false; } Zi[0] = -1.0; delta_time_offset_integer = 0; freq_offset_init = frequency_offset_fractional_init; time_offset_fractional_init = time_offset - time_offset_integer; delta_time_offset_I_init = samplerate_offset_estimation * Ts; t_smp = 0; for (i = 0; i < N_symbols_frequency_pilot_search; i++) { delta_time_offset_integer = getofdm(&rs_buffer[2 * t_smp], time_offset_fractional_init,freq_offset_init, delta_time_offset_I_init, Ts, Tu, Zi, symbol_temp, 0, 1,1); for (j = 0; j < K_modulo; j++) { symbol_buffer[(i * K_modulo + j) * 2] = symbol_temp[j * 2]; symbol_buffer[(i * K_modulo + j) * 2 + 1] = symbol_temp[j * 2 + 1]; } t_smp = t_smp + Ts + delta_time_offset_integer; } freq_offset_integer = getfoffsint(symbol_buffer, N_symbols_frequency_pilot_search, K_dc,K_modulo, Tu); // prepare for new round delta_time_offset_integer = 0; freq_offset_init = -freq_offset_integer + frequency_offset_fractional_init; time_offset_fractional_init = 0.0; Zi[0] = -1.0; // detmn frequency occupancy // start with reshaping symbol_buffer to S_buffer for (i = 0; i < N_symbols_frequency_pilot_search; i++) { for (j = 0; j < K_modulo; j++) { (S_buffer[j][i]).re = symbol_buffer[(j + i * K_modulo) * 2]; (S_buffer[j][i]).im = symbol_buffer[(j + i * K_modulo) * 2 + 1]; } } /* now per freq occupancy mode */ for (sp_idx = 0; sp_idx < 2; sp_idx++) { K_min_ = K_min_K_max_list[0][sp_idx + robustness_mode * 6]; K_max_ = K_min_K_max_list[1][sp_idx + robustness_mode * 6]; if (K_min_ != K_max_) { K_dc_indx = (int) floor(freq_offset_integer / (2.0 * M_PI) + 0.5) + Tu / 2; K_dc_indx = K_dc_indx % Tu; K_dc_plus2_indx = (K_dc_indx + 2 + Tu) % Tu; K_min_indx = (K_dc_indx + K_min_ + Tu) % Tu; K_min_minus4_indx = (K_min_indx - 4 + Tu) % Tu; K_max_indx = (K_dc_indx + K_max_ + Tu) % Tu; K_max_plus1_indx = (K_max_indx + 1 + Tu) % Tu; // calc energy ratios tmp1 = 0.0; tmp2 = 0.0; tmp3 = 0.0; tmp4 = 0.0; tmp5 = 0.0; tmp6 = 0.0; for (i = 0; i < N_symbols_frequency_pilot_search; i++) { tmp1 += (S_buffer[K_dc_plus2_indx][i]).re * (S_buffer[K_dc_plus2_indx][i]).re + (S_buffer[K_dc_plus2_indx][i]).im * (S_buffer[K_dc_plus2_indx][i]).im; tmp2 += (S_buffer[K_dc_indx][i]).re * (S_buffer[K_dc_indx][i]).re + (S_buffer[K_dc_indx][i]).im * (S_buffer[K_dc_indx][i]).im; tmp3 += (S_buffer[K_max_indx][i]).re * (S_buffer[K_max_indx][i]).re + (S_buffer[K_max_indx][i]).im * (S_buffer[K_max_indx][i]).im; tmp4 += (S_buffer[K_max_plus1_indx][i]).re * (S_buffer[K_max_plus1_indx][i]).re + (S_buffer[K_max_plus1_indx][i]).im * (S_buffer[K_max_plus1_indx][i]).im; tmp5 += (S_buffer[K_min_indx][i]).re * (S_buffer[K_min_indx][i]).re + (S_buffer[K_min_indx][i]).im * (S_buffer[K_min_indx][i]).im; tmp6 += (S_buffer[K_min_minus4_indx][i]).re * (S_buffer[K_min_minus4_indx][i]).re + (S_buffer[K_min_minus4_indx][i]).im * (S_buffer[K_min_minus4_indx][i]).im; } // energy_ratio_K2_to_K0 = tmp1 / tmp2; energy_ratio_K_max_to_K_max_p1 = tmp3 / tmp4; energy_ratio_K_min_to_K_min_m4 = tmp5 / tmp6; spectrum_occupancy_indicator[sp_idx] = energy_ratio_K_min_to_K_min_m4 + energy_ratio_K_max_to_K_max_p1; } else spectrum_occupancy_indicator[sp_idx] = 0.0; } // detmn max in spectrum_occupancy_indicator and its index tmp1 = 0.0; for (sp_idx = 0; sp_idx < 2; sp_idx++) { if (spectrum_occupancy_indicator[sp_idx] > tmp1) { tmp1 = spectrum_occupancy_indicator[sp_idx]; spectrum_occupancy_estimation = sp_idx; } } frequencySyncFlag = true; addToLog(QString("spectrum occupancy estimation:%1").arg(spectrum_occupancy_estimation),LOGDRMDEMOD); } return true; } bool demodulator::frameSync() { int i,j,k; int symbol0; int symbol_no_to_equalize; int t_smp; if (!frameSyncFlag) { initChannelEstimation=true; // enough data ? N_symbols_needed = symbols_per_frame + symbols_per_2D_window - 1; N_samples_needed = (N_symbols_needed + 1) * Ts - (rsbufwidx); if (N_samples_needed > 0) { input_samples_buffer_request = N_samples_needed; return false; } t_smp = 0; for (i = 0; i < symbols_per_frame; i++) { delta_time_offset_integer = getofdm(&rs_buffer[2 * t_smp], time_offset_fractional_init,freq_offset_init, delta_time_offset_I_init, Ts, Tu, Zi,symbol_temp, 0, 1,1); for (j = 0; j < K_modulo; j++) { symbol_buffer[(i * K_modulo + j) * 2] = symbol_temp[j * 2]; symbol_buffer[(i * K_modulo + j) * 2 + 1] = symbol_temp[j * 2 + 1]; } t_smp = t_smp + Ts + delta_time_offset_integer; } // search first symbol of frame using time ref cells symbol0 = getsymbolidx(symbol_buffer, symbols_per_frame, time_ref_cells_k,time_ref_cells_theta_1024, K_dc, K_modulo, 21); symbol_no_to_equalize =((symbol0 - symbols_to_delay + symbols_per_frame) % symbols_per_frame) + 1; frameSyncFlag = true; symbol_counter = 0; // frame align rs_buffer if (symbol_no_to_equalize != 1) { rsbufwidx -= (symbol_no_to_equalize - 1) * Ts; for (j = 0; j < rsbufwidx; j++) /* pa0mbo was rsbufwidx 22-4-07 now better */ { rs_buffer[j * 2] = rs_buffer[((symbol_no_to_equalize - 1) * Ts + j) * 2]; rs_buffer[j * 2 + 1] = rs_buffer[((symbol_no_to_equalize - 1) * Ts + j) * 2 + 1]; } } symbufwidx = 0; Zi[0] = -1.0; t_smp = 0; for(i=0;i<(Tu_A * 2 * 26);i++) { symbol_buffer[i]=0; } for (i = 0; i 0) { input_samples_buffer_request = N_samples_needed; return false; } // now set the parameter spectrum_occupancy if (spectrum_occupancy <= 0) { if (spectrum_occupancy_estimation < 0) spectrum_occupancy = 3; else spectrum_occupancy = spectrum_occupancy_estimation; } if (spectrum_occupancy > 3) spectrum_occupancy = 3; // 4 and 5 not yet supported mode_and_occupancy_code = mode_and_occupancy_code_table[robustness_mode * 6 + spectrum_occupancy]; if (mode_and_occupancy_code < 0) { spectrum_occupancy = 1; mode_and_occupancy_code = mode_and_occupancy_code_table[robustness_mode * 6 + spectrum_occupancy]; } if (mode_and_occupancy_code != mode_and_occupancy_code_last) { K_min = K_min_K_max_list[0][spectrum_occupancy + robustness_mode * 6]; K_max = K_min_K_max_list[1][spectrum_occupancy + robustness_mode * 6]; carrier_per_symbol = K_max - K_min + 1; (void) getofdmsync(NULL, Ts, Tu, NULL, K_max - K_min + 1, 0, NULL, NULL, 1, 1, 1); /* initialisation */ // reformat pilot index stuff into th K_dc/K_modulo block // first call listsinit to get gain_ref_cells_k etc // Jan 5th 2009 changed listsinit() call to an include of all code from listsinit.c Tu = Tu_list[robustness_mode]; Ts = Ts_list[robustness_mode]; Tg = Ts - Tu; sigmaq_noise = sigmaq_noise_list[robustness_mode]; symbols_per_frame = symbols_per_frame_list[robustness_mode]; for (i = 0; i < 3; i++) { freq_ref_cells_k[i] = freq_ref_cells_k_list[robustness_mode][i]; freq_ref_cells_theta_1024[i] = freq_ref_cells_theta_1024_list[robustness_mode][i]; } cnt_time_ref_cells = time_ref_cells_cnt_list[robustness_mode]; for (i = 0; i < cnt_time_ref_cells; i++) { time_ref_cells_k[i] = time_ref_cells_k_list[robustness_mode][i]; time_ref_cells_theta_1024[i] = time_ref_cells_theta_1024_list[robustness_mode][i]; } K_min = K_min_K_max_list[0][spectrum_occupancy_estimation + robustness_mode * 6]; K_max = K_min_K_max_list[1][spectrum_occupancy_estimation + robustness_mode * 6]; carrier_per_symbol = K_max - K_min + 1; for (i = 0; i < 4; i++) { power_boost[i] = power_boost_list[robustness_mode][spectrum_occupancy_estimation][i]; } x = x_list[robustness_mode]; y = y_list[robustness_mode]; k0 = k0_list[robustness_mode]; Q_1024 = Q_1024_list[robustness_mode]; mean_energy_of_used_cells =(float) (no_of_used_cells_per_frame_list[spectrum_occupancy_estimation + robustness_mode * 6] + 3 + cnt_time_ref_cells); rndcnt = 0; for (s = 0; s < symbols_per_frame; s++) { nnn = s % y; m = (int) floor((double) (s / y)); p_min = (int) ceil((double) ((K_min - k0 - x * nnn) / (x * y))); p_max = (int) floor((double) ((K_max - k0 - x * nnn) / (x * y))); for (p = p_min; p <= p_max; p++) { k = k0 + x * nnn + x * y * p; theta_1024 = (4*Z_256_list[robustness_mode][nnn][m]+p*W_1024_list[robustness_mode][nnn][m]+p*p*(1 +s)*Q_1024) % 1024; a = sqrtf(2.0); // power boost for (i = 0; i < 4; i++) { if (k == power_boost[i]) a = 2; } // is time ref cell ? if (s == 0) { for (i = 0; i < cnt_time_ref_cells; i++) { if (k == time_ref_cells_k[i]) { indx = i; theta_1024 = time_ref_cells_theta_1024[indx]; a = sqrtf(2.0); mean_energy_of_used_cells -= 1.0; } } } // is frequence reference cell? for (i = 0; i < 3; i++) { if (k == freq_ref_cells_k[i]) { indx = i; theta_1024 = freq_ref_cells_theta_1024[indx]; if (robustness_mode == 3) { theta_1024 = (theta_1024 + 512 * s) % 1024; } a = sqrtf(2.0); mean_energy_of_used_cells -= 1.0; } } gain_ref_cells_k[rndcnt] = k + s * carrier_per_symbol; gain_ref_cells_theta_1024[rndcnt] = theta_1024; gain_ref_cells_a[rndcnt++] = a; mean_energy_of_used_cells =(float) (mean_energy_of_used_cells - 1.0 + a * a); } } mean_energy_of_used_cells /=no_of_used_cells_per_frame_list[spectrum_occupancy_estimation + robustness_mode * 6]; addToLog(QString("mean_energy_of_used_cells %1").arg(mean_energy_of_used_cells),LOGDRMDEMOD); // precompute 2-D Wiener filter matrix // uses gain_ref_cells etc // and rndcnt symbols_per_2D_window = symbols_per_2D_window_list[robustness_mode]; symbols_to_delay = symbols_to_delay_list[robustness_mode]; f_cut_t = 0.0675 / (1.0 * (double) y); f_cut_k = 1.75 * (float) Tg / (float) Tu; for(i=0;i<5;i++) cnt_tr_cells[i]=0; // start nnn-loop for (nnn = 0; nnn < y; nnn++) { for (i = 0; i < rndcnt; i++) { training_cells_k[nnn][i] = (gain_ref_cells_k[i] - K_min +(symbols_per_frame -nnn) * carrier_per_symbol) % (symbols_per_frame * carrier_per_symbol) + K_min; } // cnt_tr_cells[nnn] = 0; for (i = 0; i < rndcnt; i++) { if ((training_cells_k[nnn][i] - K_min) <(carrier_per_symbol * symbols_per_2D_window)) { gain_ref_cells_subset_index[nnn][cnt_tr_cells[nnn]] = i; gain_ref_cells_subset[nnn][(cnt_tr_cells[nnn])++] =training_cells_k[nnn][i]; } } cnt_next_pilot_cells[nnn] = 0; for (i = 0; i < rndcnt; i++) { if (((training_cells_k[nnn][i] - K_min) >= (carrier_per_symbol * symbols_per_2D_window)) && ((training_cells_k[nnn][i] - K_min) < carrier_per_symbol * (symbols_per_2D_window + 1))) { next_pilot_cells_k_index[nnn][cnt_next_pilot_cells[nnn]] = i; next_pilot_cells_k[nnn][(cnt_next_pilot_cells[nnn])++] = ((training_cells_k[nnn][i]- K_min) % carrier_per_symbol) + K_min; } } // now sort training cells in subset if necessary sortbrkpnt = 0; for (i = 1; i < cnt_tr_cells[nnn]; i++) { if (gain_ref_cells_subset[nnn][i] < gain_ref_cells_subset[nnn][i - 1]) sortbrkpnt = i; // break in data ? } if (sortbrkpnt > 0) { // keep first part in sorttmp for (i = 0; i < sortbrkpnt; i++) { sorttmp[i] = gain_ref_cells_subset[nnn][i]; sorttmp2[i] = gain_ref_cells_subset_index[nnn][i]; /* pa0mbo added 22-jan-2009 */ } // now shift smaller ones to start of vector for (i = 0; i < cnt_tr_cells[nnn] - sortbrkpnt; i++) { gain_ref_cells_subset[nnn][i] = gain_ref_cells_subset[nnn][i + sortbrkpnt]; gain_ref_cells_subset_index[nnn][i] =gain_ref_cells_subset_index[nnn][i + sortbrkpnt]; } // replace last part from tmp for (i = cnt_tr_cells[nnn] - sortbrkpnt; i < cnt_tr_cells[nnn];i++) { gain_ref_cells_subset[nnn][i] =sorttmp[i + sortbrkpnt - cnt_tr_cells[nnn]]; gain_ref_cells_subset_index[nnn][i] =sorttmp2[i + sortbrkpnt - cnt_tr_cells[nnn]]; } sortbrkpnt = 0; } // copy to training_cells_k for (i = 0; i < cnt_tr_cells[nnn]; i++) { training_cells_k[nnn][i] = gain_ref_cells_subset[nnn][i]; } gain_ref_cells_per_window = cnt_tr_cells[nnn]; for (k_index1 = 0; k_index1 < gain_ref_cells_per_window; k_index1++) { for (k_index2 = 0; k_index2 < gain_ref_cells_per_window;k_index2++) { k1_pos = (((gain_ref_cells_subset[nnn][k_index1] -K_min)) % carrier_per_symbol) + K_min; t1_pos = (gain_ref_cells_subset[nnn][k_index1] - K_min) / carrier_per_symbol; k2_pos = ((gain_ref_cells_subset[nnn][k_index2] -K_min)) % carrier_per_symbol + K_min; t2_pos = ((gain_ref_cells_subset[nnn][k_index2] - K_min)) / carrier_per_symbol; xsinc1 = (k1_pos - k2_pos) * f_cut_k; xsinc2 = (t1_pos - t2_pos) * f_cut_t; if (k1_pos == k2_pos) xsinc1 = 1.0; else { rest = sin(M_PI * xsinc1); xsinc1 = rest / (M_PI * xsinc1); } if (fabs(xsinc2) < DBL_EPSILON) xsinc2 = 1.0; else { rest = sin(M_PI * xsinc2); xsinc2 = rest / (M_PI * xsinc2); } PHI[k_index1][k_index2] = (float) (xsinc1 * xsinc2); } } for (i = 0; i < gain_ref_cells_per_window; i++) { PHI[i][i] += sigmaq_noise * 2.0 /((gain_ref_cells_a[gain_ref_cells_subset_index[nnn][i]]) * (gain_ref_cells_a[gain_ref_cells_subset_index[nnn][i]])); } // now the matrix inversion from numerical recipes NP = gain_ref_cells_per_window; amatrix = matrix(1, NP, 1, NP); indxlu = ivector(1, NP); collu = fvector(1, NP); for (i = 1; i <= NP; i++) for (j = 1; j <= NP; j++) amatrix[i][j] = PHI[i - 1][j - 1]; ludcmp(amatrix, NP, indxlu, &dlu); /* decompose just once */ for (j = 1; j <= NP; j++) { for (i = 1; i <= NP; i++) collu[i] = 0.0; collu[j] = 1.0; lubksb(amatrix, NP, indxlu, collu); for (i = 1; i <= NP; i++) PHI_INV[i - 1][j - 1] = collu[i]; } free_fvector(collu, 1, NP); free_ivector(indxlu, 1, NP); free_matrix(amatrix, 1, NP, 1, NP); for (k_index1 = 0; k_index1 < (K_max - K_min + 1); k_index1++) { for (k_index2 = 0; k_index2 < gain_ref_cells_per_window; k_index2++) { k1_pos = k_index1 + K_min; t1_pos = symbols_to_delay; k2_pos = (training_cells_k[nnn][k_index2] - K_min) % (K_max -K_min + 1) + K_min; t2_pos = (training_cells_k[nnn][k_index2] - K_min) / (K_max -K_min + 1); xsinc1 = (k1_pos - k2_pos) * f_cut_k; xsinc2 = (t1_pos - t2_pos) * f_cut_t; if (k1_pos == k2_pos) xsinc1 = 1.0; else { rest = sin(M_PI * xsinc1); xsinc1 = rest / (M_PI * xsinc1); } if (t1_pos == t2_pos) xsinc2 = 1.0; else { rest = sin(M_PI * xsinc2); xsinc2 = rest / (M_PI * xsinc2); } THETA[k_index2] = (float) (xsinc1 * xsinc2); } // calc matrix product THETA*PHI_INV for (j = 0; j < NP; j++) { W_symbol[j] = 0.0; for (k = 0; k < NP; k++) W_symbol[j] += THETA[k] * PHI_INV[k][j]; } for (j = 0; j < NP; j++) { W_symbol_blk[nnn][j][k_index1] = W_symbol[j]; } } for (k_index1 = 0; k_index1 < cnt_next_pilot_cells[nnn]; k_index1++) { for (k_index2 = 0; k_index2 < gain_ref_cells_per_window;k_index2++) { k1_pos = next_pilot_cells_k[nnn][k_index1]; t1_pos = symbols_per_2D_window - 1; k2_pos = (training_cells_k[nnn][k_index2] - K_min) % (K_max -K_min + 1) +K_min; t2_pos = (training_cells_k[nnn][k_index2] - K_min) / (K_max -K_min + 1); xsinc1 = (k1_pos - k2_pos) * f_cut_k; xsinc2 = (t1_pos - t2_pos) * f_cut_t; if (k1_pos == k2_pos) xsinc1 = 1.0; else { rest = sin(M_PI * xsinc1); xsinc1 = rest / (M_PI * xsinc1); } if (t1_pos == t2_pos) xsinc2 = 1.0; else { rest = sin(M_PI * xsinc2); xsinc2 = rest / (M_PI * xsinc2); } THETA[k_index2] = (float) (xsinc1 * xsinc2); } /* end k_index2-loop */ // calc matrix product THETA*PHI_INV for (j = 0; j < NP; j++) { W_pilots[j] = 0.0; for (k = 0; k < NP; k++) W_pilots[j] += THETA[k] * PHI_INV[k][j]; } for (j = 0; j < NP; j++) { W_pilots_blk[nnn][j][k_index1] = W_pilots[j]; } } /* end k_index1-loop */ } /* end nnn-loop pa0mbo 26-5-2007 */ for (i = 0; i < rndcnt; i++) { temp = ((gain_ref_cells_k[i] - K_min) / (carrier_per_symbol)) * (K_modulo - carrier_per_symbol); gain_ref_cells_k[i] += temp + K_dc - 1; } lFAC = mkfacmap(robustness_mode, K_dc, K_modulo, FAC_cells_k); mode_and_occupancy_code_last = mode_and_occupancy_code; for (i = 0; i < cnt_tr_cells[y-1]; i++) // joma y-1 was y { next_pilots[2 * i] = 0.0; /* real part */ // modified joma was j now i next_pilots[2 * i + 1] = 0.0; /* imag */ } gain_ref_cells_per_frame = rndcnt; gain_ref_cells_per_y_symbols = rndcnt / (symbols_per_frame / y); } // in matlab code here for display toctic_equalization = 0 etc t_smp = 0; for (i = 0; i < symbols_per_frame; i++) { symbol_counter++; // shifted symbol index nn = (i - symbols_to_delay + symbols_per_frame) % symbols_per_frame; ntwee = nn % y; mtwee = nn / y; for (j = 0; j < cnt_tr_cells[ntwee]; j++) { gain_ref_cells_subset_nn[j] =(mtwee * gain_ref_cells_per_y_symbols + gain_ref_cells_subset_index[ntwee][j]) % gain_ref_cells_per_frame; training_cells_relative_index[j] =(gain_ref_cells_k[gain_ref_cells_subset_nn[j]] +(symbols_per_frame -nn) * K_modulo) % (K_modulo * symbols_per_frame); } cnt_actual_pilots_rel_indx = 0; // logfile->addToAux(QString("block %1").arg(iterationCounter)); for (j = 0; j < cnt_tr_cells[ntwee]; j++) { if ((training_cells_relative_index[j] - (symbols_per_2D_window-1) * K_modulo) >= 0) { actual_pilots_relative_index[cnt_actual_pilots_rel_indx++] = j; } ntc_indx = training_cells_relative_index[j] + i * K_modulo + 1; /* pa0mbo in matlab +1 =OK trcrindx 1 lager dan in M */ hoek =(float) (2.0 * M_PI *(float)gain_ref_cells_theta_1024[gain_ref_cells_subset_nn[j]] /1024.0); tmpreal =(float) (cos(hoek) / gain_ref_cells_a[gain_ref_cells_subset_nn[j]]); tmpimag =(float) (-sin(hoek) /gain_ref_cells_a[gain_ref_cells_subset_nn[j]]); normalized_training_cells[2 * j] = symbol_buffer[2 * ntc_indx] * tmpreal - symbol_buffer[2 * ntc_indx + 1] * tmpimag; /* real part */ normalized_training_cells[2 * j + 1] = symbol_buffer[2 * ntc_indx + 1] * tmpreal + symbol_buffer[2 * ntc_indx] * tmpimag; /* imag part */ } for (j = 0; j < cnt_actual_pilots_rel_indx; j++) { actual_pilots[2 * j] = normalized_training_cells[2 * (actual_pilots_relative_index[j])]; /* real part */ actual_pilots[2 * j + 1] = normalized_training_cells[2 * (actual_pilots_relative_index[j]) + 1]; /* imag */ } temp1 = 0.0; temp2 = 0.0; for (j = 0; j < cnt_actual_pilots_rel_indx; j++) { temp1 += actual_pilots[2 * j] * next_pilots[2 * j] + actual_pilots[2 * j + 1] * next_pilots[2 * j + 1]; /* real part */ temp2 += actual_pilots[2 * j] * next_pilots[2 * j + 1] -actual_pilots[2 * j + 1] * next_pilots[2 * j]; } if (i != 0) delta_freq_offset = (float) atan2(temp2, temp1 + MIN_ABS_H); for (j = 0; j < K_max - K_min + 1; j++) { H[2 * j] = 0.0; H[2 * j + 1] = 0.0; for (k = 0; k < cnt_tr_cells[ntwee]; k++) { H[2 * j] += normalized_training_cells[2 * k] * W_symbol_blk[ntwee][k][j]; H[2 * j + 1] += normalized_training_cells[2 * k + 1] * W_symbol_blk[ntwee][k][j]; } } for (j = 0; j < cnt_actual_pilots_rel_indx; j++) { next_pilots[2 * j] = 0.0; next_pilots[2 * j + 1] = 0.0; for (k = 0; k < cnt_tr_cells[ntwee]; k++) { next_pilots[2 * j] += normalized_training_cells[2 * k] * W_pilots_blk[ntwee][k][j]; next_pilots[2 * j + 1] += normalized_training_cells[2 * k + 1] * W_pilots_blk[ntwee][k][j]; } } for (j = K_min; j <= K_max; j++) { trxbuf_indx = transmission_frame_buffer_wptr + i * K_modulo + K_dc + j; symbuf_indx = (i + symbols_to_delay) * K_modulo + K_dc + j; tmp1 = H[2 * (j - K_min)] * H[2 * (j - K_min)] + H[2 * (j - K_min) +1] * H[2 * (j -K_min) +1] + MIN_ABS_H; tmp2 = H[2 * (j - K_min)] / tmp1; tmp3 = -H[2 * (j - K_min) + 1] / tmp1; transmission_frame_buffer[2 * trxbuf_indx] =symbol_buffer[2 * symbuf_indx] * tmp2 -symbol_buffer[2 * symbuf_indx + 1] * tmp3; transmission_frame_buffer[2 * trxbuf_indx + 1] =symbol_buffer[2 * symbuf_indx] * tmp3 +symbol_buffer[2 * symbuf_indx + 1] * tmp2; channel_transfer_function_buffer[2 * trxbuf_indx] =H[2 * (j - K_min)]; channel_transfer_function_buffer[2 * trxbuf_indx + 1] =H[2 * (j - K_min) + 1]; } // get next symbol if ((iterationCounter>=0) && (iterationCounter<=180)) { // arrayDump("b179",&rs_buffer[2 * t_smp],Ts,true); // logfile->addToAux(QString("block %1").arg(iterationCounter)); // arrayDump("h179",H,K_max - K_min + 1,true); } delta_time_offset_integer =getofdmsync(&rs_buffer[2 * t_smp], Ts, Tu, H, K_max - K_min + 1,delta_freq_offset, Zi, symbol_temp, 0, 1,1); // arrayDump("symtmp",symbol_temp,K_modulo,true); // addToLog(QString("delta_time_offset_integer %1").arg(delta_time_offset_integer),LOGDRMDEMOD); for (j = 0; j < K_modulo; j++) { symbol_buffer[(symbufwidx * K_modulo + j) * 2] = symbol_temp[j * 2]; symbol_buffer[(symbufwidx * K_modulo + j) * 2 + 1] = symbol_temp[j * 2 + 1]; } symbufwidx++; t_smp += Ts + delta_time_offset_integer; /* next symbol */ } /* end i-loop over symbols_per_frame */ // fac_valid=0; freq_offset = Zi[4]; time_offset_fractional = Zi[5]; delta_time_offset_I = Zi[2]; addToLog("GREEN on channel estimation",LOGDRMDEMOD); // clock too slow or too fast: adjust playing speed smp_rate_conv_fft_phase_diff = 4 * (t_smp - N_symbols_needed * Ts); smp_rate_conv_fft_phase_offset = 4 * time_offset_fractional; smp_rate_conv_in_out_delay += smp_rate_conv_fft_phase_diff; addToLog(QString("Rate %1 %2 %3").arg(smp_rate_conv_fft_phase_diff).arg(smp_rate_conv_fft_phase_offset).arg(smp_rate_conv_in_out_delay),LOGDRMDEMOD); // display results freqOffset=-freq_offset * 12000.0 / (float) Tu / (2.0 * M_PI); deltaFS= (1.0 / (delta_time_offset_I / Ts + 1.0) - 1.0) ; samplerate_offset=delta_time_offset_I /Ts; // symbol align rs_buffer // swap symbol buffer symbufwidx -= symbols_per_frame; for (i = 0; i < symbufwidx * K_modulo; i++) { symbol_buffer[i * 2] = symbol_buffer[2 * symbols_per_frame * K_modulo + 2 * i]; symbol_buffer[i * 2 + 1] = symbol_buffer[2 * symbols_per_frame * K_modulo + 2 * i + 1]; } // SNR estimation using FAC cells // mean energy of used cells set in listsinit() sum_MERFAC = 0.0; sum_WMERFAC = 0.0; sum_weight_FAC = 0.0; for (i = 0; i < lFAC; i++) { trxbuf_indx = transmission_frame_buffer_wptr + FAC_cells_k[i]; /* pa0mbo 18-5-2007 checked */ FAC_cells_sequence[i * 2] = transmission_frame_buffer[2 * trxbuf_indx]; FAC_cells_sequence[i * 2 + 1] = transmission_frame_buffer[2 * trxbuf_indx + 1]; t1 = (float) (fabs(FAC_cells_sequence[i * 2]) - sqrt(0.5)); t1 = t1 * t1; t2 = (float) (fabs(FAC_cells_sequence[i * 2 + 1]) - sqrt(0.5)); t2 = t2 * t2; FAC_squared_noise_sequence[i] = t1 + t2; t1 = channel_transfer_function_buffer[trxbuf_indx * 2]; t1 = t1 * t1; t2 = channel_transfer_function_buffer[trxbuf_indx * 2 + 1]; t2 = t2 * t2; squared_weight_sequence[i] = t1 + t2; sum_MERFAC += FAC_squared_noise_sequence[i]; sum_WMERFAC += FAC_squared_noise_sequence[i] * (squared_weight_sequence[i] + 1.0E-10); sum_weight_FAC += squared_weight_sequence[i]; } FACAvailable=true; MERFAC = (float) (log(sum_MERFAC / lFAC + 1.0E-10)); MERFAC /= (log(10.0)); MERFAC *= -10.0; WMERFAC =(float) (log(sum_WMERFAC /(mean_energy_of_used_cells * (sum_weight_FAC + lFAC * 1.0E-10)))); WMERFAC /= (log(10.0)); WMERFAC *= -10.0; SNR_dB = WMERFAC; addToLog(QString("SNR-FAC =%1").arg(SNR_dB),LOGDRMDEMOD); // N_samples_needed = (symbols_per_frame + 1) * Ts - rsbufwidx; if (SNR_dB < SNR_MIN_DB) { SNR_timeout_counter--; if (SNR_timeout_counter <= 0) { doSynchronize = true; SNR_timeout_counter = SNR_TIMEOUT; } transmission_frame_buffer_data_valid = 0; fac_not_valid_counter--; if (fac_not_valid_counter <= 0) { doSynchronize = true; fac_not_valid_counter = FACVALIDCNTR; } } else { SNR_timeout_counter = SNR_TIMEOUT; transmission_frame_buffer_data_valid = 1; fac_valid = 1; } if (doSynchronize) N_samples_needed = N_symbols_mode_detection * 320 - rsbufwidx; else { rsbufwidx -= t_smp; for (i = 0; i < rsbufwidx; i++) { rs_buffer[i * 2] = rs_buffer[(i + t_smp) * 2]; rs_buffer[i * 2 + 1] = rs_buffer[(i + t_smp) * 2 + 1]; } N_samples_needed = (symbols_per_frame + 1) * Ts - rsbufwidx; } if (N_samples_needed > 0) { input_samples_buffer_request = N_samples_needed; } else { input_samples_buffer_request = 0; } return true; } qsstv_8.2.12/qsstv/drmrx/demodulator.h000664 001750 001750 00000006164 12440612574 020006 0ustar00jomajoma000000 000000 #ifndef DEMODULATOR_H #define DEMODULATOR_H #include #include "drmproto.h" #include "drmdefs.h" #include "sourcedecoder.h" #define SNR_TIMEOUT 10 #define FACVALIDCNTR 10 #define SNR_MIN_DB 3 #define DRMNUMMODES 4 //original //#define SNR_TIMEOUT 3 //#define FAC_NOT_VALID 4 //#define SNR_MIN_DB 5 //#define FAC_NOT_VALID_TIMEOUT 4 extern int Ts_list[DRMNUMMODES]; extern int Tu_list[DRMNUMMODES]; extern int Tg_list[DRMNUMMODES]; class demodulator { public: demodulator(); ~demodulator(); void init(); bool demodulate(float *sigin, int numSamples); bool isTimeSync() {return timeSyncFlag;} bool isFrequencySync() {return frequencySyncFlag;} bool isFrameSync() {return frameSyncFlag;} private: int iterationCounter; bool timeSync(); bool frequencySync(); bool frameSync(); bool channelEstimation(); // bool FACAvailable; int symbol_counter; int N_samples_needed; int SNR_time_out_counter; int fac_not_valid_counter; int mode_and_occupancy_code_last; int rsbufwidx; int symbufwidx; int smp_rate_conv_fft_phase_diff; float smp_rate_conv_fft_phase_offset; int smp_rate_conv_in_out_delay; fftwf_plan p1; drmComplex ss[256], S[256]; // float rs_buffer[DRMBUFSIZE]; float rs_buffer[10*8000]; bool doSynchronize; bool timeSyncFlag; bool frequencySyncFlag; bool frameSyncFlag; int numberOfSamples; smode_info mode_block; float time_offset; float frequency_offset_fractional_init; int time_offset_integer; int counter; int Ts, Tu, Tg, Tgh; float freq_offset_integer; int x,y, k0; int symbols_per_2D_window; int delta_time_offset_integer; float time_offset_fractional_init; float freq_offset_init; float delta_time_offset_I_init; float Zi[6]; float symbol_temp[2 * Tu_A]; float symbol_buffer[Tu_A * 2 * 26]; int time_ref_cells_k[21]; int time_ref_cells_theta_1024[21]; int symbols_to_delay; int N_symbols_needed; int no_of_used_cells_per_frame_list[24]; float sigmaq_noise_list[4]; int gain_ref_cells_k[712]; int gain_ref_cells_theta_1024[712]; float gain_ref_cells_a[712]; int training_cells_k[5][712]; int cnt_tr_cells[5]; int gain_ref_cells_per_frame; int gain_ref_cells_per_y_symbols; float next_pilots[2*70]; /* complex */ //joma int K_min,K_max; float W_symbol_blk[5][208][229]; float W_symbol[208]; float W_pilots_blk[5][208][205]; float W_pilots[208]; int SNR_timeout_counter; float delta_freq_offset; int mode_and_occupancy_code; int carrier_per_symbol; int freq_ref_cells_k[3]; int freq_ref_cells_theta_1024[3]; int power_boost[4]; int Q_1024; int gain_ref_cells_subset[5][209]; int gain_ref_cells_subset_index[5][209]; int cnt_next_pilot_cells[5]; int next_pilot_cells_k_index[5][40]; int next_pilot_cells_k[5][40]; float PHI[208][208]; float PHI_INV[208][208]; float THETA[208]; int gain_ref_cells_subset_nn[209]; int training_cells_relative_index[209]; int actual_pilots_relative_index[209]; float normalized_training_cells[1424]; float actual_pilots[458]; float H[458]; float delta_time_offset_I; float time_offset_fractional; bool initChannelEstimation; }; #endif // DEMODULATOR_H qsstv_8.2.12/qsstv/drmrx/drm.cpp000664 001750 001750 00000013524 12440612574 016602 0ustar00jomajoma000000 000000 /* * File drm.h * * M.Bos - PA0MBO * Date feb 21st 2009 */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include "drm.h" //float acq_signal[2*DRMBUFSIZE]; //contains complex numbers int input_samples_buffer_request; int symbols_per_frame_list[4] = { 15, 15, 20, 24 }; int time_ref_cells_k_list[4][21] = { {6, 7, 11, 12, 15, 16, 23, 29, 30, 33, 34, 38, 39, 41, 45, 46, 0, 0, 0, 0, 0}, {6, 10, 11, 14, 17, 18, 27, 28, 30, 33, 34, 38, 40, 41, 44, 0, 0, 0, 0, 0, 0}, {7, 8, 13, 14, 21, 22, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0} }; int time_ref_cells_theta_1024_list[4][21] = { {973, 205, 717, 264, 357, 357, 952, 440, 856, 88, 88, 68, 836, 836, 836, 1008, 0, 0, 0, 0, 0}, {304, 331, 108, 620, 192, 704, 44, 432, 588, 844, 651,651, 651, 460, 950, 0, 0, 0, 0, 0, 0}, {432, 331, 108, 620, 192, 704, 44, 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0} }; int y_list[4] = { 5, 3, 4, 3 }; int symbols_per_2D_window_list[4] = { 10, 6, 8, 6 }; int symbols_to_delay_list[4] = { 5, 3, 4, 3 }; float cpsd[513], psd[513]; int N_symbols_frequency_pilot_search = 15; int K_min_K_max_list[2][24] = { {2, 2, -102, -114, -98, -110, 1, 1, -91, -103, -87, -99, 1, 1, 0, -69, 0, -67, 0, 0, 0, -44, 0, -43}, {54, 58, 102, 114, 314, 350, 45, 51, 91, 103, 279, 311, 29,31, 0, 69, 0, 213, 0, 0, 0, 44, 0, 135} }; float samplerate_offset_estimation; float samplerate_offset; int N_symbols_mode_detection; int time_offset_log_last; int transmission_frame_buffer_data_valid; int fac_valid=0; int no_of_unused_carriers_list[4] = { 2, 1, 1, 1 }; int freq_ref_cells_k_list[4][3] = { {9, 27, 36}, {8, 24, 32}, {5, 15, 20}, {5, 15, 20}}; int freq_ref_cells_theta_1024_list[4][3] = { {205, 836, 215}, {331, 651, 555}, {788, 1014, 332}, {788, 1014, 332} }; int x_list[4] = { 4, 2, 1, 1 }; int k0_list[4] = { 2, 1, 1, 1 }; int dimw1024[4][2] = { {5, 3}, {3, 5}, {2, 10}, {3, 8} }; /* matrix[mode][n][m] */ int W_1024_list[4][5][10] = { {{228, 341, 455, 0, 0, 0, 0, 0, 0, 0}, {455, 569, 683, 0, 0, 0, 0, 0, 0, 0}, {683, 796, 910, 0, 0, 0, 0, 0, 0, 0}, {910, 0, 114, 0, 0, 0, 0, 0, 0, 0}, {114, 228, 341, 0, 0, 0, 0, 0, 0, 0}}, {{512, 0, 512, 0, 512, 0, 0, 0, 0, 0}, {0, 512, 0, 512, 0, 0, 0, 0, 0, 0}, {512, 0, 512, 0, 512, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{512, 0, 512, 0, 512, 0, 0, 0, 0, 0}, {0, 512, 0, 512, 0, 0, 0, 0, 0, 0}, {512, 0, 512, 0, 512, 0, 0, 0, 0, 0}, {0, 512, 0, 512, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{465, 372, 279, 186, 93, 0, 931, 838, 745, 652}, {931, 838, 745, 652, 559, 465, 372, 279, 186, 93}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; int Z_256_list[4][5][10] = { {{0, 81, 248, 0, 0, 0, 0, 0, 0, 0}, {18, 106, 106, 0, 0, 0, 0, 0, 0, 0}, {122, 116, 31, 0, 0, 0, 0, 0, 0, 0}, {129, 129, 39, 0, 0, 0, 0, 0, 0, 0}, {33, 32, 111, 0, 0, 0, 0, 0, 0, 0}}, {{0, 57, 164, 64, 12, 0, 0, 0, 0, 0}, {168, 255, 161, 106, 118, 0, 0, 0, 0, 0}, {25, 232, 132, 233, 38, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 57, 164, 64, 12, 0, 0, 0, 0, 0}, {168, 255, 161, 106, 118, 0, 0, 0, 0, 0}, {25, 232, 132, 233, 38, 0, 0, 0, 0, 0}, {168, 255, 161, 106, 118, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 240, 17, 60, 220, 38, 151, 101, 0, 0}, {110, 7, 78, 82, 175, 150, 106, 25, 0, 0}, {165, 7, 252, 124, 253, 177, 197, 142, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; int Q_1024_list[4] = { 36, 12, 10, 14 }; int power_boost_list[4][6][4] = { {{2, 6, 50, 54}, {2, 6, 54, 58}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{1, 3, 43, 45}, {1, 3, 49, 51}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{1, 29, 0, 0}, {1, 31, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} }; int mode_and_occupancy_code_table[14] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; int robustness_mode, spectrum_occupancy_estimation; int spectrum_occupancy; int symbols_per_frame; int time_ref_cells_cnt_list[4] = { 16, 15, 8, 16 }; int K_modulo, K_dc; float mean_energy_of_used_cells; int FAC_cells_k[65]; float transmission_frame_buffer[82980]; /* complex */ float channel_transfer_function_buffer[82980]; /* complex */ int transmission_frame_buffer_wptr = 0; int lFAC; //Display * display; int runstate; struct mplex_desc multiplex_description; struct audio_info audio_information; struct appl_info application_information; struct stream_info stream_information; struct time_info time_and_date; struct dflttmsg default_text_message; struct dfltdunitasmbly default_data_unit_assembly; struct dfltMOTdirasmbly default_MOT_directory_assembly; struct dfltMOTobjasmbly default_MOT_object_assembly; struct dfltMOTobjasmblyinfo default_MOT_object_assembly_information; struct dfltMOTobj default_MOT_object; int channel_decoded_data_buffer_data_valid; double channel_decoded_data_buffer[110000]; float WMERFAC; /* char text_message[1000]; */ int audio_data_flag; int length_decoded_data; int MSC_Demapper[6][2959]; long bufaucnt[2048]; qsstv_8.2.12/qsstv/drmrx/drm.h000664 001750 001750 00000006355 12440612574 016253 0ustar00jomajoma000000 000000 #ifndef DRM_H #define DRM_H /* * File drm.h * * M.Bos - PA0MBO * Date feb 21st 2009 */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include "drmdefs.h" #include "structtemplates.h" class demodulator; extern int input_samples_buffer_request; extern int symbols_per_frame_list[4]; extern int time_ref_cells_k_list[4][21]; extern int time_ref_cells_theta_1024_list[4][21]; extern int y_list[4]; extern int symbols_per_2D_window_list[4]; extern int symbols_to_delay_list[4]; extern int N_symbols_frequency_pilot_search; extern int K_min_K_max_list[2][24]; extern float samplerate_offset_estimation; extern float samplerate_offset; //ON4QZ extern int N_symbols_mode_detection; extern int time_offset_log_last; extern int transmission_frame_buffer_data_valid; extern int fac_valid; extern int no_of_unused_carriers_list[4]; extern int freq_ref_cells_k_list[4][3]; extern int freq_ref_cells_theta_1024_list[4][3]; extern int x_list[4]; extern int k0_list[4]; extern int dimw1024[4][2]; /* matrix[mode][n][m] */ extern int W_1024_list[4][5][10]; extern int Z_256_list[4][5][10]; extern int Q_1024_list[4]; extern int power_boost_list[4][6][4]; extern int mode_and_occupancy_code_table[14]; extern int robustness_mode, spectrum_occupancy_estimation; extern int spectrum_occupancy; extern int symbols_per_frame; extern int time_ref_cells_cnt_list[4]; extern int K_modulo, K_dc; extern float mean_energy_of_used_cells; extern int FAC_cells_k[65]; extern float transmission_frame_buffer[82980]; /* complex */ extern float channel_transfer_function_buffer[82980]; /* complex */ extern int transmission_frame_buffer_wptr; extern int lFAC; extern float cpsd[513], psd[513]; //Display * display; extern int runstate; extern struct mplex_desc multiplex_description; extern struct audio_info audio_information; extern struct appl_info application_information; extern struct stream_info stream_information; extern struct time_info time_and_date; extern struct dflttmsg default_text_message; extern struct dfltdunitasmbly default_data_unit_assembly; extern struct dfltMOTdirasmbly default_MOT_directory_assembly; extern struct dfltMOTobjasmbly default_MOT_object_assembly; extern struct dfltMOTobjasmblyinfo default_MOT_object_assembly_information; extern struct dfltMOTobj default_MOT_object; extern int channel_decoded_data_buffer_data_valid; extern double channel_decoded_data_buffer[110000]; extern float WMERFAC; extern bool callsignValid; /* char text_message[1000]; */ extern int audio_data_flag; extern int length_decoded_data; extern int MSC_Demapper[6][2959]; extern long bufaucnt[2048]; extern int spectrum_occupancy_new; extern int msc_mode_new; extern int interleaver_depth_new; extern float freqOffset; extern float deltaFS; //extern char drmCallsign[9]; extern demodulator *demodulatorPtr; #endif qsstv_8.2.12/qsstv/drmrx/drmconstellationframe.cpp000664 001750 001750 00000004016 12440612574 022410 0ustar00jomajoma000000 000000 #include "drmconstellationframe.h" #include "ui_drmconstellationframe.h" #include #include "drm.h" #include "math.h" #include "qsstvdefs.h" extern float MSC_cells_sequence[2 * 2959]; extern int lMSC; extern bool MSCAvailable; extern int lFAC; extern float FAC_cells_sequence[200]; extern bool FACAvailable; #define CSTRANGE 1.5 #define CSTSPAN 3. drmConstellationFrame::drmConstellationFrame(QWidget *parent) : QFrame(parent), ui(new Ui::drmConstellationFrame) { ui->setupUi(this); lmsc=0; } drmConstellationFrame::~drmConstellationFrame() { delete ui; } void drmConstellationFrame::paintEvent (QPaintEvent *e) { int i,posx,posy; QPainter qpainter (this); // qpainter.drawRect (contentsRect()); qpainter.setPen (QPen (Qt::blue, 2)); qpainter.drawLine (contentsRect().x()+contentsRect().width()/2, contentsRect().y(), contentsRect().x()+contentsRect().width()/2,contentsRect().y()+contentsRect().height()); qpainter.drawLine (contentsRect().x(), contentsRect().y()+contentsRect().height()/2, contentsRect().x()+contentsRect().width(),contentsRect().y()+contentsRect().height()/2); for(i=0;i enum econstellation {FAC,MSC}; namespace Ui { class drmConstellationFrame; } class drmConstellationFrame : public QFrame { Q_OBJECT public: explicit drmConstellationFrame(QWidget *parent = 0); ~drmConstellationFrame(); void setConstellation(econstellation constellation); void clearConstellation(); private: Ui::drmConstellationFrame *ui; void paintEvent (QPaintEvent *); float ConstellationArray[2 * 2959]; int lmsc; }; #endif // DRMCONSTELLATIONFRAME_H qsstv_8.2.12/qsstv/drmrx/drmconstellationframe.ui000664 001750 001750 00000007744 12440612574 022256 0ustar00jomajoma000000 000000 drmConstellationFrame 0 0 400 300 76 76 76 180 180 180 0 0 0 60 60 60 76 76 76 76 76 76 180 180 180 0 0 0 60 60 60 76 76 76 0 0 0 180 180 180 0 0 0 0 0 0 0 0 0 Frame QFrame::Panel QFrame::Sunken 3 qsstv_8.2.12/qsstv/drmrx/drmdatainput.cpp000664 001750 001750 00000037232 12440612574 020516 0ustar00jomajoma000000 000000 #include "drmdatainput.h" #include "qsstvglobal.h" #include "dsp/filter.h" #include "dsp/downsamplefilter.h" #include "drm.h" #include "drmproto.h" #include "sound/soundio.h" #include "utils/supportfunctions.h" #include "dsp/filterparam.h" #define FILTERLENGTH 8 //#define HILBERT83 #define HILBERT151 //#define HILBERT360 #ifdef HILBERT83 #define HILBERTTAPS 83 #endif #ifdef HILBERT151 #define HILBERTTAPS 151 #endif #ifdef HILBERT360 #define HILBERTTAPS 360 #endif //static float subfilt1[FILTERLENGTH] = //{ // -6.304691e-004, // 2.369513e-003, // -9.174512e-003, // 3.102797e-002, // 2.437302e-001, // -2.230165e-002, // 6.759297e-003, // -1.587494e-003 //}; //static float subfilt2[FILTERLENGTH] = //{ // -1.818568e-003, // 8.332497e-003, // -2.973091e-002, // 1.111435e-001, // 1.924554e-001, // -3.981645e-002, // 1.180361e-002, // -2.561942e-003 //}; //static float subfilt3[FILTERLENGTH] = //{ // -2.561942e-003, // 1.180361e-002, // -3.981645e-002, // 1.924554e-001, // 1.111435e-001, // -2.973091e-002, // 8.332497e-003, // -1.818568e-003 //}; //static float subfilt4[FILTERLENGTH] = //{ // -1.587494e-003, // 6.759297e-003, // -2.230165e-002, // 2.437302e-001, // 3.102797e-002, // -9.174512e-003, // 2.369513e-003, // -6.304691e-004 //}; //static float B_Inphase[HILBERTTAPS] = //{ // -0.000013096429498, // 0.000000663887755, // -0.000069635287780, // -0.000011931707517, // -0.000144533153108, // -0.000025373980217, // -0.000391789228659, // -0.000232426477943, // -0.000478143393960, // -0.000487558968789, // -0.000685650336825, // -0.001354704880460, // -0.000546201344479, // -0.002342397998132, // -0.000346673289958, // -0.004288405547670, // 0.000076514567549, // -0.006214057213030, // 0.000471140764452, // -0.008869259301553, // 0.000310928936475, // -0.010853542810835, // -0.000618723760850, // -0.012558669622822, // -0.003528318293013, // -0.012565638823234, // -0.008458796942648, // -0.010998473138919, // -0.016909533624041, // -0.007029340421051, // -0.028648813220546, // -0.000916074544044, // -0.045239295406484, // 0.007126861010101, // -0.067146558987974, // 0.016470713456071, // -0.099200587662524, // 0.025927955112860, // -0.157545675961710, // 0.034759206835915, // -0.403756659009051, // 0.872044314623357, // 0.298152956415124, // 0.045762401414113, // 0.057682372386628, // 0.046612304642337, // 0.009812557897304, // 0.044738697480695, // -0.007877026958678, // 0.039793922738241, // -0.014019542011307, // 0.033363547774391, // -0.014228247558443, // 0.025586601071249, // -0.011722710151015, // 0.018169441690637, // -0.007774072820479, // 0.011227152592688, // -0.004254206945683, // 0.005868718139545, // -0.001002308783387, // 0.001901375136305, // 0.000729336127630, // -0.000472570900136, // 0.001969539594901, // -0.001560255803054, // 0.001905716822635, // -0.001878235948282, // 0.001813958429404, // -0.001475079548897, // 0.001117144708583, // -0.001143142395249, // 0.000739068897549, // -0.000539580485663, // 0.000277728151810, // -0.000341625345467, // 0.000100860733753, // -0.000052333537017, // 0.000001973643242, // -0.000040013168559, // -0.000013316614262, // 0.000006340573991, // -0.000004973750149 //}; //static float B_Quad[HILBERTTAPS] = // { 0.000000000000000, -0.000006581551523, -0.000014192774668, //0.000038355453153, -0.000061469802717, 0.000046155098672, // -0.000269873790862, 0.000273874035623, -0.000496517495085, // 0.000383120218360, -0.001080412050939, 0.000679569009380, // -0.001431859472243, // 0.000632904747289, -0.002103194937170, 0.000269803608080, // -0.002028650339142, -0.000864482682011, -0.001935633229621, // -0.003130320749406, // -0.000660757624173, -0.006511157948451, 0.000829477180331, // -0.011499838339182, 0.003150251021340, -0.017295118095470, // 0.004931046332886, // -0.024156288476640, 0.005730140929231, -0.030544691199518, // 0.003619186767370, -0.036441773169957, -0.003417440897749, // -0.040091021199004, // -0.019051201727783, -0.041600273509535, -0.051332869304505, // -0.039743071204460, -0.127032560999817, -0.035198771562362, // -0.488057960837085, // -0.584664836150859, 0.558860293285832, -0.018787192344116, // 0.193986224985834, -0.008891772659445, 0.111263353226189, // 0.000562232648398, // 0.069350999397921, 0.008632835092782, 0.043147713646936, // 0.014687263334153, 0.025127872636149, 0.018102917799341, // 0.013466436394485, // 0.019348490199617, 0.005952331932605, 0.018192510371929, // 0.002067567347773, 0.015985137219339, 0.000257349155187, // 0.012513166744168, // -0.000036691339210, 0.009393580004274, 0.000299271454802, // 0.006076795140808, 0.000699657108499, 0.003864640455567, // 0.001119449029703, // 0.001926535004930, 0.001049068709402, 0.000995120503174, // 0.001044597409952, 0.000305528639009, 0.000630886520545, // 0.000111000803475, // 0.000464927709514, 0.000005944149118, 0.000157049271650, // -0.000003528848644, 0.000069808136642, 0.000001885388254, // 0.000012115208419, //}; #ifdef HILBERT83 // blFIR Hilbert // localSamplingrate = 12000.000000 // number of taps = 83 // corner frequency = 1000.000000 // beta = 0.500000 // window applied //Coefficients: const FILTERPARAMTYPE hilbert[HILBERTTAPS]= { 0.00195121951219512, 0, 0.00218951295028307, 0, 0.00274155836904681, 0, 0.00365039553708327, 0, 0.00496219678931242, 0, 0.00672774409495607, 0, 0.00900470037777058, 0, 0.01186106975868, 0, 0.0153804894372836, 0, 0.0196704386862718, 0, 0.024875273452504, 0, 0.0311975987201718, 0, 0.0389347935888508, 0, 0.0485447715399211, 0, 0.0607723902308125, 0, 0.0769136201887418, 0, 0.0994316691908993, 0, 0.13362885988773, 0, 0.193330225501393, 0, 0.329299964994593, 0, 0.998650268544521, 0, -0.998650268544521, 0, -0.329299964994593, 0, -0.193330225501393, 0, -0.13362885988773, 0, -0.0994316691908993, 0, -0.0769136201887418, 0, -0.0607723902308125, 0, -0.0485447715399211, 0, -0.0389347935888508, 0, -0.0311975987201718, 0, -0.024875273452504, 0, -0.0196704386862718, 0, -0.0153804894372836, 0, -0.01186106975868, 0, -0.00900470037777058, 0, -0.00672774409495607, 0, -0.00496219678931242, 0, -0.00365039553708327, 0, -0.00274155836904681, 0, -0.00218951295028307, 0, -0.00195121951219512 }; #endif #ifdef HILBERT151 // blFIR Hilbert // localSamplingrate = 12000.000000 // number of taps = 151 // corner frequency = 1000.000000 // beta = 0.500000 // window applied //Coefficients: const FILTERPARAMTYPE hilbert[HILBERTTAPS]= { 0.00106666666666667, 0, 0.00111799020198943, 0, 0.00121749046405025, 0, 0.00136886588233087, 0, 0.00157592342822028, 0, 0.00184260137668314, 0, 0.00217299884412417, 0, 0.00257141359464515, 0, 0.00304238999373074, 0, 0.00359077949800265, 0, 0.00422181674681683, 0, 0.00494121522949637, 0, 0.00575528773156199, 0, 0.00667109844581354, 0, 0.00769665596238367, 0, 0.0088411596130561, 0, 0.0101153162732349, 0, 0.0115317513868608, 0, 0.0131055477183722, 0, 0.0148549598147661, 0, 0.0168023740886606, 0, 0.0189756183245283, 0, 0.0214097779833233, 0, 0.0241497635092426, 0, 0.0272540175599975, 0, 0.0308, 0, 0.0348925322232539, 0, 0.0396769064421141, 0, 0.045360270349271, 0, 0.0522481015058711, 0, 0.0608098544941651, 0, 0.0718051968979872, 0, 0.0865479463372845, 0, 0.107521909278733, 0, 0.140052424123536, 0, 0.19798957926751, 0, 0.332124254201553, 0, 0.999596501845475, 0, -0.999596501845475, 0, -0.332124254201553, 0, -0.19798957926751, 0, -0.140052424123536, 0, -0.107521909278733, 0, -0.0865479463372845, 0, -0.0718051968979872, 0, -0.0608098544941651, 0, -0.0522481015058711, 0, -0.045360270349271, 0, -0.0396769064421141, 0, -0.0348925322232539, 0, -0.0308, 0, -0.0272540175599975, 0, -0.0241497635092426, 0, -0.0214097779833233, 0, -0.0189756183245283, 0, -0.0168023740886606, 0, -0.0148549598147661, 0, -0.0131055477183722, 0, -0.0115317513868608, 0, -0.0101153162732349, 0, -0.0088411596130561, 0, -0.00769665596238367, 0, -0.00667109844581354, 0, -0.00575528773156199, 0, -0.00494121522949637, 0, -0.00422181674681683, 0, -0.00359077949800265, 0, -0.00304238999373074, 0, -0.00257141359464515, 0, -0.00217299884412417, 0, -0.00184260137668314, 0, -0.00157592342822028, 0, -0.00136886588233087, 0, -0.00121749046405025, 0, -0.00111799020198943, 0, -0.00106666666666667 }; #endif #ifdef HILBERT360 // blFIR Hilbert // localSamplingrate = 12000.000000 // number of taps = 360 // corner frequency = 8000.000000 // beta = 1.000000 // window applied //Coefficients: const FILTERPARAMTYPE hilbert[HILBERTTAPS]= { 0.000447320955694772, 0, 0.000455558927413046, 0, 0.000467201131289238, 0, 0.000482357657235191, 0, 0.000501139723312327, 0, 0.000523659757475149, 0, 0.000550031490215828, 0, 0.000580370059009746, 0, 0.000614792125543957, 0, 0.000653416006801779, 0, 0.000696361821178391, 0, 0.000743751650915635, 0, 0.000795709722270862, 0, 0.000852362604976147, 0, 0.000913839432702755, 0, 0.000980272146423472, 0, 0.00105179576276502, 0, 0.0011285486696673, 0, 0.001210672951919, 0, 0.0012983147494246, 0, 0.00139162465137996, 0, 0.00149075812989859, 0, 0.00159587601704457, 0, 0.00170714502969781, 0, 0.00182473834721175, 0, 0.00194883624743331, 0, 0.0020796268073506, 0, 0.0022173066754303, 0, 0.00236208192361964, 0, 0.00251416898803742, 0, 0.00267379570858608, 0, 0.00284120247911163, 0, 0.00301664352135053, 0, 0.00320038829777273, 0, 0.00339272308060342, 0, 0.00359395269683864, 0, 0.00380440247202873, 0, 0.00402442039907038, 0, 0.00425437956232035, 0, 0.00449468085214296, 0, 0.00474575601067502, 0, 0.0050080710563162, 0, 0.00528213014245216, 0, 0.00556847991546485, 0, 0.00586771444852104, 0, 0.00618048084138014, 0, 0.00650748559305694, 0, 0.00684950187428514, 0, 0.00720737785119832, 0, 0.00758204624155527, 0, 0.00797453532156124, 0, 0.00838598164664784, 0, 0.00881764480575967, 0, 0.00927092459873636, 0, 0.00974738111417594, 0, 0.0102487582958671, 0, 0.0107770117263209, 0, 0.0113343415352682, 0, 0.0119232315715625, 0, 0.0125464962755426, 0, 0.0132073370786259, 0, 0.0139094106696869, 0, 0.0146569121483854, 0, 0.015454676997362, 0, 0.0163083070387749, 0, 0.0172243272273486, 0, 0.0182103824647697, 0, 0.019275486886001, 0, 0.0204303427008687, 0, 0.0216877523409707, 0, 0.0230631574055806, 0, 0.0245753523839949, 0, 0.0262474430643373, 0, 0.028108153434625, 0, 0.0301936384591154, 0, 0.0325500469449935, 0, 0.0352372234345217, 0, 0.0383341869762954, 0, 0.0419474683535509, 0, 0.0462242114069099, 0, 0.0513735488362621, 0, 0.0577030667580263, 0, 0.0656844408554181, 0, 0.0760796596826624, 0, 0.0902049460455389, 0, 0.110546573465011, 0, 0.142432367889117, 0, 0.199714813347055, 0, 0.333186579940791, 0, 0.999982386895462, 0, -0.999982386895462, 0, -0.333186579940791, 0, -0.199714813347055, 0, -0.142432367889117, 0, -0.110546573465011, 0, -0.0902049460455389, 0, -0.0760796596826624, 0, -0.0656844408554181, 0, -0.0577030667580263, 0, -0.0513735488362621, 0, -0.0462242114069099, 0, -0.0419474683535509, 0, -0.0383341869762954, 0, -0.0352372234345217, 0, -0.0325500469449935, 0, -0.0301936384591154, 0, -0.028108153434625, 0, -0.0262474430643373, 0, -0.0245753523839949, 0, -0.0230631574055806, 0, -0.0216877523409707, 0, -0.0204303427008687, 0, -0.019275486886001, 0, -0.0182103824647697, 0, -0.0172243272273486, 0, -0.0163083070387749, 0, -0.015454676997362, 0, -0.0146569121483854, 0, -0.0139094106696869, 0, -0.0132073370786259, 0, -0.0125464962755426, 0, -0.0119232315715625, 0, -0.0113343415352682, 0, -0.0107770117263209, 0, -0.0102487582958671, 0, -0.00974738111417594, 0, -0.00927092459873636, 0, -0.00881764480575967, 0, -0.00838598164664784, 0, -0.00797453532156124, 0, -0.00758204624155527, 0, -0.00720737785119832, 0, -0.00684950187428514, 0, -0.00650748559305694, 0, -0.00618048084138014, 0, -0.00586771444852104, 0, -0.00556847991546485, 0, -0.00528213014245216, 0, -0.0050080710563162, 0, -0.00474575601067502, 0, -0.00449468085214296, 0, -0.00425437956232035, 0, -0.00402442039907038, 0, -0.00380440247202873, 0, -0.00359395269683864, 0, -0.00339272308060342, 0, -0.00320038829777273, 0, -0.00301664352135053, 0, -0.00284120247911163, 0, -0.00267379570858608, 0, -0.00251416898803742, 0, -0.00236208192361964, 0, -0.0022173066754303, 0, -0.0020796268073506, 0, -0.00194883624743331, 0, -0.00182473834721175, 0, -0.00170714502969781, 0, -0.00159587601704457, 0, -0.00149075812989859, 0, -0.00139162465137996, 0, -0.0012983147494246, 0, -0.001210672951919, 0, -0.0011285486696673, 0, -0.00105179576276502, 0, -0.000980272146423472, 0, -0.000913839432702755, 0, -0.000852362604976147, 0, -0.000795709722270862, 0, -0.000743751650915635, 0, -0.000696361821178391, 0, -0.000653416006801779, 0, -0.000614792125543957, 0, -0.000580370059009746, 0, -0.000550031490215828, 0, -0.000523659757475149, 0, -0.000501139723312327, 0, -0.000482357657235191, 0, -0.000467201131289238, 0, -0.000455558927413046, 0, -0.000447320955694772, 0 }; #endif //double lowpass[4*FILTERLENGTH]; drmDataInput::drmDataInput(int blockSize) { iqFilter=NULL; init(blockSize); } drmDataInput::~drmDataInput() { // delete downFilter; delete iqFilter; } void drmDataInput::init(int blockSize) { if(iqFilter) delete iqFilter; iqFilter=new filter(0,hilbert,HILBERTTAPS,0,48000,false,1); inputResampler.init(blockSize); iterationCounter=0; } unsigned int drmDataInput::getData(DSPFLOAT *inputBuf,DSPFLOAT *outputBuf,DSPFLOAT rRation) { int processedSamples; inputResampler.resample(rRation,inputBuf); processedSamples=inputResampler.rxBuffer.count(); inputResampler.rxBuffer.copy(outputBuf,processedSamples); inputResampler.rxBuffer.skip(processedSamples); iqFilter->processIQ(inputBuf,outputBuf,processedSamples); return (processedSamples); } qsstv_8.2.12/qsstv/drmrx/drmdatainput.h000664 001750 001750 00000001147 12440612574 020157 0ustar00jomajoma000000 000000 #ifndef DRMDATAINPUT_H #define DRMDATAINPUT_H #include "qsstvglobal.h" #include "qsstvdefs.h" #include "drmrx/drmdefs.h" #include "sound/resampler.h" #define RESAMPLINGLEN 2048 class filter; class downsampleFilter; class drmDataInput { public: drmDataInput(int blockSize); ~drmDataInput(); // void doResample(DSPFLOAT rRation,short int *inputBuffer); unsigned int getData(DSPFLOAT *inputBuf, DSPFLOAT *outputBuf, DSPFLOAT rRation); void init(int blockSize); private: // downsampleFilter *downFilter; filter *iqFilter; resampler inputResampler; int iterationCounter; }; #endif // DRMDATAINPUT_H qsstv_8.2.12/qsstv/drmrx/drmdefs.h000664 001750 001750 00000001602 12440612574 017103 0ustar00jomajoma000000 000000 /* * File drmdefs.h * * M.Bos - PA0MBO * Date Feb 21st 2009 */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #define DRMBUFSIZE 50000 #define Ts_A 320 #define Tu_A 288 #define Tg_A 32 #define Ts_B 320 #define Tu_B 256 #define Tg_B 64 #define Ts_C 240 #define Tu_C 160 #define Tg_C 64 #define Ts_D 200 #define Tu_D 112 #define Tg_D 88 #define RUN_STATE_POWER_ON -2 #define RUN_STATE_INIT -1 #define RUN_STATE_FIRST 0 #define RUN_STATE_NORMAL 1 qsstv_8.2.12/qsstv/drmrx/drmproto.h000664 001750 001750 00000006263 12440612574 017335 0ustar00jomajoma000000 000000 #ifndef DRMPROTO_H #define DRMPROTO_H /* * file drmproto.h * * defines the protoypes for project RXAMADRM * * PA0MBO - M.BOS * * Date Feb 21st 2009 * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ struct smode_info { int mode_indx; float time_offset; float sample_rate_offset; float freq_offset_fract; }; struct soutblock_ofdm { int OKflag; float phifcl; int dtoffsI; int dfoffsI; float foffs; float toffsfr; }; void init_audio (void); //int monorec (short int *,int n); //void drmfilter (float *, float *, float *, float *, int, int); int demodulate ( /*@null@ */ float *, int, int); void drmfilter1c (float *, float *, float *, int, int); void drmfilter1 (float *, float *, float *, int, int); void initGetmode(int n); void getmode (/*@null@ */ float *, int, /*@null@ *//*@out@ */ smode_info *); float getfoffsint (float *, int, int, int, int); int resample (float *, /*@out@ */ float *, float, int, int); int getofdm ( /*@null@ */ float *, float, float, float, int, int, /*@null@ */ float *, /*@null@ */ float *, int, int, int); int getsymbolidx (float *, int, int *, int *, int, int, int); int getofdmsync ( /*@null@ */ float *, int, int, /*@null@ */ float *, int, float, /*@null@ */ float *, /*@null@ */ float *, int, int, int); int mkfacmap (int, int, int, int /*@out@ */ *); void showFAC ( /*@null@ */ float *, int, /*@null@ */ char argv[], int argc, int); int *deinterleaver (int, int, int, int); int msdhardfac ( /*@out@ */ double *, /*@out@ */ double *, int, /*@out@ */ double *, int, double *, int, int, int *, int *, int, int, double *); int mkmscmap (int, int, int, int, int); int msdhardsdc (double *, double *, int, double *, int, double *, int, int, int, int *, int *, int, int, double *); //void crc16_c (double *, double *, int); /*void copy_mplex_desc(struct mplex_desc *, struct mplex_desc *); int cmp_mplex_desc(struct mplex_desc *, struct mplex_desc *); */ int msdhardmsc (double *, double *, int, double *, int, double *, int, int, int, int *, int *, int, int, /*@out@ */ double *, /*@out@ */ double *, double *, double *, double *); void bits2bytes (double *, int, unsigned char /*@out@ */ *); void crc16_bytewise (double /*@out@ */ *, unsigned char *, long); int deflate_uncompress (unsigned char *, int, char /*@out@ */ *, int, unsigned char /*@out@ */ *, int *, double /*@out@ */ *); float **matrix (long, long, long, long); int *ivector (long, long); float *fvector (long, long); void channel_decoding (void); void source_decoding (void); void crc8_c (double *, double *, int); void psdmean (float *, float *, int, int); void psdcmean (float *, float *, int, int); struct drmComplex { float re; float im; }; #endif qsstv_8.2.12/qsstv/drmrx/drmpsdframe.cpp000664 001750 001750 00000003515 12440612574 020323 0ustar00jomajoma000000 000000 #include "drmpsdframe.h" #include "ui_drmpsdframe.h" #include #include "drm.h" #include "math.h" #define PSDRANGE 70. #define PSDLOW 0. drmPSDFrame::drmPSDFrame(QWidget *parent) : QFrame(parent), ui(new Ui::drmPSDFrame) { ui->setupUi(this); } drmPSDFrame::~drmPSDFrame() { delete ui; } void drmPSDFrame::paintEvent (QPaintEvent *e) { int i,x1,x2,y1,y2; float y; QPainter qpainter (this); //qpainter.drawRect (contentsRect()); qpainter.setPen (QPen (Qt::blue, 1)); qpainter.drawLine (contentsRect().x()+contentsRect().width()/2, contentsRect().y(), contentsRect().x()+contentsRect().width()/2,contentsRect().y()+contentsRect().height()); qpainter.drawLine (contentsRect().x(), contentsRect().y()+contentsRect().height()/2, contentsRect().x()+contentsRect().width(),contentsRect().y()+contentsRect().height()/2); // draw PSD Info x1=0; y1=contentsRect().height(); for(i=0;iPSDRANGE) y=PSDRANGE; y2=contentsRect().height()-rint((y/PSDRANGE) *(float)contentsRect().height()); x2=(i*contentsRect().width())/(PSDSPAN/4); qpainter.drawLine(x1,y1,x2,y2); x1=x2;y1=y2; } qpainter.setPen (QPen (Qt::red, 1)); x1=0; y1=contentsRect().height(); for(i=0;iPSDRANGE) y=PSDRANGE; y2=contentsRect().height()-rint((y/PSDRANGE) *(float)contentsRect().height()); x2=(i*contentsRect().width())/(PSDSPAN/4); qpainter.drawLine(x1,y1,x2,y2); x1=x2;y1=y2; } QFrame::paintEvent(e); } void drmPSDFrame::setPSD() { for(int i=0;i #define PSDSPAN 512 namespace Ui { class drmPSDFrame; } class drmPSDFrame : public QFrame { Q_OBJECT public: explicit drmPSDFrame(QWidget *parent = 0); ~drmPSDFrame(); void setPSD(); private: Ui::drmPSDFrame *ui; void paintEvent (QPaintEvent *); float psdArray[PSDSPAN]; float psdCArray[PSDSPAN/4]; }; #endif // DRMPSDFRAME_H qsstv_8.2.12/qsstv/drmrx/drmpsdframe.ui000664 001750 001750 00000007720 12440612574 020160 0ustar00jomajoma000000 000000 drmPSDFrame 0 0 390 239 76 76 76 180 180 180 0 0 0 60 60 60 76 76 76 76 76 76 180 180 180 0 0 0 60 60 60 76 76 76 0 0 0 180 180 180 0 0 0 0 0 0 0 0 0 Frame QFrame::Panel QFrame::Sunken 3 qsstv_8.2.12/qsstv/drmrx/drmstatusframe.cpp000664 001750 001750 00000012536 12440612574 021063 0ustar00jomajoma000000 000000 #include "drmstatusframe.h" #include "ui_drmstatusframe.h" #include "drm.h" #include "qsstvglobal.h" #include "drmrx/demodulator.h" #include #include "configparams.h" drmStatusFrame::drmStatusFrame(QWidget *parent) : QFrame(parent), ui(new Ui::drmStatusFrame) { ui->setupUi(this); greenPXM=new QPixmap(40,30); greenPXM->fill(Qt::green); redPXM=new QPixmap(40,30); redPXM->fill(Qt::red); yellowPXM=new QPixmap(40,30); yellowPXM->fill(Qt::yellow); init(); } drmStatusFrame::~drmStatusFrame() { delete ui; } void drmStatusFrame::init() { mode=""; bandwidth=0; interleave=""; protection=""; qam=0; call=""; currentSegment=0; transportID=0; totalSeg=0; rxSeg=0; ui->mscLED->setPixmap(*redPXM); ui->facLED->setPixmap(*redPXM); ui->frameLED->setPixmap(*redPXM); ui->timeLED->setPixmap(*redPXM); } void drmStatusFrame::paintEvent (QPaintEvent *) { int freqOff; ui->modeEdit->setText(mode); ui->bandwidthEdit->setText(QString::number(bandwidth)); ui->interleaveEdit->setText(interleave); ui->protectionEdit->setText(protection); ui->qamEdit->setText(QString::number(qam)); ui->snrEdit->setText(QString::number(WMERFAC,'g',2)+" dB"); freqOff=(int)round(freqOffset-350); ui->offsetEdit->setText(QString::number(freqOff)+" Hz"); // ui->dfsEdit->setText(QString::number(deltaFS,'g',3) + " ppm"); ui->totalSegmentsEdit->setText(QString::number(totalSeg)); ui->blocksReceivedFrame->setMaxBlocks(totalSeg); ui->rxSegmentsEdit->setText(QString::number(rxSeg)); ui->callEdit->setText(call.toUpper()); ui->transportIDEdit->setText(QString::number(transportID)); ui->currentSegmentEdit->setText(QString::number(currentSegment)); ui->blocksReceivedFrame->setBlocks(drmBlockList); } void drmStatusFrame::setStatus() { if(demodulatorPtr->isTimeSync()) { ui->timeLED->setPixmap(*greenPXM); } else { ui->timeLED->setPixmap(*redPXM); ui->facLED->setPixmap(*redPXM); ui->frameLED->setPixmap(*redPXM); ui->mscLED->setPixmap(*redPXM); // update(); return; } currentSegment=currentSegmentNumber; transportID=rxTransportID; totalSeg=bodyTotalSegments; rxSeg=rxSegments; switch(robustness_mode) { case 0: mode="A"; break; case 1: mode="B"; break; case 2: mode="E"; break; default: mode=""; break; } if(callsignValid) { call=drmCallsign; } if(fac_valid==1) { ui->facLED->setPixmap(*greenPXM); } else { ui->facLED->setPixmap(*redPXM); } switch(msc_valid) { case INVALID: ui->mscLED->setPixmap(*redPXM); break; case VALID: ui->mscLED->setPixmap(*greenPXM); break; case ALREADYRECEIVED: ui->mscLED->setPixmap(*yellowPXM); break; } if(demodulatorPtr->isFrameSync()) { ui->frameLED->setPixmap(*greenPXM); } else { ui->frameLED->setPixmap(*redPXM); } if(demodulatorPtr->isTimeSync()) { ui->timeLED->setPixmap(*greenPXM); } else { ui->timeLED->setPixmap(*redPXM); } if(mode=="") return; switch(spectrum_occupancy_new) { case 0: bandwidth=2.3; break; case 1: bandwidth=2.5;; break; default:bandwidth=0; break; } switch (multiplex_description.PL_PartB) { case 0: protection="High"; break; case 1: protection="Low"; break; default: ; break; } switch(interleaver_depth_new) { case 0: interleave="Long"; break; case 1: interleave="Short"; break; default: ; break; } switch(msc_mode_new) { case 0: qam=64; break; case 1: qam=16; break; case 3: qam=4; break; default: qam=0; break; } ui->totalSegmentsEdit->setText(QString::number(bodyTotalSegments)); ui->rxSegmentsEdit->setText(QString::number(rxSegments)); update(); } QString modeToString(uint mode) { QString tmp; tmp+="Mode: "; switch(mode/10000) { case 0: tmp+="A"; break; case 1: tmp+="B"; break; case 2: tmp+="E"; break; default: tmp+="-"; break; } tmp+="\nBW: "; mode-=(mode/10000)*10000; switch(mode/1000) { case 0: tmp+="2.3"; break; case 1: tmp+="2.5";; break; default:tmp+="---"; break; } tmp+="\nProt: "; mode-=(mode/1000)*1000; switch(mode/100) { case 0: tmp+="High"; break; case 1: tmp+="Low"; break; default:tmp+="---" ; break; } tmp+="\nQAM: "; mode-=(mode/100)*100; switch(mode/10) { case 0: tmp+="4"; break; case 1: tmp+="16"; break; case 2: tmp+="64"; break; default: tmp+="--"; break; } return tmp; } QString compactModeToString(uint mode) { QString tmp; switch(mode/10000) { case 0: tmp+="A"; break; case 1: tmp+="B"; break; case 2: tmp+="E"; break; default: tmp+="-"; break; } tmp+="/"; // bandwidth mode-=(mode/10000)*10000; switch(mode/1000) { case 0: tmp+="2.3"; break; case 1: tmp+="2.5";; break; default:tmp+="---"; break; } tmp+="/"; mode-=(mode/1000)*1000; switch(mode/100) { case 0: tmp+="Hi"; break; case 1: tmp+="Lo"; break; default:tmp+="--" ; break; } tmp+="/"; mode-=(mode/100)*100; switch(mode/10) { case 0: tmp+="4"; break; case 1: tmp+="16"; break; case 2: tmp+="64"; break; default: tmp+="--"; break; } tmp+="/"; switch(mode&1) { case 0: tmp+="Long"; break; case 1: tmp+="Short"; break; default:tmp+="--" ; break; } return tmp; } qsstv_8.2.12/qsstv/drmrx/drmstatusframe.h000664 001750 001750 00000001331 12440612574 020517 0ustar00jomajoma000000 000000 #ifndef DRMSTATUSFRAME_H #define DRMSTATUSFRAME_H #include #include class demodulator; namespace Ui { class drmStatusFrame; } class drmStatusFrame : public QFrame { Q_OBJECT public: explicit drmStatusFrame(QWidget *parent = 0); ~drmStatusFrame(); void init(); void setStatus(); private: Ui::drmStatusFrame *ui; void paintEvent (QPaintEvent *); QString mode; float bandwidth; QString interleave; QString protection; int qam; QString call; QPixmap *greenPXM; QPixmap *redPXM; QPixmap *yellowPXM; int currentSegment; int transportID; int totalSeg; int rxSeg; }; QString modeToString(uint mode); QString compactModeToString(uint mode); #endif // DRMSTATUSFRAME_H qsstv_8.2.12/qsstv/drmrx/drmstatusframe.ui000664 001750 001750 00000100567 12440612574 020720 0ustar00jomajoma000000 000000 drmStatusFrame 0 0 415 399 Frame QFrame::StyledPanel QFrame::Raised 2 1 40 0 40 0 40 0 SNR Bandwidth 40 0 Total Segm. RX Sgmnts 40 0 40 0 40 0 40 0 40 0 InterLeave Protection 40 0 40 0 Offset Mode QAM Cur. Sgmnt Transp. ID Callsign 12 75 true Qt::AlignCenter 0 18 QFrame::StyledPanel QFrame::Sunken 3 2 1 8 75 true TIME Qt::AlignCenter 8 75 true FRAME Qt::AlignCenter 8 75 true FAC Qt::AlignCenter 40 0 8 75 true MSC Qt::AlignCenter 50 12 1000 12 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 50 50 50 180 180 180 50 50 50 50 50 50 50 50 50 8 75 false true true QFrame::Panel QFrame::Raised 3 Qt::AlignCenter 50 12 1000 12 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 50 50 50 180 180 180 50 50 50 50 50 50 50 50 50 8 75 false true true QFrame::Panel QFrame::Raised 3 Qt::AlignCenter 50 12 1000 12 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 50 50 50 180 180 180 50 50 50 50 50 50 50 50 50 8 75 false true true QFrame::Panel QFrame::Raised 3 Qt::AlignCenter 50 12 1000 12 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 76 76 76 180 180 180 50 50 50 60 60 60 76 76 76 50 50 50 180 180 180 50 50 50 50 50 50 50 50 50 8 75 false true true QFrame::Panel QFrame::Raised 3 Qt::AlignCenter Qt::Vertical 20 0 blockView QFrame
widgets/blockview.h
1
qsstv_8.2.12/qsstv/drmrx/filter1.cpp000664 001750 001750 00000002043 12440612574 017360 0ustar00jomajoma000000 000000 /* * File filter1.c * * implements filter routine a la MATLAB * for real data in vector sigin[] * * PA0MBO - M.Bos * Date Feb 21st 2009 * * result is stored in y[] * dataLen is number of elements in input (sigin) and mih is length of * the filter vector h[] * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include void drmfilter1(float *sigin, float *out, float *coef, int dataLen, int coefLen) { int i, j; for (i = 0; i < dataLen; i++) { out[i] = 0.0; for (j = 0; ((j <= i) && (j < coefLen)); j++) { out[i] += coef[j] * sigin[i - j]; } } } qsstv_8.2.12/qsstv/drmrx/filter1c.cpp000664 001750 001750 00000002360 12440612574 017525 0ustar00jomajoma000000 000000 /* * File filter1c.c * * implements filter routine a la MATLAB * * PA0MBO - M.Bos * Date Feb 21st 2009 * * input signal is complex and should be stored * real 1 / imag component 2 , real 2, imag2 etc.. * * result is stored in y[] in the same manner (y[] is alsdo complex) * dataLen is number of elements in input (sigin) and coefLen is length of * the filter vector h[] * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include void drmfilter1c(float *sigin, float *y, float *coef, int dataLen, int coefLen) { int i, j; for (i = 0; i < dataLen; i++) { y[i * 2] = 0.0; y[i * 2 + 1] = 0.0; for (j = 0; ((j <= i) && (j < coefLen)); j++) { y[i * 2] += coef[j] * sigin[(i - j) * 2]; y[i * 2 + 1] += coef[j] * sigin[(i - j) * 2 + 1]; } } } qsstv_8.2.12/qsstv/drmrx/fixform.cpp000664 001750 001750 00000002147 12440612574 017471 0ustar00jomajoma000000 000000 #include "fixform.h" #include "ui_fixform.h" #include "drmstatusframe.h" #include "qsstvglobal.h" #include "drmrx/drm.h" #include "configparams.h" fixForm::fixForm(QWidget *parent) : QDialog(parent), ui(new Ui::fixForm) { ui->setupUi(this); } fixForm::~fixForm() { delete ui; } void fixForm::setInfoInternal(int mode, QString fileName, int missing, QByteArray *ba) { common(mode,fileName,missing); // ui->infoTextEdit->appendPlainText("BSR for a picture you send"); ui->previewWidget->openImage(ba); } void fixForm::setInfoExternal(int mode, QString fileName, int missing) { common(mode,fileName,missing); ui->infoTextEdit->appendPlainText("BSR for a picture you received"); ui->previewWidget->openImage(fileName,false,false); } void fixForm::common(int mode,QString fileName,int missing) { ui->filenameLineEdit->setText("Filename: "+fileName+"\n"); if(callsignValid) { ui->infoTextEdit->appendPlainText("From: "+ QString(drmCallsign)); } ui->infoTextEdit->appendPlainText(modeToString(mode)); ui->infoTextEdit->appendPlainText(QString("Requested segments: %1").arg(missing)); } qsstv_8.2.12/qsstv/drmrx/fixform.h000664 001750 001750 00000000711 12440612574 017131 0ustar00jomajoma000000 000000 #ifndef FIXFORM_H #define FIXFORM_H #include namespace Ui { class fixForm; } class fixForm : public QDialog { Q_OBJECT public: explicit fixForm(QWidget *parent = 0); ~fixForm(); void setInfoInternal(int mode, QString fileName, int missing, QByteArray *ba); void setInfoExternal(int mode, QString fileName, int missing); private: Ui::fixForm *ui; void common(int mode, QString fileName, int missing); }; #endif // FIXFORM_H qsstv_8.2.12/qsstv/drmrx/fixform.ui000664 001750 001750 00000007205 12440612574 017324 0ustar00jomajoma000000 000000 fixForm 0 0 501 299 FIX 200 120 200 120 0 18 QFrame::StyledPanel QFrame::Sunken 3 Qt::Horizontal 40 20 Cancel Fix Qt::Horizontal 40 20 blockView QFrame
widgets/blockview.h
1
imageViewer QWidget
widgets/imageviewer.h
1
cancelPushButton clicked() fixForm reject() 205 275 250 149 fixPushButton clicked() fixForm accept() 296 275 250 149
qsstv_8.2.12/qsstv/drmrx/getfoffsint.cpp000664 001750 001750 00000006472 12440612574 020342 0ustar00jomajoma000000 000000 /* * * file getfoffsint.c * * implements get_frequency_offset_integer function * from diorama MATLAB code * * Author M.Bos - PA0MBO * * Date Feb 21st 2009 * * output: freq_offset_integer (float) * inputs: symbol_buffer (filled bu getofdm), N_symbols, K_dc, * K_modulo, Tu * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #define PI (4.0*atan(1.0)) struct cmplxnmbr { float re; float im; }; float getfoffsint(float *symbolbuf, int N_symbols, int K_dc, int K_modulo, int Tu) { int i, j; struct cmplxnmbr S[288][30]; /* Tu x 30 ? pa0mbo? */ float dS_sum[288 * 2]; float tmp1, tmp2; int k_pilot1, k_pilot2, k_pilot3; float abs_dS_sum[288], pilot_indicator[288]; float dummy, freq_offset_integer; int K_dc_offset; /* reshape symbolbuf to matrix S */ for (i = 0; i < N_symbols; i++) { for (j = 0; j < K_modulo; j++) { (S[j][i]).re = symbolbuf[(j + i * K_modulo) * 2]; (S[j][i]).im = symbolbuf[(j + i * K_modulo) * 2 + 1]; } } /* now accumulate phase diffs all carriers */ for (i = 0; i < Tu; i++) { dS_sum[i * 2] = 0.0; dS_sum[i * 2 + 1] = 0.0; } for (i = 1; i < N_symbols; i++) { for (j = 0; j < Tu; j++) { tmp1 = (S[j][i - 1]).re * (S[j][i]).re + /* real ac + bd */ (S[j][i - 1]).im * (S[j][i]).im; tmp2 = (S[j][i - 1]).im * (S[j][i]).re - /* imag. bc - ad */ (S[j][i - 1]).re * (S[j][i]).im; dS_sum[j * 2] += cos(atan2(tmp2, tmp1)); dS_sum[j * 2 + 1] += sin(atan2(tmp2, tmp1)); } } /* detect pilots */ k_pilot1 = (int) ceil((float) (9 * Tu / 288)); k_pilot2 = (int) ceil((float) (27 * Tu / 288)); k_pilot3 = (int) ceil((float) (36 * Tu / 288)); for (i = 0; i < Tu; i++) { abs_dS_sum[i] = (float) sqrt(dS_sum[i * 2] * dS_sum[i * 2] + dS_sum[i * 2 + 1] * dS_sum[i * 2 + 1]); } for (i = 0; i < Tu - k_pilot1; i++) { pilot_indicator[i] = abs_dS_sum[k_pilot1 + i]; } for (i = 0; i < k_pilot1; i++) { pilot_indicator[i + Tu - k_pilot1] = abs_dS_sum[i]; } for (i = 0; i < Tu - k_pilot2; i++) { pilot_indicator[i] += abs_dS_sum[k_pilot2 + i]; } for (i = 0; i < k_pilot2; i++) { pilot_indicator[i + Tu - k_pilot2] += abs_dS_sum[i]; } for (i = 0; i < Tu - k_pilot3; i++) { pilot_indicator[i] += abs_dS_sum[k_pilot3 + i]; } for (i = 0; i < k_pilot3; i++) { pilot_indicator[i + Tu - k_pilot3] += abs_dS_sum[i]; } /* Now find max pilot_indicator and index */ dummy = -1.0E20; K_dc_offset = 0; for (i = 0; i < Tu; i++) { if (pilot_indicator[i] > dummy) { dummy = pilot_indicator[i]; K_dc_offset = i; } } K_dc_offset = ((K_dc_offset - K_dc + Tu / 2 + Tu) % Tu) - Tu / 2; freq_offset_integer = (float) (2 * PI * K_dc_offset); return (freq_offset_integer); } qsstv_8.2.12/qsstv/drmrx/getmode.cpp000664 001750 001750 00000024055 12440612574 017445 0ustar00jomajoma000000 000000 /* * File getmode.c * * Author M.Bos - PA0MBO * Date Feb 21st 2009 * * routine to determine robustness mode * of baseband drm signal (complex) * in "in" real and imag components * stored alternatively in sequence * * returns number of the mode A=0, B=1, etc... * input param. n is number of samples in rsbuf * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include #include "structtemplates.h" #include "drmproto.h" #include "drmdefs.h" #include "qsstvglobal.h" #include "utils/supportfunctions.h" static /*@only@ */ float *in_, *abs_in_, *abs_in_in_; static /*@only@ */ float *conv_in_, *conv_abs_in_in_; static bool initDone=false; void initGetmode(int n) { if(initDone) return; initDone=true; /* create and initialize arrays */ in_ =(float *) malloc((n - Tu_D) * 2 * sizeof(float)); /* complex data */ if (in_ == NULL) { printf("mem alloc problem in getmode \n"); exit(EXIT_FAILURE); } conv_in_ = (float *)malloc((n - Tu_D) * 2 * sizeof(float)); /* complex */ if (conv_in_ == NULL) { printf("mem alloc problem in getmode \n"); exit(EXIT_FAILURE); } abs_in_ = (float *)malloc(n * sizeof(float)); if (abs_in_ == NULL) { printf("mem alloc problem in getmode \n"); exit(EXIT_FAILURE); } abs_in_in_ = (float *)malloc((n - Tu_D) * sizeof(float)); if (abs_in_in_ == NULL) { printf("mem alloc problem in getmode \n"); exit(EXIT_FAILURE); } conv_abs_in_in_ = (float *)malloc((n - Tu_D) * sizeof(float)); if (conv_abs_in_in_ == NULL) { printf("mem alloc problem in getmode \n"); exit(EXIT_FAILURE); } return; } /* end initializations */ void getmode(float *input, int n, smode_info * result) { float EPSILON = 1.0E-10; float SNR_mode_det = (float) (exp(15.0 * log(10) / 10.0)); float rho; int Ts_list[4] = { Ts_A, Ts_B, Ts_C, Ts_D }; int Tu_list[4] = { Tu_A, Tu_B, Tu_C, Tu_D }; float max_abs_gamma_rel_list[] = { 0.0, 0.0, 0.0, 0.0 }; int theta_list[] = { 0, 0, 0, 0 }; float epsilon_ML_list[] = { 0.0, 0.0, 0.0, 0.0 }; int N_symbols_mode_det, Ts, Tu, Tg, t_smp; int mode, i, j, theta, maxOK; float max_abs_gamma_rel, tmpmax, epsilon_ML; // float frequency_offset_fract; int b[20], time_offset_mean; float sumx, sumy, sumxx, sumxy, slope, boffs; // float a[20]; float gamma[2 * Ts_A], Phi[Ts_A]; float my_rect[Ts_D - Tu_D]; rho = SNR_mode_det / (SNR_mode_det + 1); N_symbols_mode_det = ((n + 1) / Ts_A) - 1; for (mode = 0; mode < 3; mode++) // ON4QZ 3 was 4 { Ts = Ts_list[mode]; Tu = Tu_list[mode]; Tg = Ts - Tu; t_smp = 0; /* initialize arrays with zero's */ for (i = 0; i < Ts; i++) { gamma[i * 2] = 0.0; gamma[i * 2 + 1] = 0.0; Phi[i] = 0.0; } for (i = 0; i < n - Tu; i++) /* complex mult */ { in_[2 * i] = input[2 * i] * input[(i + Tu) * 2] + input[2 * i + 1] * input[(i + Tu) * 2 +1]; in_[2 * i + 1] = -input[2 * i] * input[(i + Tu) * 2 + 1] + input[2 * i + 1] * input[(i + Tu) * 2]; } // arrayDump("gM1",input,16,true); my_rect[0] = 0.5; // ON4QZ for (i = 1; i < Tg; i++) { my_rect[i] = 1.0; } // my_rect[Tg-1] = 0.5; // ON4QZ drmfilter1c(in_, conv_in_, my_rect, n - Tu, Tg); for (i = 0; i < n; i++) { abs_in_[i] = input[i * 2] * input[i * 2] + input[i * 2 + 1] * input[i * 2 + 1]; } for (i = 0; i < n - Tu; i++) { abs_in_in_[i] = abs_in_[i] + abs_in_[i + Tu]; } drmfilter1(abs_in_in_, conv_abs_in_in_, my_rect, n - Tu, Tg); for (j = 0; j < N_symbols_mode_det; j++) { for (i = 0; i < Ts; i++) { gamma[i * 2] = gamma[i * 2] + conv_in_[(t_smp + Tg + i - 1) * 2]; /* pa0mbo -1 ios nieuw */ gamma[i * 2 + 1] = gamma[i * 2 + 1] + conv_in_[(t_smp + Tg + i - 1) * 2 + 1]; Phi[i] = Phi[i] + (float) (0.5 * (EPSILON + conv_abs_in_in_[t_smp + Tg + i - 1])); } t_smp += Ts; } /* detmn max and index in abs(gamma .. rho*Phi) */ theta = 0; max_abs_gamma_rel = -1.0E20; /* debugging printf("==== mode %d === gamma\n",mode); */ for (i = 0; i < Ts; i++) { tmpmax = (float) sqrt(gamma[2 * i] * gamma[2 * i] + gamma[2 * i + 1] * gamma[2 * i + 1]); /* printf("%g\n", tmpmax); */ tmpmax -= rho * Phi[i]; if (tmpmax > max_abs_gamma_rel) { max_abs_gamma_rel = tmpmax; theta = i; } } // arrayDump("gM2",gamma,Ts*2,true); /* printf("===============\n"); */ max_abs_gamma_rel = (float) sqrt(gamma[theta * 2] * gamma[theta * 2] + gamma[theta * 2 + 1] * gamma[theta * 2 + 1]) / (rho * Phi[theta]); epsilon_ML = (float) atan2(gamma[2 * theta], gamma[2 * theta + 1]); max_abs_gamma_rel_list[mode] = max_abs_gamma_rel; theta_list[mode] = theta; epsilon_ML_list[mode] = epsilon_ML; } /* debugging printf("max gamma list %g %g %g %g \n", max_abs_gamma_rel_list[0], max_abs_gamma_rel_list[1], max_abs_gamma_rel_list[2], max_abs_gamma_rel_list[3]); printf("theta list %d %d %d %d \n", theta_list[0], theta_list[1], theta_list[2], theta_list[3]); printf("epsilon ML list %g %g %g %g \n", epsilon_ML_list[0], epsilon_ML_list[1], epsilon_ML_list[2], epsilon_ML_list[3]); end debug info */ /* now decide for particular mode */ max_abs_gamma_rel = -1.0E20; for (i = 0; i < 4; i++) { if (max_abs_gamma_rel_list[i] > max_abs_gamma_rel) { max_abs_gamma_rel = max_abs_gamma_rel_list[i]; mode = i; } } // < 0.6) // was 0.6 { for (i = 0; i < 3; i++) //ON4QZ 3 was 4 { if ((i != mode) && (max_abs_gamma_rel_list[i] > 0.6)) { maxOK = 0; } } } else { maxOK = 0; } if (maxOK == 0) { result->mode_indx = 99; result->time_offset = 0.0; result->sample_rate_offset = 0.0; result->freq_offset_fract = 0.0; return; } else { addToLog("max mode ok",LOGDRMDEMOD); Ts = Ts_list[mode]; Tu = Tu_list[mode]; Tg = Ts - Tu; time_offset_mean = theta_list[mode]; /* pa0mbo checked +1 removed on Dec 22nd 2006 */ // frequency_offset_fract = epsilon_ML_list[mode]; /* now recalculate several vars with the established mode */ for (i = 0; i < n - Tu; i++) { in_[2 * i] = input[2 * i] * input[(i + Tu) * 2] + input[2 * i + 1] * input[(i + Tu) * 2 + 1]; in_[2 * i + 1] = -input[2 * i] * input[(i + Tu) * 2 + 1] + input[2 * i + 1] * input[(i + Tu) * 2]; } my_rect[0] = 0.5; for (i = 1; i < Tg; i++) { my_rect[i] = 1.0; } my_rect[Tg - 1] = 0.5; drmfilter1c(in_, conv_in_, my_rect, n - Tu, Tg); for (i = 0; i < n; i++) { abs_in_[i] = input[i * 2] * input[i * 2] + input[i * 2 + 1] * input[i * 2 + 1]; } for (i = 0; i < n - Tu; i++) { abs_in_in_[i] = abs_in_[i] + abs_in_[i + Tu]; } drmfilter1(abs_in_in_, conv_abs_in_in_, my_rect, n - Tu, Tg); t_smp = Tg + time_offset_mean + Ts / 2; for (j = 0; j < (N_symbols_mode_det - 2); j++) { max_abs_gamma_rel = -1.0E20; for (i = 0; i < Ts; i++) { gamma[i * 2] = conv_in_[(t_smp + i) * 2]; gamma[i * 2 + 1] = conv_in_[(t_smp + i) * 2 + 1]; Phi[i] = (float) (0.5 * (EPSILON + conv_abs_in_in_[t_smp + i])); /* detmn max and its indx */ tmpmax = (float) sqrt(gamma[2 * i] * gamma[2 * i] + gamma[2 * i + 1] * gamma[2 * i + 1]) - rho * Phi[i]; if (tmpmax > max_abs_gamma_rel) { max_abs_gamma_rel = tmpmax; // a[j] = tmpmax; b[j] = i; } } t_smp += Ts; } /* Now least squares to 0...N_symbols_mode_det-3 and b[0] .. */ sumx = 0.0; sumy = 0.0; sumxx = 0.0; sumxy = 0.0; for (i = 0; i < N_symbols_mode_det - 2; i++) { sumx += (float) i; sumy += (float) b[i]; sumxx += (float) i *(float) i; sumxy += (float) i *(float) b[i]; } slope = (float) (((N_symbols_mode_det - 2) * sumxy - sumx * sumy) / ((N_symbols_mode_det - 2) * sumxx - sumx * sumx)); boffs = (float) ((sumy * sumxx - sumx * sumxy) / ((N_symbols_mode_det - 2) * sumxx - sumx * sumx)); } /* printf("in getmode N_symbols_mode_det %d \n", N_symbols_mode_det); printf("mode is %d toffs %g samplroffs %g f_offs_fract %g\n", mode, fmod((boffs + Ts / 2 + time_offset_mean - 1), (float) Ts), slope / ((float) Ts), epsilon_ML_list[mode]); */ /* pa0mbo todo reliability check */ result->mode_indx = mode; result->time_offset = fmodf((boffs + Ts / 2 + time_offset_mean - 1), (float) Ts); /* fp rest pa0mbo was -2 */ result->sample_rate_offset = slope / ((float) Ts); result->freq_offset_fract = epsilon_ML_list[mode]; //logfile->addToAux(QString("%1 %2 %3 %4").arg( mode).arg(result->time_offset).arg(result->sample_rate_offset).arg(result->freq_offset_fract)); } qsstv_8.2.12/qsstv/drmrx/getofdm.cpp000664 001750 001750 00000031214 12440612574 017441 0ustar00jomajoma000000 000000 /* * File getofdm.c * * Author PA0MBO - M.BOS * DATE Feb 21st 2009 * * implements more or less the get_ofdm_symbol * MATLAB routine from diorama-1.1.1 * * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include "drmproto.h" #include "qsstvglobal.h" #define PI (atan(1.0)*4.0) int getofdm( /*@null@ */ float *rs, float time_offset_fractional_init, float freq_offset_init, float delta_time_offset_I_init, int Ts, int Tu, /*@null@ */ float Zi[], /*@null@ */ float *out, int init, int TIME_SYNC_ENABLE, int FREQ_SYNC_ENABLE) { float EPSILON = 1.0E-10; float max_theta = 10.0; // float max_time_offset_ctrl = 10.0; // float max_delta_time_offset = 2.0; float kP_small_timing_controller = 0.01; float kP_large_timing_controller = 0.01; float threshold_timing_small_large = 2.0; float kI_timing_controller = 0.00020; float kP_small_freq_controller = 0.750; float threshold_freq_small_large = 0.75; float kI_freq_controller = 0.0008; int Tg, Tgh; float phi_freq_correction_last; float delta_time_offset_I; float delta_time_offset_P; float dfreq_offset_I; float freq_offset, time_offset_fractional; int i; float temp1[] = { 0.0, 0.0 }, temp2, temp3, temp4; float temp[] = { 0.0, 0.0 }; float temp5[] = { 0.0, 0.0 }; float temp6, temp7; float temp8[] = { 0.0, 0.0 }; float temp9, temp10; float theta_plus, theta_minus, delta_theta; float time_offset_ctrl; float delta_time_offset; int delta_time_offset_integer; float epsilon_ML, freq_offset_ctrl, dfreq_offset_P; float kP_large_freq_controller, dfreq_offset; float tmptheta, term1; static float *exp_temp; static float *out1; static drmComplex s[288], S[288]; /* 288 = max Tu */ static fftwf_plan p = NULL; if (init == 1) { /* malloc space for arrays */ if ((exp_temp = (float *)malloc(Tu * 2 * sizeof(float))) == NULL) { printf("cannot malloc space for exp_temp in get_ofdm_symbol\n"); exit(EXIT_FAILURE); } if ((out1 = (float *)malloc(Tu * 2 * sizeof(float))) == NULL) { printf("cannot malloc space for out1 in get_ofdm_symbol\n"); exit(EXIT_FAILURE); } if (p != NULL) { fftwf_destroy_plan(p); } p = fftwf_plan_dft_1d(Tu,(fftwf_complex *)s,(fftwf_complex *)S,FFTW_FORWARD, FFTW_ESTIMATE); return (0); } else { /* fixed parameters */ EPSILON = 1.0E-10; max_theta = 5.0; // max_time_offset_ctrl = 10.0; // max_delta_time_offset = 2.0; kP_small_timing_controller = 0.01; kP_large_timing_controller = 0.01; threshold_timing_small_large = 2.0; kI_timing_controller = 0.00005; kP_small_freq_controller = 0.05; kP_large_freq_controller = 0.75; threshold_freq_small_large = 0.5; kI_freq_controller = 0.0008; Tg = Ts - Tu; Tgh = (int) floor(Tg / 2 + 0.5); if (Zi[0] < 0.0) { phi_freq_correction_last = 0.0; delta_time_offset_I = delta_time_offset_I_init; dfreq_offset_I = 0.0; freq_offset = freq_offset_init; time_offset_fractional = time_offset_fractional_init; } else { phi_freq_correction_last = Zi[1]; delta_time_offset_I = Zi[2]; dfreq_offset_I = Zi[3]; freq_offset = Zi[4]; time_offset_fractional = Zi[5]; } if (TIME_SYNC_ENABLE == 1) { temp1[0] = 0.0; temp1[1] = 0.0; temp2 = 0.0; temp3 = 0.0; temp5[0] = 0.0; temp5[1] = 0.0; temp6 = 0.0; temp7 = 0.0; temp8[0] = 0.0; temp8[1] = 0.0; temp9 = 0.0; temp10 = 0.0; for (i = 0; i < Tg + 2; i++) { // logfile->addToAux(QString("tm1 %1 %2 %3 %4 %5").arg(rs[i * 2] ).arg(rs[(Tu + i) * 2]).arg(rs[i * 2 + 1]).arg(rs[(Tu + i) * 2 + 1]).arg(temp1[0])); temp1[0] += rs[i * 2] * rs[(Tu + i) * 2] + rs[i * 2 + 1] * rs[(Tu + i) * 2 + 1]; /* real part */ temp1[1] += -rs[i * 2] * rs[(Tu + i) * 2 + 1] + rs[i * 2 + 1] * rs[(Tu + i) * 2]; /* imag part */ temp2 += rs[i * 2] * rs[i * 2] + rs[i * 2 + 1] * rs[i * 2 + 1]; temp3 += rs[(i + Tu) * 2] * rs[(i + Tu) * 2] + rs[(i + Tu) * 2 + 1] * rs[(i + Tu) * 2 + 1]; } temp4 = (float) (EPSILON + 0.5 * (temp2 + temp3)); // logfile->addToAux(QString("tmp %1 %2 %3 %4 %5").arg(temp1[0]).arg(temp1[1]).arg(temp2).arg(temp3).arg(temp4)); /* time offset measurement : theta */ for (i = 0; i < 5; i++) { temp5[0] += rs[i * 2] * rs[(Tu + i) * 2] + rs[i * 2 + 1] * rs[(Tu + i) * 2 + 1]; /* 1-5 * Tu_1_5 */ temp5[1] += -rs[i * 2] * rs[(Tu + i) * 2 + 1] + rs[i * 2 +1] * rs[(Tu + i) * 2]; temp6 += rs[i * 2] * rs[i * 2] + rs[i * 2 + 1] * rs[i * 2 + 1]; /* 1-5 * 1-5' */ temp7 += rs[(i + Tu) * 2] * rs[(i + Tu) * 2] + rs[(i + Tu) * 2 + 1] * rs[(i + Tu) * 2 + 1]; /* Tu_1_5 * Tu_1_5' */ /* pa0mbo check for OK */ temp8[0] += rs[(i + Tg - 3) * 2] * rs[(i + Tu + Tg - 3) * 2] + rs[(i + Tg - 3) * 2 + 1] * rs[(i + Tu + Tg - 3) * 2 + 1]; /* Tg -2 +2 * Tg + Tu -2 +2 */ temp8[1] += -rs[(i + Tg - 3) * 2] * rs[(i + Tu + Tg - 3) * 2 + 1] + rs[(i + Tg - 3) * 2 + 1] + rs[(i + Tu + Tg - 3) * 2]; temp9 += rs[(i + Tg - 3) * 2] * rs[(i + Tg - 3) * 2] + rs[(i + Tg - 3) * 2 + 1] * rs[(i + Tg - 3) * 2 + 1]; /* Tg-2+2 * Tg-2+2 */ temp10 += rs[(i + Tg + Tu - 3) * 2] * rs[(i + Tg + Tu - 3) * 2] + rs[(i + Tg + Tu - 3) * 2 + 1] * rs[(i + Tg + Tu - 3) * 2 + 1]; /* TG+Tu-2+2 * Tg+Tu-2+2 */ } theta_plus = (float) sqrt((temp1[0] - temp5[0]) * (temp1[0] - temp5[0]) + (temp1[1] - temp5[1]) * (temp1[1] - temp5[1])); theta_plus -= (0.5 * (-temp6 - temp7)); theta_minus = (float) sqrt((temp1[0] - temp8[0]) * (temp1[0] - temp8[0]) + (temp1[1] - temp8[1]) * (temp1[1] - temp8[1])); theta_minus -= (0.5 * (temp9 - temp10)); delta_theta = (theta_plus - theta_minus) * Tgh / temp4; /* now limit the delta_theta value */ if (delta_theta < -max_theta) delta_theta = -max_theta; if (delta_theta > max_theta) delta_theta = max_theta; /* P-I controller for theta */ time_offset_ctrl = delta_theta - time_offset_fractional; delta_time_offset_I += kI_timing_controller * time_offset_ctrl; delta_time_offset_P = kP_large_timing_controller * time_offset_ctrl + threshold_timing_small_large * (kP_small_timing_controller -kP_large_timing_controller) * tanh(time_offset_ctrl / threshold_timing_small_large); delta_time_offset = delta_time_offset_P + delta_time_offset_I + time_offset_fractional; delta_time_offset_integer = (int) floor(delta_time_offset + 0.5); // logfile->addToAux(QString("dt %1 %2 %3 %4 %5").arg(time_offset_ctrl).arg(delta_time_offset_I).arg(delta_time_offset_P).arg(delta_time_offset).arg(delta_time_offset_integer)); /* now limit delta_time_offset_integer */ if (delta_time_offset_integer < -1) delta_time_offset_integer = -1; if (delta_time_offset_integer > 1) delta_time_offset_integer = 1; time_offset_fractional = delta_time_offset - delta_time_offset_integer; /* printf("delta_time_offset_integer as used in phi_freq_corr %d phifcl %g \n", delta_time_offset_integer, phi_freq_correction_last); */ phi_freq_correction_last += (delta_time_offset_integer / Tu) * freq_offset; } else { delta_time_offset_integer = 0; time_offset_fractional = 0.0; } /* printf("in getofdm delta_time_offset_integer is %d time_offs_fract %g\n", delta_time_offset_integer, time_offset_fractional); */ if (FREQ_SYNC_ENABLE == 1) { temp[0] = 0.0; temp[1] = 0.0; for (i = 0; i < Tg; i++) { temp[0] += rs[(i + 1 + delta_time_offset_integer) * 2] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2] + rs[(i + 1 + delta_time_offset_integer) * 2 + 1] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2 + 1]; temp[1] += rs[(i + 1 + delta_time_offset_integer) * 2 + 1] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2] - rs[(i + 1 + delta_time_offset_integer) * 2] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2 + 1]; } epsilon_ML = (float) (atan2(temp[1], temp[0])); /* filter epsilon_ML */ freq_offset_ctrl = fmodf(epsilon_ML - freq_offset + PI + 100.0 * PI, 2 * PI) - PI; dfreq_offset_I += kI_freq_controller * freq_offset_ctrl; dfreq_offset_P = kP_large_freq_controller * freq_offset_ctrl + threshold_freq_small_large * (kP_small_freq_controller - kP_large_freq_controller) * tanh(freq_offset_ctrl / threshold_freq_small_large); dfreq_offset = dfreq_offset_P + dfreq_offset_I; freq_offset += dfreq_offset; } else { /* freq_offset =0.0 */ } /* printf("in getofdm freq_offset = %g\n", freq_offset); */ /* get symbol and correct frequency */ for (i = 0; i < Tu; i++) { tmptheta = (freq_offset / Tu) * i + phi_freq_correction_last; exp_temp[i * 2] = (float) cos(tmptheta); exp_temp[i * 2 + 1] = (float) sin(tmptheta); } for (i = 0; i < Tu; i++) { (s[i]).re = rs[(1 + delta_time_offset_integer + Tgh + i) * 2] * exp_temp[i * 2] - rs[(1 + delta_time_offset_integer + Tgh + i) * 2 + 1] * exp_temp[i * 2 + 1]; (s[i]).im = rs[(1 + delta_time_offset_integer + Tgh + i) * 2] * exp_temp[i * 2 + 1] + rs[(1 + delta_time_offset_integer + Tgh + i) * 2 + 1] * exp_temp[i * 2]; } phi_freq_correction_last = (float) fmod(phi_freq_correction_last + (float) Ts / (float) Tu * freq_offset, (float)(2.0 * PI)); /* Now do fft and output symbol */ fftwf_execute(p); for (i = 0; i <= Tu / 2; i++) { term1 = (float) (i * 2.0 * PI * (Tgh + time_offset_fractional) / Tu); /* Euler */ exp_temp[i * 2] = (float) cos(term1); exp_temp[i * 2 + 1] = (float) sin(term1); } /* now calc out */ for (i = 0; i < Tu / 2; i++) { out1[i * 2] = (float) (((S[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2] + ((S[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2 + 1]); /* real = ac+bd */ out1[i * 2 + 1] = (float) (((S[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2] - ((S[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2 + 1]); /* imag bc -ad */ } /* Now flip out1 to out */ for (i = 0; i < Tu / 2; i++) { out[i * 2] = out1[(Tu / 2 - 1 - i) * 2]; out[i * 2 + 1] = out1[(Tu / 2 - i - 1) * 2 + 1]; out[(Tu / 2 + i) * 2] = (float) (((S[i]).re) * exp_temp[i * 2] - ((S[i]).im) * exp_temp[i * 2 + 1]); out[(Tu / 2 + i) * 2 + 1] = (float) (((S[i]).im) * exp_temp[i * 2] + ((S[i]).re) * exp_temp[i * 2 + 1]); } Zi[0] = 1.0; Zi[1] = phi_freq_correction_last; Zi[2] = delta_time_offset_I; Zi[3] = dfreq_offset_I; Zi[4] = freq_offset; Zi[5] = time_offset_fractional; return (delta_time_offset_integer); } } qsstv_8.2.12/qsstv/drmrx/getofdmsync.cpp000664 001750 001750 00000027371 12440612574 020347 0ustar00jomajoma000000 000000 /* * File getofdmsync.c * * Author PA0MBO - M.BOS * DATE Feb 21st 2009 * * implements more or less the get_ofdm_symbol_sync * MATLAB routine from diorama-1.1.1 * * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include "drmproto.h" #include "qsstvglobal.h" #include "utils/supportfunctions.h" extern int FREQ_SYNC_ENABLE; #define PI (atan(1.0)*4.0) void filter1(float *, float *, float *, int, int); int getofdmsync( /*@null@ */ float *rs, int Ts, int Tu, /*@null@ */ float *H, int lH, float delta_freq_offset, /*@null@ */ float *Zi, /*@null@ */ float *out, int init, int TIME_SYNC_ENABLE, int FREQ_SYNC_ENABLE) { static int Tg, Tgh; static int Tc; static int Tgs, Tgsh; static float kP_small_timing_controller = 0.0005; static float kP_large_timing_controller = 0.003; /* pa0mbo was 0.01 */ static float threshold_timing_small_large = 2.0; /* was 2.0 */ static float kI_timing_controller = 0.000020; /* was 0.00005 */ int max_delta_theta; int max_delta_time_offset_integer = 3; int max_symbol_position_offset; static drmComplex s[512], S[512]; static drmComplex s1[512], S1[512]; static fftwf_plan p1, p2; float h_absq[512]; /* 2 x max el */ static float sinfilter[256]; /* too long */ float h_absq_filtered[512]; float dummy; float delta_theta, delta_theta_tmp; int dftmp, symbol_position_offset, spotmp; float freq_offset_ctrl; static float /*@only@ */ *exp_temp; static float /*@only@ */ *out1; int i; float kP_freq_controller; // float *pinput; float time_offset_ctrl; float delta_time_offset_P, delta_time_offset; int delta_time_offset_integer; float tmptheta, term1; int indexin; float time_offset_fractional, freq_offset; float delta_time_offset_I, phi_freq_correction_last; /* pa0mbo if-part checken 16 april 2007 */ if (init == 1) { Tg = Ts - Tu; Tgh = (int) floor(Tg / 2 + 0.5); Tc = (int) pow(2, ceil(log((double) lH) / log(2.0))); Tgs = (int) floor((float) Tg / (float) Tu * (float) Tc); Tgsh = (int) floor((float) Tg / (float) Tu / 2.0 * (float) Tc); /* printf("Tg %d, Tgh %d, Tc %d,Tu %d, Tgs %d, Tgsh %d\n", Tg, Tgh, Tc, Tu, Tgs, Tgsh); */ /* malloc space for arrays */ if ((exp_temp = (float *)malloc((Tu * 2 + 2) * sizeof(float))) == NULL) { printf("cannot malloc space for exp_temp in get_ofdm_symbol\n"); exit(EXIT_FAILURE); } if ((out1 = (float *)malloc(Tu * 2 * sizeof(float))) == NULL) { printf("cannot malloc space for out1 in get_ofdm_symbol\n"); exit(EXIT_FAILURE); } if (p1 != NULL) fftwf_destroy_plan(p1); if (p2 != NULL) fftwf_destroy_plan(p2); p1 = fftwf_plan_dft_1d(Tc,(fftwf_complex *)s,(fftwf_complex *)S,FFTW_FORWARD, FFTW_PATIENT); p2 = fftwf_plan_dft_1d(Tu,(fftwf_complex *)s1,(fftwf_complex *)S1, FFTW_FORWARD, FFTW_PATIENT); /* printf("xxxx sinfilter\n"); */ for (i = 0; i < Tgs; i++) { sinfilter[i] = (float) pow(sin((float) (i + 1.0) / (float) (Tgs + 1.0) * PI), 0.001); } return (0); } else { /* fixed parameters */ Tg = Ts - Tu; Tgh = (int) floor(Tg / 2 + 0.5); Tc = (int) pow(2, ceil(log((double) lH) / log(2.0))); Tgs = (int) floor((float) Tg / (float) Tu * (float) Tc); Tgsh = (int) floor((float) Tg / (float) Tu / 2.0 * (float) Tc); kP_small_timing_controller = 0.001; /* pa0mbo was 0.005 */ kP_large_timing_controller = 0.001; /* pa0mbo was 0.01 */ threshold_timing_small_large = (float) Tgh; kI_timing_controller = 2E-5; /* pa0mbo was 0.000005 */ max_delta_theta = Tgh; max_delta_time_offset_integer = 3; max_symbol_position_offset = Tgh - max_delta_time_offset_integer; kP_freq_controller = 0.01; /* pa0mbo was 0.01 */ phi_freq_correction_last = Zi[1]; delta_time_offset_I = Zi[2]; freq_offset = Zi[4]; time_offset_fractional = Zi[5]; /* debugging */ addToLog(QString("ofdmsync: dfo= %1 tof=%2 fofs= %3 dtoI = %4 phicl = %5") .arg(delta_freq_offset).arg(time_offset_fractional).arg(freq_offset) .arg(delta_time_offset_I).arg(phi_freq_correction_last),LOGDRMDEMOD); if (TIME_SYNC_ENABLE == 1) { /* estimate time offset */ /* first copy H data to s buffer that is destroyed by fft */ // pinput = H; for (i = 0; i < lH; i++) { s[i].re = H[i * 2]; s[i].im = H[i * 2 + 1]; } /* zero fill to power of 2 elements */ for (i = lH; i < Tc; i++) { s[i].re = 0.0; s[i].im = 0.0; } fftwf_execute(p1); /* do complex fft */ /* printf("xxx h_absq\n"); */ for (i = 0; i < Tc; i++) { h_absq[i] = (float) (S[i].re * S[i].re + S[i].im * S[i].im); h_absq[i + Tc] = (float) (S[i].re * S[i].re + S[i].im * S[i].im); /* needed 2 times */ /* printf(" %g\n", h_absq[i]); */ } drmfilter1(h_absq, h_absq_filtered, sinfilter, 2 * Tc, Tgs); /* debugging printf("xxx filter h_abs \n"); for (i=0; i < 2*Tc ; i++) printf("%g \n", h_absq_filtered[i]); printf("ooooo\n"); */ /* now determine max and position */ dummy = -1.0E30; delta_theta = 0.0; for (i = 0; i < 2 * Tc; i++) { if (h_absq_filtered[i] > dummy) { dummy = h_absq_filtered[i]; delta_theta = (float) i; } } /* debugging printf("ofdmsync: dummy= %g delta_theta=%g\n", dummy, delta_theta); */ delta_theta = (float) (((((Tc + Tgsh - (int) delta_theta + (int) (Tc * 1.5)) % Tc) - Tc / 2) * Tu) / (float) Tc); /* printf("delta_theta rescaled %g\n", delta_theta); */ if (delta_theta >= (float) max_delta_theta) delta_theta_tmp = (float) max_delta_theta; else delta_theta_tmp = delta_theta; if (delta_theta_tmp > (float) -max_delta_theta) delta_theta = delta_theta_tmp; else delta_theta = (float) -max_delta_theta; /* filter theta: P-I controller */ time_offset_ctrl = delta_theta - time_offset_fractional; delta_time_offset_I += kI_timing_controller * time_offset_ctrl; delta_time_offset_P = kP_large_timing_controller * time_offset_ctrl + threshold_timing_small_large * (kP_small_timing_controller - kP_large_timing_controller) * tanhf(time_offset_ctrl / threshold_timing_small_large); delta_time_offset = delta_time_offset_P + delta_time_offset_I + time_offset_fractional; delta_time_offset_integer = (int) floor(delta_time_offset + 0.5); if (delta_time_offset_integer > -max_delta_time_offset_integer) dftmp = delta_time_offset_integer; else dftmp = -max_delta_time_offset_integer; if (dftmp > max_delta_time_offset_integer) delta_time_offset_integer = max_delta_time_offset_integer; else delta_time_offset_integer = dftmp; /* only +/- one symbol */ time_offset_fractional = delta_time_offset - delta_time_offset_integer; /* debugging printf("delta_t_offs %g delta_t_int %d time_offs_fract %g \n", delta_time_offset, delta_time_offset_integer, time_offset_fractional); */ /* get best time window */ symbol_position_offset = (int) floor(delta_theta - delta_time_offset_integer + 0.5); if (symbol_position_offset > -max_symbol_position_offset) spotmp = symbol_position_offset; else spotmp = -max_symbol_position_offset; if (spotmp < max_symbol_position_offset) symbol_position_offset = spotmp; else symbol_position_offset = max_symbol_position_offset; /* do integer time offset correction and comp phase shift */ phi_freq_correction_last += ((float) delta_time_offset_integer / Tu) * freq_offset; } else { delta_time_offset_integer = 0; time_offset_fractional = 0; symbol_position_offset = 0; } if (FREQ_SYNC_ENABLE == 1) { /* frequency offset estimation */ freq_offset_ctrl = delta_freq_offset; freq_offset += kP_freq_controller * freq_offset_ctrl; } /* get symbol and correct frequency */ for (i = 0; i < Tu; i++) { indexin = i + symbol_position_offset; tmptheta = (freq_offset / Tu) * indexin + phi_freq_correction_last; exp_temp[i * 2] = (float) cos(tmptheta); exp_temp[i * 2 + 1] = (float) sin(tmptheta); } for (i = 0; i < Tu; i++) { indexin =i + 1 + delta_time_offset_integer + Tgh + symbol_position_offset; s1[i].re = rs[indexin * 2] * exp_temp[i * 2] - rs[indexin * 2 + 1] * exp_temp[i * 2 + 1]; s1[i].im = rs[indexin * 2] * exp_temp[i * 2 + 1] + rs[indexin * 2 + 1] * exp_temp[i * 2]; } phi_freq_correction_last = fmodf(phi_freq_correction_last + (float) Ts / (float) Tu * freq_offset, 2.0 * PI); /* Now do fft and output symbol */ fftwf_execute(p2); /* printf("xxx exp_temp in getofdmsync \n"); */ for (i = 0; i <= Tu / 2; i++) { term1 = (float) ((i * 2.0 * PI / (float) Tu) * (Tgh + time_offset_fractional - symbol_position_offset)); /* Euler */ exp_temp[i * 2] = (float) cos(term1); exp_temp[i * 2 + 1] = (float) sin(term1); /* printf(" %g %g \n", exp_temp[i*2], exp_temp[i*2+1]); */ } /* now calc out */ for (i = 0; i < Tu / 2; i++) { out1[i * 2] = (float) (((S1[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2] + ((S1[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2 + 1]); /* real = ac+bd */ out1[i * 2 + 1] = (float) (((S1[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2] - ((S1[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2 + 1]); /* imag bc -ad */ } for (i = 0; i < (Tu / 2 - 1); i++) { out1[(Tu / 2 + i) * 2] = (float) (((S1[i]).re) * exp_temp[i * 2] - ((S1[i]).im) * exp_temp[i * 2 + 1]); out1[(Tu / 2 + i) * 2 + 1] = (float) (((S1[i]).im) * exp_temp[i * 2] + ((S1[i]).re) * exp_temp[i * 2 + 1]); } /* Now flip out1 to out */ for (i = 0; i < Tu / 2; i++) { out[i * 2] = out1[(Tu / 2 - 1 - i) * 2]; out[i * 2 + 1] = out1[(Tu / 2 - 1 - i) * 2 + 1]; } /* now put in the rest */ for (i = Tu / 2; i < Tu; i++) { out[i * 2] = out1[i * 2]; out[i * 2 + 1] = out1[i * 2 + 1]; } Zi[1] = phi_freq_correction_last; Zi[2] = delta_time_offset_I; Zi[4] = freq_offset; Zi[5] = time_offset_fractional; return (delta_time_offset_integer); } } qsstv_8.2.12/qsstv/drmrx/getsymbolidx.cpp000664 001750 001750 00000006474 12440612574 020540 0ustar00jomajoma000000 000000 /* * * file getsymbolidx.c * * corresponds with matlab file get_symbol_index.m * from diorama-1.1.1 * by Andreas Dittrich * * translated to C * by M.Bos - PA0MBO * * Date feb 21st 2009 * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include struct cmplxnmbr { float re; float im; }; #define PI (4.0*atan(1.00)) int getsymbolidx(float *symbol_buffer, int symbols_per_frame, int *time_ref_cells_k, int *time_ref_cells_theta_1024, int K_dc, int K_modulo, int n_time_ref_cells) { struct cmplxnmbr S[288][25]; /* max 24 symbols per frame */ int i, j, n, symbol0; float sum_real_xx[25]; // float sum_imag_xx[25]; float tmp1real, tmp1imag, tmp2real, tmp2imag; int k1_index, k2_index; float phi1, phi2; float max_sum_xx; /* reshape symbol buffer to matrix S */ for (i = 0; i < symbols_per_frame; i++) { for (j = 0; j < K_modulo; j++) { (S[j][i]).re = symbol_buffer[(j + i * K_modulo) * 2]; (S[j][i]).im = symbol_buffer[(j + i * K_modulo) * 2 + 1]; } } /* debugging printf("ooo symbols buffer in get symbolidx\n"); for (i=0; i < K_modulo; i++) printf("%g\n", sqrt( (S[i][0]).re* (S[i][0]).re+ (S[i][0]).im*(S[i][0]).im)); printf("oooo\n"); */ for (i = 0; i < symbols_per_frame; i++) { sum_real_xx[i] = 0.0; // sum_imag_xx[i] = 0.0; } for (n = 0; n < n_time_ref_cells - 1; n++) { if (time_ref_cells_k[n + 1] - time_ref_cells_k[n] == 1) { k1_index = K_dc + time_ref_cells_k[n]; k2_index = K_dc + time_ref_cells_k[n + 1]; phi1 = (2.0 * PI * time_ref_cells_theta_1024[n]) / 1024.0; phi2 = (2.0 * PI * time_ref_cells_theta_1024[n + 1]) / 1024.0; /* printf("timeref[n] is %d timeref[n+1] is %d n is %d\n", time_ref_cells_k[n], time_ref_cells_k[n+1], n); printf("in getsymbolidx K_dc is %d k1_index %d k2_index %d phi1 %g phi2 %g\n", K_dc, k1_index, k2_index, phi1, phi2); */ for (j = 0; j < symbols_per_frame; j++) { tmp1real = (S[k1_index][j]).re * cos(phi1) + (S[k1_index][j]).im * sin(phi1); tmp1imag = (S[k1_index][j]).im * cos(phi1) - (S[k1_index][j]).re * sin(phi1); tmp2real = (S[k2_index][j]).re * cos(phi2) + (S[k2_index][j]).im * sin(phi2); tmp2imag = (S[k2_index][j]).im * cos(phi2) - (S[k2_index][j]).re * sin(phi2); sum_real_xx[j] += tmp1real * tmp2real + tmp1imag * tmp2imag; /* sum_imag_xx[j] += tmp1imag*tmp2real - tmp1real*tmp2imag; */ } } } /* detmn of index of max in abs(sum..xx) */ max_sum_xx = -1.0E20; symbol0 = 0; for (j = 0; j < symbols_per_frame; j++) { tmp1real = fabs(sum_real_xx[j]); /* debugging printf("abs_sum_real_xx[%d] %g\n", j, tmp1real); */ if (tmp1real > max_sum_xx) { max_sum_xx = tmp1real; symbol0 = j; } } return (symbol0); } qsstv_8.2.12/qsstv/drmrx/hybridcrypt.cpp000664 001750 001750 00000005543 12440612574 020365 0ustar00jomajoma000000 000000 #include "hybridcrypt.h" #include #include "configparams.h" #include "QResource" hybridCrypt::hybridCrypt() { const uchar *d; QResource qrc(":/icons/mgc.raw"); d=qrc.data(); key1=d[32]-0x36; key2=d[33]-0x72; key3=d[34]-0xd8; key4=d[35]-0xFE; } bool hybridCrypt::deCrypt(QByteArray *ba, QString &result) { int baSize; bool ok; int charCount=0; QString tempStr="0x00"; short int bufI, bufI2, divzr, num1, num2, num3, num4, res1, res2, res3, res4; QString bufS, hexa, hexa1, hexa2; unsigned char r1,r2; result=""; res1=res2=res3=res4=0; divzr=key1*key4; bufI2=key3*key2; divzr-=bufI2; if(divzr==0) return FALSE; baSize=ba->size()-2; //drop /r/n if(baSize<20) { hcFtpRemoteHost=hybridFtpRemoteHost; hcFtpLogin=hybridFtpLogin; hcFtpPassword=hybridFtpPassword; hcFtpRemoteDirectory=hybridFtpRemoteDirectory2; return TRUE; } do { for(bufI=0;bufI<4;bufI++,charCount+=2) { r1=ba->at(charCount); r2=ba->at(charCount+1); if(r1==0xFF) { r1=r2=0; } if(r1==0xFE) { r1=0; } if(r1==0xFD) { r1=r2; r2=0; } switch(bufI) { case 0: res1=r1*256+r2; break; case 1: res2=r1*256+r2; break; case 2: res3=r1*256+r2; break; case 3: res4=r1*256+r2; break; } } bufI= res1 * key4; bufI2= res2 * key3; num1= bufI - bufI2; num1= num1 / divzr; bufI= res2 * key1; bufI2= res1 * key2; num2= bufI - bufI2; num2 = num2 / divzr; bufI= res3 * key4; bufI2= res4 * key3; num3= bufI - bufI2; num3= num3 / divzr; bufI= res4 * key1; bufI2= res3 * key2; num4= bufI - bufI2; num4= num4 / divzr; tempStr[2]=QChar(num1); tempStr[3]=QChar(num2); result.append(QChar(tempStr.toInt(&ok,16))); tempStr[2]=QChar(num3); tempStr[3]=QChar(num4); result.append(QChar(tempStr.toInt(&ok,16))); } while(charCount=1;i--) { sum=b[i]; for (j=i+1;j<=n;j++) sum -= a[i][j]*b[j]; b[i]=sum/a[i][i]; } } /* (C) Copr. 1986-92 Numerical Recipes Software 0!-"1. */ qsstv_8.2.12/qsstv/drmrx/ludcmp.cpp000664 001750 001750 00000002213 12440612574 017275 0ustar00jomajoma000000 000000 #include #define NRANSI #include "nrutil.h" #define TINY 1.0e-20; void ludcmp(float **a, int n, int *indx, float *d) { int i,imax=0,j,k; float big,dum,sum,temp; float *vv; vv=fvector(1,n); *d=1.0; for (i=1;i<=n;i++) { big=0.0; for (j=1;j<=n;j++) if ((temp=fabs(a[i][j])) > big) big=temp; if (big == 0.0) nrerror("Singular matrix in routine ludcmp"); vv[i]=1.0/big; } for (j=1;j<=n;j++) { for (i=1;i= big) { big=dum; imax=i; } } if (j != imax) { for (k=1;k<=n;k++) { dum=a[imax][k]; a[imax][k]=a[j][k]; a[j][k]=dum; } *d = -(*d); vv[imax]=vv[j]; } indx[j]=imax; if (a[j][j] == 0.0) a[j][j]=TINY; if (j != n) { dum=1.0/(a[j][j]); for (i=j+1;i<=n;i++) a[i][j] *= dum; } } free_fvector(vv,1,n); } #undef TINY #undef NRANSI /* (C) Copr. 1986-92 Numerical Recipes Software 0!-"1. */ qsstv_8.2.12/qsstv/drmrx/mkfacmap.cpp000664 001750 001750 00000024261 12440612574 017577 0ustar00jomajoma000000 000000 /* * File mkfacmap.c * * * produces FAC mapping data * * Author M.Bos * Date Feb 21st 2009 * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include int mkfacmap(int robustness_mode, int K_dc, int K_modulo, int /*@out@ */ *FACmap) { int elem_cnt, i; switch (robustness_mode) { case 0: elem_cnt = 45; i = 0; FACmap[i++] = K_dc + K_modulo + 10; FACmap[i++] = K_dc + K_modulo + 22; FACmap[i++] = K_dc + K_modulo + 30; FACmap[i++] = K_dc + K_modulo + 50; FACmap[i++] = K_dc + 2 * K_modulo + 14; FACmap[i++] = K_dc + 2 * K_modulo + 26; FACmap[i++] = K_dc + 2 * K_modulo + 34; FACmap[i++] = K_dc + 3 * K_modulo + 18; FACmap[i++] = K_dc + 3 * K_modulo + 30; FACmap[i++] = K_dc + 3 * K_modulo + 38; FACmap[i++] = K_dc + 4 * K_modulo + 22; FACmap[i++] = K_dc + 4 * K_modulo + 34; FACmap[i++] = K_dc + 4 * K_modulo + 42; FACmap[i++] = K_dc + 5 * K_modulo + 18; FACmap[i++] = K_dc + 5 * K_modulo + 26; FACmap[i++] = K_dc + 5 * K_modulo + 38; FACmap[i++] = K_dc + 5 * K_modulo + 46; FACmap[i++] = K_dc + 6 * K_modulo + 22; FACmap[i++] = K_dc + 6 * K_modulo + 30; FACmap[i++] = K_dc + 6 * K_modulo + 42; FACmap[i++] = K_dc + 6 * K_modulo + 50; FACmap[i++] = K_dc + 7 * K_modulo + 26; FACmap[i++] = K_dc + 7 * K_modulo + 34; FACmap[i++] = K_dc + 7 * K_modulo + 46; FACmap[i++] = K_dc + 8 * K_modulo + 10; FACmap[i++] = K_dc + 8 * K_modulo + 30; FACmap[i++] = K_dc + 8 * K_modulo + 38; FACmap[i++] = K_dc + 8 * K_modulo + 50; FACmap[i++] = K_dc + 9 * K_modulo + 14; FACmap[i++] = K_dc + 9 * K_modulo + 34; FACmap[i++] = K_dc + 9 * K_modulo + 42; FACmap[i++] = K_dc + 10 * K_modulo + 18; FACmap[i++] = K_dc + 10 * K_modulo + 38; FACmap[i++] = K_dc + 10 * K_modulo + 46; FACmap[i++] = K_dc + 11 * K_modulo + 10; FACmap[i++] = K_dc + 11 * K_modulo + 22; FACmap[i++] = K_dc + 11 * K_modulo + 42; FACmap[i++] = K_dc + 11 * K_modulo + 50; FACmap[i++] = K_dc + 12 * K_modulo + 14; FACmap[i++] = K_dc + 12 * K_modulo + 26; FACmap[i++] = K_dc + 12 * K_modulo + 46; FACmap[i++] = K_dc + 13 * K_modulo + 18; FACmap[i++] = K_dc + 13 * K_modulo + 30; FACmap[i++] = K_dc + 14 * K_modulo + 22; FACmap[i++] = K_dc + 14 * K_modulo + 34; break; case 1: elem_cnt = 45; i = 0; FACmap[i++] = K_dc + 21; FACmap[i++] = K_dc + K_modulo + 11; FACmap[i++] = K_dc + K_modulo + 23; FACmap[i++] = K_dc + K_modulo + 35; FACmap[i++] = K_dc + 2 * K_modulo + 13; FACmap[i++] = K_dc + 2 * K_modulo + 25; FACmap[i++] = K_dc + 2 * K_modulo + 37; FACmap[i++] = K_dc + 3 * K_modulo + 15; FACmap[i++] = K_dc + 3 * K_modulo + 27; FACmap[i++] = K_dc + 3 * K_modulo + 39; FACmap[i++] = K_dc + 4 * K_modulo + 5; FACmap[i++] = K_dc + 4 * K_modulo + 17; FACmap[i++] = K_dc + 4 * K_modulo + 29; FACmap[i++] = K_dc + 4 * K_modulo + 41; FACmap[i++] = K_dc + 5 * K_modulo + 7; FACmap[i++] = K_dc + 5 * K_modulo + 19; FACmap[i++] = K_dc + 5 * K_modulo + 31; FACmap[i++] = K_dc + 6 * K_modulo + 9; FACmap[i++] = K_dc + 6 * K_modulo + 21; FACmap[i++] = K_dc + 6 * K_modulo + 33; FACmap[i++] = K_dc + 7 * K_modulo + 11; FACmap[i++] = K_dc + 7 * K_modulo + 23; FACmap[i++] = K_dc + 7 * K_modulo + 35; FACmap[i++] = K_dc + 8 * K_modulo + 13; FACmap[i++] = K_dc + 8 * K_modulo + 25; FACmap[i++] = K_dc + 8 * K_modulo + 37; FACmap[i++] = K_dc + 9 * K_modulo + 15; FACmap[i++] = K_dc + 9 * K_modulo + 27; FACmap[i++] = K_dc + 9 * K_modulo + 39; FACmap[i++] = K_dc + 10 * K_modulo + 5; FACmap[i++] = K_dc + 10 * K_modulo + 17; FACmap[i++] = K_dc + 10 * K_modulo + 29; FACmap[i++] = K_dc + 10 * K_modulo + 41; FACmap[i++] = K_dc + 11 * K_modulo + 7; FACmap[i++] = K_dc + 11 * K_modulo + 19; FACmap[i++] = K_dc + 11 * K_modulo + 31; FACmap[i++] = K_dc + 12 * K_modulo + 9; FACmap[i++] = K_dc + 12 * K_modulo + 21; FACmap[i++] = K_dc + 12 * K_modulo + 33; FACmap[i++] = K_dc + 13 * K_modulo + 11; FACmap[i++] = K_dc + 13 * K_modulo + 23; FACmap[i++] = K_dc + 13 * K_modulo + 35; FACmap[i++] = K_dc + 14 * K_modulo + 13; FACmap[i++] = K_dc + 14 * K_modulo + 25; FACmap[i++] = K_dc + 14 * K_modulo + 37; break; case 2: elem_cnt = 45; i = 0; FACmap[i++] = K_dc + K_modulo + 7; FACmap[i++] = K_dc + K_modulo + 23; FACmap[i++] = K_dc + 2 * K_modulo + 8; FACmap[i++] = K_dc + 2 * K_modulo + 16; FACmap[i++] = K_dc + 2 * K_modulo + 24; FACmap[i++] = K_dc + 3 * K_modulo + 9; FACmap[i++] = K_dc + 3 * K_modulo + 17; FACmap[i++] = K_dc + 4 * K_modulo + 10; FACmap[i++] = K_dc + 4 * K_modulo + 18; FACmap[i++] = K_dc + 5 * K_modulo + 11; FACmap[i++] = K_dc + 5 * K_modulo + 19; FACmap[i++] = K_dc + 6 * K_modulo + 4; FACmap[i++] = K_dc + 6 * K_modulo + 12; FACmap[i++] = K_dc + 7 * K_modulo + 13; FACmap[i++] = K_dc + 7 * K_modulo + 21; FACmap[i++] = K_dc + 8 * K_modulo + 6; FACmap[i++] = K_dc + 8 * K_modulo + 14; FACmap[i++] = K_dc + 8 * K_modulo + 22; FACmap[i++] = K_dc + 9 * K_modulo + 7; FACmap[i++] = K_dc + 9 * K_modulo + 23; FACmap[i++] = K_dc + 10 * K_modulo + 8; FACmap[i++] = K_dc + 10 * K_modulo + 16; FACmap[i++] = K_dc + 10 * K_modulo + 24; FACmap[i++] = K_dc + 11 * K_modulo + 9; FACmap[i++] = K_dc + 11 * K_modulo + 13; FACmap[i++] = K_dc + 11 * K_modulo + 17; FACmap[i++] = K_dc + 12 * K_modulo + 10; FACmap[i++] = K_dc + 12 * K_modulo + 18; FACmap[i++] = K_dc + 13 * K_modulo + 11; FACmap[i++] = K_dc + 13 * K_modulo + 19; FACmap[i++] = K_dc + 14 * K_modulo + 4; FACmap[i++] = K_dc + 14 * K_modulo + 12; FACmap[i++] = K_dc + 14 * K_modulo + 16; FACmap[i++] = K_dc + 15 * K_modulo + 13; FACmap[i++] = K_dc + 15 * K_modulo + 21; FACmap[i++] = K_dc + 16 * K_modulo + 6; FACmap[i++] = K_dc + 16 * K_modulo + 14; FACmap[i++] = K_dc + 16 * K_modulo + 22; FACmap[i++] = K_dc + 17 * K_modulo + 7; FACmap[i++] = K_dc + 17 * K_modulo + 23; FACmap[i++] = K_dc + 18 * K_modulo + 8; FACmap[i++] = K_dc + 18 * K_modulo + 16; FACmap[i++] = K_dc + 18 * K_modulo + 24; FACmap[i++] = K_dc + 19 * K_modulo + 9; FACmap[i++] = K_dc + 19 * K_modulo + 17; break; case 3: /* does not exist in amateur mode */ elem_cnt = 45; i = 0; FACmap[i++] = K_dc + 3 * K_modulo + 9; FACmap[i++] = K_dc + 3 * K_modulo + 18; FACmap[i++] = K_dc + 3 * K_modulo + 27; FACmap[i++] = K_dc + 4 * K_modulo + 10; FACmap[i++] = K_dc + 4 * K_modulo + 19; FACmap[i++] = K_dc + 5 * K_modulo + 11; FACmap[i++] = K_dc + 5 * K_modulo + 20; FACmap[i++] = K_dc + 5 * K_modulo + 29; FACmap[i++] = K_dc + 6 * K_modulo + 12; FACmap[i++] = K_dc + 6 * K_modulo + 30; FACmap[i++] = K_dc + 7 * K_modulo + 13; FACmap[i++] = K_dc + 7 * K_modulo + 22; FACmap[i++] = K_dc + 7 * K_modulo + 31; FACmap[i++] = K_dc + 8 * K_modulo + 5; FACmap[i++] = K_dc + 8 * K_modulo + 14; FACmap[i++] = K_dc + 8 * K_modulo + 23; FACmap[i++] = K_dc + 8 * K_modulo + 32; FACmap[i++] = K_dc + 9 * K_modulo + 6; FACmap[i++] = K_dc + 9 * K_modulo + 15; FACmap[i++] = K_dc + 9 * K_modulo + 24; FACmap[i++] = K_dc + 9 * K_modulo + 33; FACmap[i++] = K_dc + 10 * K_modulo + 16; FACmap[i++] = K_dc + 10 * K_modulo + 25; FACmap[i++] = K_dc + 10 * K_modulo + 34; FACmap[i++] = K_dc + 11 * K_modulo + 8; FACmap[i++] = K_dc + 11 * K_modulo + 17; FACmap[i++] = K_dc + 11 * K_modulo + 26; FACmap[i++] = K_dc + 11 * K_modulo + 35; FACmap[i++] = K_dc + 12 * K_modulo + 9; FACmap[i++] = K_dc + 12 * K_modulo + 18; FACmap[i++] = K_dc + 12 * K_modulo + 27; FACmap[i++] = K_dc + 12 * K_modulo + 36; FACmap[i++] = K_dc + 13 * K_modulo + 10; FACmap[i++] = K_dc + 13 * K_modulo + 19; FACmap[i++] = K_dc + 13 * K_modulo + 37; FACmap[i++] = K_dc + 14 * K_modulo + 11; FACmap[i++] = K_dc + 14 * K_modulo + 20; FACmap[i++] = K_dc + 14 * K_modulo + 29; FACmap[i++] = K_dc + 15 * K_modulo + 12; FACmap[i++] = K_dc + 15 * K_modulo + 30; FACmap[i++] = K_dc + 16 * K_modulo + 13; FACmap[i++] = K_dc + 16 * K_modulo + 22; FACmap[i++] = K_dc + 16 * K_modulo + 31; FACmap[i++] = K_dc + 17 * K_modulo + 5; FACmap[i++] = K_dc + 17 * K_modulo + 14; FACmap[i++] = K_dc + 17 * K_modulo + 23; FACmap[i++] = K_dc + 17 * K_modulo + 32; FACmap[i++] = K_dc + 18 * K_modulo + 6; FACmap[i++] = K_dc + 18 * K_modulo + 15; FACmap[i++] = K_dc + 18 * K_modulo + 24; FACmap[i++] = K_dc + 18 * K_modulo + 33; FACmap[i++] = K_dc + 19 * K_modulo + 16; FACmap[i++] = K_dc + 19 * K_modulo + 25; FACmap[i++] = K_dc + 19 * K_modulo + 34; FACmap[i++] = K_dc + 20 * K_modulo + 8; FACmap[i++] = K_dc + 20 * K_modulo + 17; FACmap[i++] = K_dc + 20 * K_modulo + 26; FACmap[i++] = K_dc + 20 * K_modulo + 35; FACmap[i++] = K_dc + 21 * K_modulo + 9; FACmap[i++] = K_dc + 21 * K_modulo + 18; FACmap[i++] = K_dc + 21 * K_modulo + 27; FACmap[i++] = K_dc + 21 * K_modulo + 36; FACmap[i++] = K_dc + 22 * K_modulo + 10; FACmap[i++] = K_dc + 22 * K_modulo + 19; FACmap[i++] = K_dc + 22 * K_modulo + 37; break; default: printf("wrong robustness mode in cal to mkfacmap\n"); exit(EXIT_FAILURE); } return elem_cnt; } qsstv_8.2.12/qsstv/drmrx/mkmap.h000664 001750 001750 00000000063 12440612574 016564 0ustar00jomajoma000000 000000 #ifndef MKMAP_H #define MKMAP_H #endif // MKMAP_H qsstv_8.2.12/qsstv/drmrx/mkmscmap.cpp000664 001750 001750 00000024740 12440612574 017632 0ustar00jomajoma000000 000000 /* * file mkmscmap.c * * makes MSC_Demapper * * cf create_MSC_demapper.m matlab code by * Torsten Schorr 2004 * * recoded in C by PA0MBO - M.Bos * * date Feb 21st 2009 * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include #include "drmdefs.h" #include "structtemplates.h" #include "drmproto.h" extern int symbols_per_frame_list[4]; extern int time_ref_cells_k_list[4][21]; extern int y_list[4]; extern int K_min_K_max_list[2][24]; extern int freq_ref_cells_k_list[4][3]; extern int x_list[4]; extern int k0_list[4]; extern int mode_and_occupancy_code_table[24]; extern int time_ref_cells_cnt_list[4]; extern int lFAC; extern int MSC_Demapper[6][2959]; int mkmscmap(int robustness_mode, int spectrum_occupancy, int interleaver_depth, int K_dc, int K_modulo) { int frames_per_superframe = 3; int K_min; int K_max; int mode_and_occupancy_code; int x, y, k0; int s; // int Tu; int gain_ref_cells_k[712]; int unused_carriers_k[3]; int i, m, j; int first_symbol; int control_cells_k[65]; int pilot_cells_k[600]; int cnt_msc_cells = 0; int rndcnt, cnt_time_ref_cells; int n, k, p, p_min, p_max; int contains; int term; int N_SFA, N_L, N_MUX, D; int cnt_msc_cells_3_superframes; static int *PICMSC_inv = NULL; int step, ncGIMSC; // int nrGIMSC; int columnv[5]; int rowv[1000]; int vproduct[5][1000]; int GIMSC_inv[5000]; int cnt_GIMSC; int Cell_Deinterleaver[5000]; int FAC_cells_k[65]; /* reeds global */ // int Tu_list[] = { Tu_A, Tu_B, Tu_C, Tu_D }; int symbols_per_frame; int freq_ref_cells_k[3]; int time_ref_cells_k[21]; // int carrier_per_symbol; int MSC_cells_k[8877]; int MSC_cells_3_superframes[3 * 8877]; // Tu = Tu_list[robustness_mode]; K_min = K_min_K_max_list[0][spectrum_occupancy + robustness_mode * 6]; K_max = K_min_K_max_list[1][spectrum_occupancy + robustness_mode * 6]; mode_and_occupancy_code = mode_and_occupancy_code_table[robustness_mode * 6 + spectrum_occupancy]; if (mode_and_occupancy_code < 0) { printf("BAD MODE AND OCCUPANCY CODE \n"); } symbols_per_frame = symbols_per_frame_list[robustness_mode]; // carrier_per_symbol = K_max - K_min + 1; x = x_list[robustness_mode]; y = y_list[robustness_mode]; k0 = k0_list[robustness_mode]; rndcnt = 0; for (s = 0; s < symbols_per_frame; s++) { n = s % y; m = s / y; p_min = (int) ceil((double) ((K_min - k0 - x * n) / (x * y))); p_max = (K_max - k0 - x * n) / (x * y); for (p = p_min; p <= p_max; p++) { k = k0 + x * n + x * y * p; gain_ref_cells_k[rndcnt++] = k + s * K_modulo; /* printf("gain_ref_cells_k[%d] = %d\n", rndcnt-1, gain_ref_cells_k[rndcnt-1]); */ } } unused_carriers_k[0] = 0; if (robustness_mode == 0) { unused_carriers_k[1] = 1; } for (i = 0; i < 3; i++) { freq_ref_cells_k[i] = freq_ref_cells_k_list[robustness_mode][i]; } cnt_time_ref_cells = time_ref_cells_cnt_list[robustness_mode]; for (i = 0; i < cnt_time_ref_cells; i++) { time_ref_cells_k[i] = time_ref_cells_k_list[robustness_mode][i]; } lFAC = mkfacmap(robustness_mode, 0, K_modulo, FAC_cells_k); /* MSC cells per superframe */ first_symbol = 0; cnt_msc_cells = 0; for (m = 0; m < frames_per_superframe; m++) { for (i = 0; i < lFAC; i++) { control_cells_k[i] = FAC_cells_k[i] + K_modulo * symbols_per_frame * m; /* printf("control_cells_k[%d] = %d FAC_cells_k %d K_modulo %d symbols_per_frame %d m %d \n", i, control_cells_k[i], FAC_cells_k[i], K_modulo, symbols_per_frame, m); */ } for (j = 3; j < cnt_time_ref_cells + 3; j++) { pilot_cells_k[j] = K_modulo * symbols_per_frame * m + time_ref_cells_k[j - 3]; } for (j = 3 + cnt_time_ref_cells; j < 3 + cnt_time_ref_cells + rndcnt; j++) { pilot_cells_k[j] = K_modulo * symbols_per_frame * m + gain_ref_cells_k[j - 3 - cnt_time_ref_cells]; } for (s = first_symbol; s < symbols_per_frame; s++) { for (j = 0; j < 3; j++) { pilot_cells_k[j] = K_modulo * symbols_per_frame * m + K_modulo * s + freq_ref_cells_k[j]; } for (k = K_min; k <= K_max; k++) { contains = 0; term = k + K_modulo * symbols_per_frame * m + K_modulo * s; for (j = 0; j < 3 + cnt_time_ref_cells + rndcnt; j++) { if (term == pilot_cells_k[j]) { contains = 1; goto uit; } } for (j = 0; j < lFAC; j++) { if (term == control_cells_k[j]) { contains = 1; goto uit; } } if (robustness_mode == 0) { for (j = 0; j < 1; j++) { if (term == K_modulo * symbols_per_frame * m + K_modulo * s + unused_carriers_k[j]) { contains = 1; goto uit; } } } else { if (term == K_modulo * symbols_per_frame * m + K_modulo * s) /* pa0mbo 29-11-2007 was + unused_carriers_k[0] */ { contains = 1; goto uit; } } uit:if (contains == 0) { MSC_cells_k[cnt_msc_cells++] = term; /* debugging printf("%d cell=%d \n", cnt_msc_cells, MSC_cells_k[cnt_msc_cells -1]); */ } } /* end k-loop */ } /* end s-loop */ first_symbol = 0; } /* end m -loop */ N_SFA = cnt_msc_cells; N_L = N_SFA % frames_per_superframe; N_MUX = (N_SFA - N_L) / frames_per_superframe; /* cell interleaver for MSC_cells */ cnt_msc_cells_3_superframes = 0; for (i = 0; i < N_SFA - N_L; i++) { MSC_cells_3_superframes[cnt_msc_cells_3_superframes++] = K_dc + MSC_cells_k[i]; } for (i = 0; i < N_SFA - N_L; i++) { MSC_cells_3_superframes[cnt_msc_cells_3_superframes++] = K_dc + symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_k[i]; } for (i = 0; i < N_SFA - N_L; i++) { MSC_cells_3_superframes[cnt_msc_cells_3_superframes++] = K_dc + 2 * symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_k[i]; } /* for (i=0; i < cnt_msc_cells_3_superframes; i++) printf("MSC_cells3..[%d] = %d\n", i, MSC_cells_3_superframes[i]); printf("====\n"); */ if (PICMSC_inv != NULL) free(PICMSC_inv); PICMSC_inv = deinterleaver(0, 1, N_MUX, 5); if (interleaver_depth == 0) { /* convolutional deinterleaver ETSI ES 201980 / 7.6 */ D = 5; /* calc of GIMSC_inv in steps */ /* first step [1:N_MUX+1:D*(N_MUX+1)] */ step = N_MUX + 1; // nrGIMSC = D; ncGIMSC = (int) ceil((float) N_MUX / D); /* printf("ncGIMSC = %d\n", ncGIMSC); */ columnv[0] = 1; rowv[0] = 0; for (i = 1; i < D; i++) columnv[i] = columnv[i - 1] + step; for (i = 1; i < ncGIMSC; i++) rowv[i] = rowv[i - 1] + D; for (i = 0; i < D; i++) { for (j = 0; j < ncGIMSC; j++) { vproduct[i][j] = columnv[i] + rowv[j]; } } cnt_GIMSC = 0; for (j = 0; j < ncGIMSC; j++) { for (i = 0; i < D; i++) { GIMSC_inv[cnt_GIMSC++] = vproduct[i][j]; /* printf("GIMSC_inv[%d] = %d \n", cnt_GIMSC-1, vproduct[i][j]); */ } } cnt_GIMSC--; /* printf("xxx Cell_Deinterleaver\n"); */ for (i = 0; i < N_MUX; i++) { Cell_Deinterleaver[i] = GIMSC_inv[PICMSC_inv[i]]; /* printf("%d \n", Cell_Deinterleaver[i]); */ } /* printf("xxx\n"); */ for (i = 0; i < N_MUX; i++) { MSC_Demapper[5][i] = MSC_cells_3_superframes[Cell_Deinterleaver[i] - 1]; MSC_Demapper[0][i] = ((MSC_cells_3_superframes[N_MUX + Cell_Deinterleaver[i] - 1] + 1) % (2 * symbols_per_frame * frames_per_superframe * K_modulo)) - 1; MSC_Demapper[1][i] = ((MSC_cells_3_superframes[2 * N_MUX + Cell_Deinterleaver[i] - 1] + 1) % (2 * symbols_per_frame * frames_per_superframe * K_modulo)) - 1; MSC_Demapper[2][i] = ((symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[Cell_Deinterleaver[i] - 1] + 1) % (2 * symbols_per_frame * frames_per_superframe * K_modulo)) - 1; MSC_Demapper[3][i] = ((symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[N_MUX + Cell_Deinterleaver[i] - 1] + 1) % (2 * symbols_per_frame * frames_per_superframe * K_modulo)) - 1; MSC_Demapper[4][i] = ((symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[2 * N_MUX + Cell_Deinterleaver[i] - 1] + 1) % (2 * symbols_per_frame * frames_per_superframe * K_modulo)) - 1; } } else { /* printf("xxx Cell_Deinterleaver\n"); */ for (i = 0; i < N_MUX; i++) { Cell_Deinterleaver[i] = PICMSC_inv[i]; /* printf("%d \n", Cell_Deinterleaver[i]); */ } /* printf("xxx\n"); */ /* printf("xxxx MSC_Demap[1]\n"); */ for (i = 0; i < N_MUX; i++) { MSC_Demapper[1][i] = MSC_cells_3_superframes[Cell_Deinterleaver[i]]; /* pa0mbo -1 binnen [] weggehaald */ /* printf("%d \n", MSC_Demapper[1][i]); */ MSC_Demapper[2][i] = (MSC_cells_3_superframes[N_MUX + Cell_Deinterleaver[i]]) % (2 * symbols_per_frame * frames_per_superframe * K_modulo); MSC_Demapper[3][i] = (MSC_cells_3_superframes[2 * N_MUX + Cell_Deinterleaver[i]]) % (2 * symbols_per_frame * frames_per_superframe * K_modulo); MSC_Demapper[4][i] = (symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[Cell_Deinterleaver[i]]) % (2 * symbols_per_frame * frames_per_superframe * K_modulo); MSC_Demapper[5][i] = (symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[N_MUX + Cell_Deinterleaver[i]]) % (2 * symbols_per_frame * frames_per_superframe * K_modulo); MSC_Demapper[0][i] = (symbols_per_frame * frames_per_superframe * K_modulo + MSC_cells_3_superframes[2 * N_MUX + Cell_Deinterleaver[i]]) % (2 * symbols_per_frame * frames_per_superframe * K_modulo); } } return N_MUX; } qsstv_8.2.12/qsstv/drmrx/msd_hard.h000664 001750 001750 00000003475 12440612574 017252 0ustar00jomajoma000000 000000 signed char puncturing[13][17] = { {0, 15, 0}, {-4, 15, 2, 7, 2, 7, -4}, {0, 7, 0}, {-6, 7, 2, 7, 2, 7, 2, 3, -6}, {0, 3, 0}, {-6, 3, 2, 5, 2, 3, 2, 1, -6}, {-4, 3, 2, 1, 2, 3, -4}, {-2, 3, 2, 1, -2}, {-14, 3, 2, 1, 2, 1, 2, 3, 2, 1, 2, 1, 2, 3, 2, 1, -14}, {-4, 3, 2, 1, 2, 1, -4}, {-6, 3, 2, 1, 2, 1, 2, 1, -6}, {-12, 3, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, -12}, {-14, 3, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, -14} }; /* int RX[13] = {1, 3, 1, 4, 1, 4, 3, 2, 8, 3, 4, 7, 8}; */ int RY[13] = { 4, 10, 3, 11, 2, 7, 5, 3, 11, 4, 5, 8, 9 }; signed char tailpuncturing[12][13] = { {-10, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, -10}, {-10, 7, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, -10}, {-10, 7, 2, 3, 2, 3, 2, 7, 2, 3, 2, 3, -10}, {-10, 7, 2, 7, 2, 3, 2, 7, 2, 3, 2, 3, -10}, {-10, 7, 2, 7, 2, 3, 2, 7, 2, 7, 2, 3, -10}, {-10, 7, 2, 7, 2, 7, 2, 7, 2, 7, 2, 3, -10}, {-10, 7, 2, 7, 2, 7, 2, 7, 2, 7, 2, 7, -10}, {-10, 15, 2, 7, 2, 7, 2, 7, 2, 7, 2, 7, -10}, {-10, 15, 2, 7, 2, 7, 2, 15, 2, 7, 2, 7, -10}, {-10, 15, 2, 15, 2, 7, 2, 15, 2, 7, 2, 7, -10}, {-10, 15, 2, 15, 2, 7, 2, 15, 2, 7, 2, 15, -10}, {-10, 15, 2, 15, 2, 15, 2, 15, 2, 7, 2, 15, -10} }; #define SQRT2 1.41421356237310F #define SQRT10 3.16227766016838F #define SQRT42 6.48074069840786F float partitioning[4][8] = { {7 / SQRT42, 5 / SQRT42, 3 / SQRT42, 1 / SQRT42, -1 / SQRT42, -3 / SQRT42, -5 / SQRT42, -7 / SQRT42}, /* 64-QAM Ungerb�k Set Partitioning */ {7 / SQRT42, -1 / SQRT42, 5 / SQRT42, -3 / SQRT42, 3 / SQRT42, -5 / SQRT42, 1 / SQRT42, -7 / SQRT42}, /* 64-QAM Block Partitioning */ {3 / SQRT10, 1 / SQRT10, -1 / SQRT10, -3 / SQRT10}, /* 16-QAM Ungerb�k Set Partitioning */ {1 / SQRT2, -1 / SQRT2} }; /* 4-QAM Ungerb�k Set Partitioning */ #undef SQRT2 #undef SQRT10 #undef SQRT42 qsstv_8.2.12/qsstv/drmrx/msd_hard_sdc.h000664 001750 001750 00000006264 12440612574 020102 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 15.06.2004 */ /* Last change : 30.06.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* msd_hard.h (part of msd_hard) */ /* */ /******************************************************************************/ /* Description: */ /* constants and tables for msd_hard.c */ /* */ /******************************************************************************/ extern signed char puncturing[13][17]; /* int RX[13] = {1, 3, 1, 4, 1, 4, 3, 2, 8, 3, 4, 7, 8}; */ extern int RY[13]; extern signed char tailpuncturing[12][13]; #define SQRT2 1.41421356237310F #define SQRT10 3.16227766016838F #define SQRT42 6.48074069840786F extern float partitioning[4][8]; #undef SQRT2 #undef SQRT10 #undef SQRT42 qsstv_8.2.12/qsstv/drmrx/msdhardfac.cpp000664 001750 001750 00000053302 12440612574 020112 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 15.06.2004 */ /* Last change : 22.07.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* msdhardfac.c */ /* */ /******************************************************************************/ /* Description: */ /* Multi-Stage-Decoder for DRM QAM signals (iterations with hard decisions) */ /* Usage: */ /* */ /* [LPhardout, HPhardout, VSPPhardout] = */ /* msd_hard (received, H, N1, L, Lvspp, */ /* Deinterleaver,PL, maxiter, SDCorMSC); */ /* */ /* received: samples of an FAC, SDC or MSC frame */ /* H: estimated channel transfer function */ /* N1: number of OFDM cells in the higher protected part (part A) */ /* L: number of information bits for Part A/B for each level in (2xl)-matrix */ /* Lvspp: number of information bits in the very strongly protected part */ /* Deinterleaver: deinterleavers for each levels in (Nxl)-int32-matrix */ /* PL: Protection Levels for Part A/B for each level in (2xl)-matrix */ /* maxiter: maximum number of decoding iterations */ /* SDCorMSC: 1 for SDC and MSC frames, 0 for FAC frames */ /* */ /******************************************************************************/ /* * changed filename to msdhardfac.c * and added new interface to accomodate * own C-language interface instead of * Matlab interface * * Author of changes M.Bos - PA0MBO * Date July 10th 2007 * changed memory alignment of lastiter and malloc to prevent IRIX problem */ #include #include #include #include #include #include "viterbi_decode.h" #include "msd_hard.h" #define ITER_BREAK #define CONSIDERING_SNR #ifdef CONSIDERING_SNR #define ARG_INDEX_OFFSET 1 #define NARGS_RHS_STR "9" #define NARGS_RHS 9 #else /* */ #define ARG_INDEX_OFFSET 0 #define NARGS_RHS_STR "8" #define NARGS_RHS 8 #endif /* */ #define PROGNAME "msd_hard" #define PRBS_INIT(reg) reg = 511; #define PRBS_BIT(reg) ((reg ^ (reg >> 4)) & 0x1) #define PRBS_SHIFT(reg) reg = (((reg ^ (reg >> 4)) & 0x1) << 8) | (reg >> 1) int msdhardfac(double /*@out@ */ *received_real, double /*@out@ */ *received_imag, int Lrxdata, /*@out@ */ double *snr, int N1, double *L, int dimL, int Lvspp, int *Deinterleaver, int *PL, int maxiter, int SDCorMSC, double *facdata) { double *received, *first_received, *L1, *L2, L1_real[10], *L2_real, *L1_imag, *L2_imag; double *PL1, *PL2, PL1_real[10], *PL2_real, *PL1_imag, *PL2_imag, *output_ptr, L_dummy[3] = { 0, 0, 0 }; float *metric_real, *metric_imag, *metric, *first_metric, closest_one, closest_zero, sample, *llr, dist; char *memory_ptr, *viterbi_mem, *msd_mem, *hardpoints, *hardpoints_ptr, *lastiter, *infoout[3]; int m, n, N, no_of_levels, iteration, diff; int sample_index, rp_real[3], rp_imag[3], *rp, level, subset_point, no_of_bits, error, msd_mem_size, viterbi_mem_size; int PRBS_reg; int HMmix = 0, HMsym = 0; int i; #ifdef CONSIDERING_SNR double *signal_to_noise_ratio; float SNR; #endif /* */ /* new interface to C-language */ signal_to_noise_ratio = snr; no_of_levels = 1; for (i = 0; i < dimL; i++) { L1_real[i] = L[i]; /* debugging printf("L[%d] = %g , L1_real[%d] = %g\n", i, L[i], i, L1_real[i]); */ } L2_real = L1_real + no_of_levels; L1_imag = L_dummy; L2_imag = L_dummy; for (i = 0; i < 2; i++) { PL1_real[i] = (double) PL[i]; } PL2_real = PL1_real + no_of_levels; PL1_imag = PL2_real + no_of_levels; PL2_imag = PL1_imag + no_of_levels; /* pa0mbo will not be OK has to be checked !! will do for the moment */ /* debugging printf("PL1_real[0]= %g, PL1_real[1]= %g, PL2_real[0]= %g, PL2_real[1]= %g, PL1_imag[0]= %g, PL2_imag[0]= %g\n", PL1_real[0], PL1_real[1], PL2_real[0], PL2_real[1], PL1_imag[0], PL2_imag[0]); */ SDCorMSC = ((0 - SDCorMSC) != 0); /* debugging printf("SDCorMSC = %d\n", SDCorMSC); */ if (Lrxdata < 20) { printf("msdhardfac: length rxdata should be >= 20\n"); exit(1); } N = Lrxdata; if (N < 20) { printf("msdhardfac: N has to be >= 20!\n"); exit(1); } if ((N1 < 0) || (N1 > N - 20)) { printf("msdhardfac: N1 has to be >= 0!\n"); exit(1); } if (Lvspp < 0) { printf("msdhardfac: Lvspp has to be >= 0!\n"); exit(1); } if (maxiter < 0) { printf("msdhardfac: maxiter must not be negativ."); exit(1); } if (HMmix && (Lvspp == 0)) { printf("msdhardfac: HMmix requires Lvspp > 0."); exit(1); } /* printf("start mem alloc \n "); printf("N= %d, no_of_levels= %d\n", N, no_of_levels); */ /* memory allocation and initialization: */ no_of_bits = 0; for (level = 0; level < no_of_levels; level++) { no_of_bits += (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level] + (int) L2_imag[level] + 6; /* printf(" --- level %d L1real %d L2real %d L1imga %d L2imag %d\n", level, (int)L1_real[level], (int)L2_real[level], (int)L1_imag[level], (int)L2_imag[level]); */ } msd_mem_size = 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2 * N * sizeof(char) + no_of_bits * sizeof(char); viterbi_mem_size = STATES * sizeof(float) + STATES * sizeof(float) + 2 * N * STATES * sizeof(char); /* printf("msdhardfac: viterbi_mem_size is %d STATES is %d\n", viterbi_mem_size, STATES); */ if (received_imag == NULL) { memory_ptr = (char *) malloc(viterbi_mem_size + msd_mem_size + N * sizeof(double) + 2); received_imag = (double *) (memory_ptr + viterbi_mem_size + msd_mem_size); memset(received_imag, 0, N * sizeof(double)); } else { memory_ptr = (char *) malloc(viterbi_mem_size + msd_mem_size + 2); /* printf("msdhardfac: debugging memory_ptr alloc succeeded viterbi_size = %d mds_size=%d end addr is %x\n", viterbi_mem_size, msd_mem_size, memory_ptr+ viterbi_mem_size+msd_mem_size); */ if (memory_ptr == NULL) { printf("msdhardfac: cannot malloc for memory_ptr\n"); exit(1); } } if (!memory_ptr) { printf("Failed memory request!\n"); exit(1); } viterbi_mem = memory_ptr; msd_mem = memory_ptr + viterbi_mem_size; llr = (float *) msd_mem; hardpoints = (char *) (msd_mem + 2 * N * sizeof(float)); lastiter = (char *) (msd_mem + 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2); infoout[0] = (char *) (msd_mem + 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2 + 2 * N * sizeof(char)); infoout[1] = 0; for (m = 1; m < no_of_levels; m++) { infoout[m] = infoout[m - 1] + (int) L1_real[m - 1] + (int) L2_real[m - 1] + 6 + (int) L1_imag[m - 1] + (int) L2_imag[m - 1] + 6; /* debugging pa0mbo printf("infoout[%d] = %p \n", m, infoout[m]); */ } memset(hardpoints, 0, 2 * N * sizeof(char)); /* choosing partitioning type: */ if (no_of_levels == 3) { if ((Lvspp != 0) && HMmix) { /* HMmix 64-QAM */ metric_real = partitioning[1]; metric_imag = partitioning[0]; rp_real[0] = (N - 12) - RY[(int) PL2_real[0]] * ((N - 12) / RY[(int) PL2_real[0]]); rp_real[1] = ((N - N1) - 12) - RY[(int) PL2_real[1]] * (((N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = ((N - N1) - 12) - RY[(int) PL2_real[2]] * (((N - N1) - 12) / RY[(int) PL2_real[2]]); rp_imag[0] = ((N - N1) - 12) - RY[(int) PL2_imag[0]] * (((N - N1) - 12) / RY[(int) PL2_imag[0]]); rp_imag[1] = ((N - N1) - 12) - RY[(int) PL2_imag[1]] * (((N - N1) - 12) / RY[(int) PL2_imag[1]]); rp_imag[2] = ((N - N1) - 12) - RY[(int) PL2_imag[2]] * (((N - N1) - 12) / RY[(int) PL2_imag[2]]); } else if (Lvspp != 0) { /* HMsym 64-QAM */ HMsym = 1; metric_real = partitioning[1]; metric_imag = partitioning[1]; rp_real[0] = (2 * N - 12) - RY[(int) PL2_real[0]] * ((2 * N - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = (2 * (N - N1) - 12) - RY[(int) PL2_real[2]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[2]]); } else { /* SM 64-QAM */ metric_real = partitioning[0]; metric_imag = partitioning[0]; rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = (2 * (N - N1) - 12) - RY[(int) PL2_real[2]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[2]]); }} else if (no_of_levels == 2) { /* SM 16-QAM */ rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); metric_real = partitioning[2]; metric_imag = partitioning[2]; } else { /* SM 4-QAM */ rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); metric_real = partitioning[3]; metric_imag = partitioning[3]; } if (!SDCorMSC) { rp_real[0] = -12; rp_real[1] = -12; rp_real[2] = -12; } if (Lvspp != 0) { L1_real[0] = 0; L2_real[0] = (double) Lvspp; } /* debugging pa0mbo printf("=== voor viterbi \n"); for (i=0; i < 2*N ; i++) { printf("hadpoints[%d] = %d \n",i, hardpoints[i]); } */ /* Multi-Stage Decoding: */ /* first decoding: */ PL1 = PL1_real; PL2 = PL2_real; L1 = L1_real; L2 = L2_real; rp = rp_real; first_metric = metric_real; first_received = received_real; hardpoints_ptr = hardpoints; /* debugging printf("msdhardfac: at start first decoding\n"); printf("PL1[0] = %g, PL2[0]= %g, L1_real[0]= %g, L2_real[0]=%g, L1[0]=%g, L2[0]= %g, rp[0]= %d\n", PL1[0], PL2[0], L1_real[0], L2_real[0], L1[0], L2[0], rp[0]); */ for (n = 0; n <= HMmix; n++) { for (level = 0; level < no_of_levels; level++) { metric = first_metric; received = first_received; for (m = 0; m < 2 - HMmix; m++) { /* for real and imaginary part */ for (sample_index = m; sample_index < (2 - HMmix) * N; sample_index += 2 - HMmix) { sample = (float) received[sample_index >> (1 - HMmix)]; /* extract real or imaginary part respectively */ closest_zero = fabs(sample - metric[(int) hardpoints_ptr[sample_index]]); /* printf("msdhardfac: index= %d sample = %g metric = %g closest_zero = %g \n", sample_index, sample, metric[hardpoints_ptr[sample_index]], closest_zero); pa0mbo */ for (subset_point = (0x1 << (level + 1)); subset_point < (0x1 << no_of_levels); subset_point += (0x1 << (level + 1))) { dist = fabs(sample - metric[hardpoints_ptr[sample_index] + subset_point]); if (dist < closest_zero) { closest_zero = dist; } } closest_one = fabs(sample - metric[hardpoints_ptr[sample_index] + (0x1 << level)]); /* printf("closest_one %g\n", closest_one); pa0mbo */ for (subset_point = (0x3 << level); subset_point < (0x1 << no_of_levels); subset_point += (0x1 << (level + 1))) { dist = fabs(sample - metric[hardpoints_ptr[sample_index] + subset_point]); if (dist < closest_one) { closest_one = dist; } } /* printf("final closest_zero=%g closest_one=%g\n", closest_zero, closest_one); pa0mbo */ #ifdef CONSIDERING_SNR SNR = (float) signal_to_noise_ratio[sample_index >> (1 - HMmix)]; llr[sample_index] = (closest_zero - closest_one) * SNR; /* printf("llr[%d] = %g\n", sample_index, llr[sample_index]); */ /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one) * SNR * SNR; */ #else /* */ llr[sample_index] = (closest_zero - closest_one); /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one); */ #endif /* */ } /* end loop sample_index */ metric = metric_imag; received = received_imag; } /* end loop m */ /* printf(" level %d HMsym %d HMmix %d N1 %d n %d\n", level, HMsym, HMmix, N1, n); printf("msdhardfac: (level || (!HMsym ..) = %d\n", (level || (!HMsym && (n || !HMmix)))* (2 - HMmix)*N1 ); printf("eerste viter PL1[0] %g PL2[0] %g L1[0] %g L2[0] %g L1_real[0] %g L2_real[0] %g rp[0] %d\n", PL1[0], PL2[0], L1[0], L2[0], L1_real[0], L2_real[0], rp[0]); for (i=0; i < 17 ; i++) printf("puncturing[6][%d] = %d\n", i, puncturing[6][i]); */ error = viterbi_decode(llr, (2 - HMmix) * N, (level || (!HMsym && (n || !HMmix))) * (2 - HMmix) * N1, puncturing[(int) PL1[level]], puncturing[(int) PL2[level]], tailpuncturing[rp[level] + 12], infoout[level] + n * ((int) L1_real[level] + (int) L2_real[level] + 6), hardpoints_ptr, level, Deinterleaver + (2 - HMmix) * N * level, (int) L1[level] + (int) L2[level] + 6, rp[level] + 12, viterbi_mem); /* debugging pa0mbo printf("=== na eerste viterbi \n"); for (i=0; i < 2*N ; i++) { printf("infoout[0][%d] = %d \n",i, infoout[0][i]); } */ if (error) { free(memory_ptr); printf("msdhardfac: Error in Viterbi decoder"); return 1; } } /* end loop level */ PL1 = PL1_imag; PL2 = PL2_imag; L1 = L1_imag; L2 = L2_imag; rp = rp_imag; first_metric = metric_imag; first_received = received_imag; hardpoints_ptr = hardpoints + N; } /* end loop over n */ diff = 1; iteration = 0; /* iterations: */ while (iteration < maxiter) { PL1 = PL1_real; PL2 = PL2_real; L1 = L1_real; L2 = L2_real; rp = rp_real; first_metric = metric_real; first_received = received_real; hardpoints_ptr = hardpoints; #ifdef ITER_BREAK memcpy(lastiter, hardpoints, 2 * N); #endif /* */ for (n = 0; n <= HMmix; n++) { for (level = 0; level < no_of_levels; level++) { metric = first_metric; received = first_received; for (m = 0; m < 2 - HMmix; m++) { /* for real and imaginary part */ for (sample_index = m; sample_index < (2 - HMmix) * N; sample_index += 2 - HMmix) { sample = (float) received[sample_index >> (1 - HMmix)]; /* extract real or imaginary part respectively */ closest_zero = fabs(sample - metric[hardpoints_ptr[sample_index] & ~(0x1 << level)]); closest_one = fabs(sample - metric[hardpoints_ptr[sample_index] | (0x1 << level)]); #ifdef CONSIDERING_SNR SNR = (float) signal_to_noise_ratio[sample_index >> (1 - HMmix)]; llr[sample_index] = (closest_zero - closest_one) * SNR; /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one) * SNR * SNR; */ #else /* */ llr[sample_index] = (closest_zero - closest_one); /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one); */ #endif /* */ } /* end loop over sample_index */ metric = metric_imag; received = received_imag; } /* end loop over m */ /* printf("Tweede viterbi PL1[0] %g PL2[0] %g L1[0] %g L2[0] %g L1_real[0] %g L2_real[0] %g rp[0] %d\n", PL1[0], PL2[0], L1[0], L2[0], L1_real[0], L2_real[0], rp[0]); */ error = viterbi_decode(llr, (2 - HMmix) * N, (level || (!HMsym && (n || !HMmix))) * (2 - HMmix) * N1, puncturing[(int) PL1[level]], puncturing[(int) PL2[level]], tailpuncturing[rp[level]], infoout[level] + n * ((int) L1_real[level] + (int) L2_real[level] + 6), hardpoints_ptr, level, Deinterleaver + (2 - HMmix) * N * level, (int) L1[level] + (int) L2[level] + 6, rp[level] + 12, viterbi_mem); if (error) { free(memory_ptr); printf("msdhardfac: Error in Viterbi decoder"); return 1; } #ifdef ITER_BREAK if (level == 0) { diff = 0; for (sample_index = 0;sample_index <((int)(((2 - HMmix) * N * sizeof(char)) / sizeof(int))); sample_index++) { diff += (((int *) hardpoints)[sample_index] ^ ((int *) lastiter)[sample_index]) != 0; } /*diff = memcmp (lastiter,hardpoints,2 * N); */ if (!diff) { break; } } #endif /* */ } /* for (level = 0; level < no_of_levels; level++) */ PL1 = PL1_imag; PL2 = PL2_imag; L1 = L1_imag; L2 = L2_imag; rp = rp_imag; first_metric = metric_imag; first_received = received_imag; hardpoints_ptr = hardpoints + N; } /* for (n = 0; n <= HMmix; n++) */ #ifdef ITER_BREAK if (!diff) { break; } #endif /* */ iteration++; } /* while (iteration < maxiter) */ /* Energy Dispersal */ no_of_bits = 0; for (level = (Lvspp != 0); level < no_of_levels; level++) { no_of_bits += (int) L1_real[level] + (int) L2_real[level]; } for (level = 0; level < no_of_levels; level++) { no_of_bits += (int) L1_imag[level] + (int) L2_imag[level]; } output_ptr = facdata; PRBS_INIT(PRBS_reg); n = 0; if (HMmix) { for (m = Lvspp + 6; m < Lvspp + 6 + (int) L1_imag[0]; m++) { output_ptr[n++] = (double) (infoout[0][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} for (level = (Lvspp != 0); level < no_of_levels; level++) { for (m = 0; m < (int) L1_real[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); } for (m = (int) L1_real[level] + (int) L2_real[level] + 6; m < (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} if (HMmix) { for (m = Lvspp + 6 + (int) L1_imag[0]; m < Lvspp + 6 + (int) L1_imag[0] + (int) L2_imag[0]; m++) { output_ptr[n++] = (double) (infoout[0][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} for (level = (Lvspp != 0); level < no_of_levels; level++) { for (m = (int) L1_real[level]; m < (int) L1_real[level] + (int) L2_real[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); } for (m = (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level]; m < (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level] + (int) L2_imag[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} PRBS_INIT(PRBS_reg); if (Lvspp != 0) { printf ("msdhardfac: There is a very strongly protected part, but no variable to put it into!"); } free(memory_ptr); return 0; } qsstv_8.2.12/qsstv/drmrx/msdhardmsc.cpp000664 001750 001750 00000047774 12440612574 020163 0ustar00jomajoma000000 000000 /* * changed filename to msdhardmsc.c * and added new interface to accomodate * own C-language interface instead of * Matlab interface * * almost fully copied from msd_hard.c * by Torsten Schorr Kaiserslautern 2004 * * Author of changes M.Bos - PA0MBO * Date Feb 21st 2009 */ #include #include #include #include #include /* #include "viterbi_decode.h" */ #include "msd_hard_sdc.h" #define ITER_BREAK #define CONSIDERING_SNR #ifdef CONSIDERING_SNR #define ARG_INDEX_OFFSET 1 #define NARGS_RHS_STR "9" #define NARGS_RHS 9 #else /* */ #define ARG_INDEX_OFFSET 0 #define NARGS_RHS_STR "8" #define NARGS_RHS 8 #endif /* */ #define STATES 64 #define PROGNAME "msd_hard" #define PRBS_INIT(reg) reg = 511; #define PRBS_BIT(reg) ((reg ^ (reg >> 4)) & 0x1) #define PRBS_SHIFT(reg) reg = (((reg ^ (reg >> 4)) & 0x1) << 8) | (reg >> 1) int viterbi_decode(float *, int, int, signed char *, signed char *, signed char *, char *, char *, int, int *, int, int, char *); int msdhardmsc(double *received_real, double *received_imag, int Lrxdata, double *snr, int N1, double *L, int rowdimL, int coldimL, int Lvspp, int *Deinterleaver, int *PL, int maxiter, int SDCorMSC, /*@out@ */ double *SPPhard, /*@out@ */ double *VSPPhard, double *iterations, double *calc_variance, double *noise_signal) { double *received, *first_received, *L1, *L2, L1_real[10], *L2_real, *L1_imag, *L2_imag; double *PL1, *PL2, PL1_real[10], *PL2_real, *PL1_imag, *PL2_imag, *output_ptr, L_dummy[3] = { 0, 0, 0 }; float *metric_real, *metric_imag, *metric, *first_metric, closest_one, closest_zero, sample, *llr, dist; double variance; char *memory_ptr, *viterbi_mem, *msd_mem, *hardpoints, *hardpoints_ptr, *lastiter, *infoout[3]; int m, n, N, no_of_levels, iteration, diff; int sample_index, rp_real[3], rp_imag[3], *rp, level, subset_point, no_of_bits, error, msd_mem_size, viterbi_mem_size; int PRBS_reg; int HMmix = 0, HMsym = 0; int i; #ifdef CONSIDERING_SNR double *signal_to_noise_ratio; float SNR; #endif /* */ /* new interface to C-language */ signal_to_noise_ratio = snr; no_of_levels = rowdimL; for (i = 0; i < rowdimL * coldimL; i++) { L1_real[i] = L[i]; /* debugging printf("L[%d] = %g , L1_real[%d] = %g\n", i, L[i], i, L1_real[i]); */ } L2_real = L1_real + no_of_levels; L1_imag = L_dummy; L2_imag = L_dummy; for (i = 0; i < coldimL * rowdimL; i++) /* pa0mbo 4 niet gebruiken later */ { PL1_real[i] = (double) PL[i]; /* printf("PL1_real[%d] = %g \n", i , PL1_real[i]); */ } PL2_real = PL1_real + no_of_levels; PL1_imag = PL2_real + no_of_levels; PL2_imag = PL1_imag + no_of_levels; /* pa0mbo will not be OK has to be checked !! will do for the moment */ /* debugging printf("PL1_real[0]= %g, PL1_real[1]= %g, PL2_real[0]= %g, PL2_real[1]= %g, PL1_imag[0]= %g, PL2_imag[0]= %g\n", PL1_real[0], PL1_real[1], PL2_real[0], PL2_real[1], PL1_imag[0], PL2_imag[0]); */ SDCorMSC = ((0 - SDCorMSC) != 0); /* debugging printf("SDCorMSC = %d\n", SDCorMSC); */ if (Lrxdata < 20) { printf("msdhardmsc: length rxdata should be >= 20\n"); exit(1); } N = Lrxdata; if (N < 20) { printf("msdhardmsc: N has to be >= 20!\n"); exit(1); } if ((N1 < 0) || (N1 > N - 20)) { printf("msdhardmsc: N1 has to be >= 0!\n"); exit(1); } if (Lvspp < 0) { printf("msdhardmsc: Lvspp has to be >= 0!\n"); exit(1); } if (maxiter < 0) { printf("msdhardmsc: maxiter must not be negativ."); exit(1); } if (HMmix && (Lvspp == 0)) { printf("msdhardmsc: HMmix requires Lvspp > 0."); exit(1); } /* printf("start mem alloc \n "); printf("N= %d, no_of_levels= %d\n", N, no_of_levels); */ /* memory allocation and initialization: */ no_of_bits = 0; for (level = 0; level < no_of_levels; level++) { no_of_bits += (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level] + (int) L2_imag[level] + 6; /* printf(" --- level %d L1real %d L2real %d L1imga %d L2imag %d\n", level, (int)L1_real[level], (int)L2_real[level], (int)L1_imag[level], (int)L2_imag[level]); */ } msd_mem_size = 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2 * N * sizeof(char) + no_of_bits * sizeof(char); viterbi_mem_size = STATES * sizeof(float) + STATES * sizeof(float) + 2 * N * STATES * sizeof(char); /* printf("msdhardmsc: viterbi_mem_size is %d STATES is %d\n", viterbi_mem_size, STATES); */ if (received_imag == NULL) { memory_ptr = (char *) malloc(viterbi_mem_size + msd_mem_size + N * sizeof(double) + 2); received_imag = (double *) (memory_ptr + viterbi_mem_size + msd_mem_size); memset(received_imag, 0, N * sizeof(double)); } else { memory_ptr = (char *) malloc(viterbi_mem_size + msd_mem_size + 2); /* printf("msdhardmsc: debugging memory_ptr alloc succeeded viterbi_size = %d mds_size=%d end addr is %x\n", viterbi_mem_size, msd_mem_size, memory_ptr+ viterbi_mem_size+msd_mem_size); */ if (memory_ptr == NULL) { printf("msdhardmsc: cannot malloc for memory_ptr\n"); exit(1); } } if (!memory_ptr) { printf("Failed memory request!\n"); exit(1); } viterbi_mem = memory_ptr; msd_mem = memory_ptr + viterbi_mem_size; llr = (float *) msd_mem; hardpoints = (char *) (msd_mem + 2 * N * sizeof(float)); lastiter = (char *) (msd_mem + 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2); infoout[0] = (char *) (msd_mem + 2 * N * sizeof(float) + 2 * N * sizeof(char) + 2 + 2 * N * sizeof(char)); infoout[1] = 0; for (m = 1; m < no_of_levels; m++) { infoout[m] = infoout[m - 1] + (int) L1_real[m - 1] + (int) L2_real[m - 1] + 6 + (int) L1_imag[m - 1] + (int) L2_imag[m - 1] + 6; /* debugging pa0mbo printf("infoout[%d] = %p \n", m, infoout[m]); */ } memset(hardpoints, 0, 2 * N * sizeof(char)); /* choosing partitioning type: */ if (no_of_levels == 3) { if ((Lvspp != 0) && HMmix) { /* HMmix 64-QAM */ metric_real = partitioning[1]; metric_imag = partitioning[0]; rp_real[0] = (N - 12) - RY[(int) PL2_real[0]] * ((N - 12) / RY[(int) PL2_real[0]]); rp_real[1] = ((N - N1) - 12) - RY[(int) PL2_real[1]] * (((N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = ((N - N1) - 12) - RY[(int) PL2_real[2]] * (((N - N1) - 12) / RY[(int) PL2_real[2]]); rp_imag[0] = ((N - N1) - 12) - RY[(int) PL2_imag[0]] * (((N - N1) - 12) / RY[(int) PL2_imag[0]]); rp_imag[1] = ((N - N1) - 12) - RY[(int) PL2_imag[1]] * (((N - N1) - 12) / RY[(int) PL2_imag[1]]); rp_imag[2] = ((N - N1) - 12) - RY[(int) PL2_imag[2]] * (((N - N1) - 12) / RY[(int) PL2_imag[2]]); } else if (Lvspp != 0) { /* HMsym 64-QAM */ HMsym = 1; metric_real = partitioning[1]; metric_imag = partitioning[1]; rp_real[0] = (2 * N - 12) - RY[(int) PL2_real[0]] * ((2 * N - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = (2 * (N - N1) - 12) - RY[(int) PL2_real[2]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[2]]); } else { /* SM 64-QAM */ metric_real = partitioning[0]; metric_imag = partitioning[0]; rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); rp_real[2] = (2 * (N - N1) - 12) - RY[(int) PL2_real[2]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[2]]); }} else if (no_of_levels == 2) { /* SM 16-QAM */ rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); rp_real[1] = (2 * (N - N1) - 12) - RY[(int) PL2_real[1]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[1]]); metric_real = partitioning[2]; metric_imag = partitioning[2]; /* printf("SM 16 QAM\n"); */ } else { /* SM 4-QAM */ rp_real[0] = (2 * (N - N1) - 12) - RY[(int) PL2_real[0]] * ((2 * (N - N1) - 12) / RY[(int) PL2_real[0]]); metric_real = partitioning[3]; metric_imag = partitioning[3]; } if (!SDCorMSC) { rp_real[0] = -12; rp_real[1] = -12; rp_real[2] = -12; } if (Lvspp != 0) { L1_real[0] = 0; L2_real[0] = (double) Lvspp; } /* debugging pa0mbo printf("=== voor viterbi \n"); for (i=0; i < 2*N ; i++) { printf("hardpoints[%d] = %d \n",i, hardpoints[i]); } */ /* Multi-Stage Decoding: */ /* first decoding: */ PL1 = PL1_real; PL2 = PL2_real; L1 = L1_real; L2 = L2_real; rp = rp_real; first_metric = metric_real; first_received = received_real; hardpoints_ptr = hardpoints; /* debugging printf("msdhardmsc: at start first decoding\n"); printf("PL1[0] = %g, PL2[0]= %g, L1_real[0]= %g, L2_real[0]=%g, L1[0]=%g, L2[0]= %g, rp[0]= %d\n", PL1[0], PL2[0], L1_real[0], L2_real[0], L1[0], L2[0], rp[0]); */ for (n = 0; n <= HMmix; n++) { for (level = 0; level < no_of_levels; level++) { metric = first_metric; received = first_received; for (m = 0; m < 2 - HMmix; m++) { /* for real and imaginary part */ for (sample_index = m; sample_index < (2 - HMmix) * N; sample_index += 2 - HMmix) { sample = (float) received[sample_index >> (1 - HMmix)]; /* extract real or imaginary part respectively */ closest_zero = fabs(sample - metric[(int) hardpoints_ptr[sample_index]]); /* printf("msdhardmsc: index= %d sample = %g metric = %g closest_zero = %g \n", sample_index, sample, metric[hardpoints_ptr[sample_index]], closest_zero); pa0mbo */ for (subset_point = (0x1 << (level + 1)); subset_point < (0x1 << no_of_levels); subset_point += (0x1 << (level + 1))) { dist = fabs(sample - metric[hardpoints_ptr[sample_index] + subset_point]); if (dist < closest_zero) { closest_zero = dist; } } closest_one = fabs(sample - metric[hardpoints_ptr[sample_index] + (0x1 << level)]); /* printf("closest_one %g\n", closest_one); pa0mbo */ for (subset_point = (0x3 << level); subset_point < (0x1 << no_of_levels); subset_point += (0x1 << (level + 1))) { dist = fabs(sample - metric[hardpoints_ptr[sample_index] + subset_point]); if (dist < closest_one) { closest_one = dist; } } /* printf("final closest_zero=%g closest_one=%g\n", closest_zero, closest_one); pa0mbo */ #ifdef CONSIDERING_SNR SNR = (float) signal_to_noise_ratio[sample_index >> (1 - HMmix)]; llr[sample_index] = (closest_zero - closest_one) * SNR; /* printf("llr[%d] = %g\n", sample_index, llr[sample_index]); */ /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one) * SNR * SNR; */ #else /* */ llr[sample_index] = (closest_zero - closest_one); /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one); */ #endif /* */ } /* end loop sample_index */ metric = metric_imag; received = received_imag; } /* end loop m */ /* printf(" level %d HMsym %d HMmix %d N1 %d n %d\n", level, HMsym, HMmix, N1, n); printf("msdhardmsc: (level || (!HMsym ..) = %d\n", (level || (!HMsym && (n || !HMmix)))* (2 - HMmix)*N1 ); printf("eerste viter PL1[0] %g PL2[0] %g L1[0] %g L2[0] %g L1_real[0] %g L2_real[0] %g rp[0] %d\n", PL1[0], PL2[0], L1[0], L2[0], L1_real[0], L2_real[0], rp[0]); */ /* for (i=0; i < 17 ; i++) printf("puncturing[6][%d] = %d\n", i, puncturing[6][i]); printf("level %d rp[level] %d \n", level, rp[level]); printf("tailpuncturing[... ] = %p\n", tailpuncturing[rp[level]]); for (i=0; i < 13 ; i++) printf("inhoud is %d ", tailpuncturing[rp[level]][i]); */ error = viterbi_decode(llr, (2 - HMmix) * N, (level || (!HMsym && (n || !HMmix))) * (2 - HMmix) * N1, puncturing[(int) PL1[level]], puncturing[(int) PL2[level]], tailpuncturing[rp[level]], infoout[level] + n * ((int) L1_real[level] + (int) L2_real[level] + 6), hardpoints_ptr, level, Deinterleaver + (2 - HMmix) * N * level, (int) L1[level] + (int) L2[level] + 6, rp[level] + 12, viterbi_mem); /* debugging pa0mbo printf("=== na eerste viterbi \n"); for (i=0; i < 2*N ; i++) { printf("infoout[0][%d] = %d \n",i, infoout[0][i]); } */ if (error) { free(memory_ptr); printf("msdhardmsc: Error in Viterbi decoder"); return 1; } } /* end loop level */ PL1 = PL1_imag; PL2 = PL2_imag; L1 = L1_imag; L2 = L2_imag; rp = rp_imag; first_metric = metric_imag; first_received = received_imag; hardpoints_ptr = hardpoints + N; } /* end loop over n */ diff = 1; iteration = 0; /* iterations: */ while (iteration < maxiter) { PL1 = PL1_real; PL2 = PL2_real; L1 = L1_real; L2 = L2_real; rp = rp_real; first_metric = metric_real; first_received = received_real; hardpoints_ptr = hardpoints; #ifdef ITER_BREAK memcpy(lastiter, hardpoints, 2 * N); #endif /* */ for (n = 0; n <= HMmix; n++) { for (level = 0; level < no_of_levels; level++) { metric = first_metric; received = first_received; for (m = 0; m < 2 - HMmix; m++) { /* for real and imaginary part */ for (sample_index = m; sample_index < (2 - HMmix) * N; sample_index += 2 - HMmix) { sample = (float) received[sample_index >> (1 - HMmix)]; /* extract real or imaginary part respectively */ closest_zero = fabs(sample - metric[hardpoints_ptr[sample_index] & ~(0x1 << level)]); closest_one = fabs(sample - metric[hardpoints_ptr[sample_index] | (0x1 << level)]); #ifdef CONSIDERING_SNR SNR = (float) signal_to_noise_ratio[sample_index >> (1 - HMmix)]; llr[sample_index] = (closest_zero - closest_one) * SNR; /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one) * SNR * SNR; */ #else /* */ llr[sample_index] = (closest_zero - closest_one); /* llr[sample_index] = (closest_zero*closest_zero - closest_one*closest_one); */ #endif /* */ } /* end loop over sample_index */ metric = metric_imag; received = received_imag; } /* end loop over m */ /* printf("Tweede viterbi PL1[0] %g PL2[0] %g L1[0] %g L2[0] %g L1_real[0] %g L2_real[0] %g rp[0] %d\n", PL1[0], PL2[0], L1[0], L2[0], L1_real[0], L2_real[0], rp[0]); */ error = viterbi_decode(llr, (2 - HMmix) * N, (level || (!HMsym && (n || !HMmix))) * (2 - HMmix) * N1, puncturing[(int) PL1[level]], puncturing[(int) PL2[level]], tailpuncturing[rp[level]], infoout[level] + n * ((int) L1_real[level] + (int) L2_real[level] + 6), hardpoints_ptr, level, Deinterleaver + (2 - HMmix) * N * level, (int) L1[level] + (int) L2[level] + 6, rp[level] + 12, viterbi_mem); if (error) { free(memory_ptr); printf("msdhardmsc: Error in Viterbi decoder"); return 1; } #ifdef ITER_BREAK if (level == 0) { diff = 0; for (sample_index = 0;sample_index <(int)((2 - HMmix) * N * sizeof(char) / sizeof(int));sample_index++) { diff += (((int *) hardpoints)[sample_index] ^ ((int *) lastiter)[sample_index]) != 0; } /*diff = memcmp (lastiter,hardpoints,2 * N); */ if (!diff) { break; } } #endif /* */ } /* for (level = 0; level < no_of_levels; level++) */ PL1 = PL1_imag; PL2 = PL2_imag; L1 = L1_imag; L2 = L2_imag; rp = rp_imag; first_metric = metric_imag; first_received = received_imag; hardpoints_ptr = hardpoints + N; } /* for (n = 0; n <= HMmix; n++) */ #ifdef ITER_BREAK if (!diff) { break; } #endif /* */ iteration++; } /* while (iteration < maxiter) */ /* Energy Dispersal */ no_of_bits = 0; for (level = (Lvspp != 0); level < no_of_levels; level++) { no_of_bits += (int) L1_real[level] + (int) L2_real[level]; } for (level = 0; level < no_of_levels; level++) { no_of_bits += (int) L1_imag[level] + (int) L2_imag[level]; } output_ptr = SPPhard; PRBS_INIT(PRBS_reg); n = 0; if (HMmix) { for (m = Lvspp + 6; m < Lvspp + 6 + (int) L1_imag[0]; m++) { output_ptr[n++] = (double) (infoout[0][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} /* printf("msdhardmsc: 1e n %d\n", n); */ for (level = (Lvspp != 0); level < no_of_levels; level++) { for (m = 0; m < (int) L1_real[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); } /* printf("msdhardmsc: 2a n %d\n", n); */ for (m = (int) L1_real[level] + (int) L2_real[level] + 6; m < (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} /* printf("msdhardmsc: 2b n %d\n", n); */ if (HMmix) { for (m = Lvspp + 6 + (int) L1_imag[0]; m < Lvspp + 6 + (int) L1_imag[0] + (int) L2_imag[0]; m++) { output_ptr[n++] = (double) (infoout[0][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} /* printf("msdhardmsc: 3e n %d\n", n); */ for (level = (Lvspp != 0); level < no_of_levels; level++) { for (m = (int) L1_real[level]; m < (int) L1_real[level] + (int) L2_real[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); } for (m = (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level]; m < (int) L1_real[level] + (int) L2_real[level] + 6 + (int) L1_imag[level] + (int) L2_imag[level]; m++) { output_ptr[n++] = (double) (infoout[level][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); }} /* printf("msdhardmsc: 4e n %d\n", n); */ PRBS_INIT(PRBS_reg); if (Lvspp != 0) { printf ("msdhardmsc: There is a very strongly protected part, but no variable to put it into!"); } no_of_bits = Lvspp; output_ptr = VSPPhard; for (m = 0; m < Lvspp; m++) { output_ptr[m] = (double) (infoout[0][m] ^ PRBS_BIT(PRBS_reg)); PRBS_SHIFT(PRBS_reg); } output_ptr = iterations; output_ptr[0] = (double) iteration; output_ptr = calc_variance; variance = 0.0; for (sample_index = 0; sample_index < N; sample_index++) { sample = (float) received_real[sample_index]; /* extract real part respectively */ dist = (sample - metric_real[(int) hardpoints[(2 - HMmix) * sample_index]]); variance += (double) dist *(double) dist; sample = (float) received_imag[sample_index]; /* extract imaginary part respectively */ dist = (sample - metric_imag[(int) hardpoints[HMmix * (N - 1) + (2 - HMmix) * sample_index + 1]]); variance += (double) dist *(double) dist; } output_ptr[0] = variance / ((double) N); output_ptr = noise_signal; for (sample_index = 0; sample_index < N; sample_index++) { sample = (float) received_real[sample_index]; /* extract real part */ output_ptr[sample_index * 2] = (sample - metric_real[(int) hardpoints[(2 - HMmix) * sample_index]]); sample = (float) received_imag[sample_index]; /* extract imaginary part */ output_ptr[2 * sample_index + 1] = (sample - metric_imag[(int) hardpoints[HMmix * (N - 1) + (2 - HMmix) * sample_index + 1]]); } free(memory_ptr); return n; } qsstv_8.2.12/qsstv/drmrx/newfft.cpp000664 001750 001750 00000012727 12440612574 017315 0ustar00jomajoma000000 000000 #include #include /****************************************************************************** * * MiXViews - an X window system based sound & data editor/processor * * Copyright (c) 1993, 1994 Regents of the University of California * * Author: Douglas Scott * Date: December 13, 1994 * * Permission to use, copy and modify this software and its documentation * for research and/or educational purposes and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. The author reserves the right to distribute this * software and its documentation. The University of California and the author * make no representations about the suitability of this software for any * purpose, and in no event shall University of California be liable for any * damage, loss of data, or profits resulting from its use. * It is provided "as is" without express or implied warranty. * ******************************************************************************/ void rfft(float *, int, int); void cfft(float *, int, int); static double twopi = M_PI * 2.0; static double pi = M_PI; /* If forward is true, rfft replaces 2*N real data points in buf with N complex values representing the positive frequency half of their Fourier spectrum, with *(buf+1) replaced with the real part of the Nyquist frequency value. If forward is false, rfft expects buf to contain a positive frequency spectrum arranged as before, and replaces it with 2*N real values. N MUST be a power of 2. */ void rfft(float *buf, int N2, int forward) { float c2, h1r, h1i, h2r, h2i, temp; float br, bi; float theta = (float) (pi / N2); float wr = 1.; float wi = 0.; float c1 = 0.5; float wpr; float wpi; int N2p1; int i, i1, i2, i3, i4; /* debugging pa0mbo printf("N2 is %d\n",N2); */ if (forward == 1) { c2 = -0.5; cfft(buf, N2, forward); /* debugging pa0mbo printf("na cfft\n"); */ br = *buf; bi = *(buf + 1); /* debuging pa0mbo printf(" na br ni = \n"); */ } else { c2 = 0.5; theta = -theta; br = *(buf + 1); bi = 0.; *(buf + 1) = 0.; } wpr = (float) (-2. * pow(sin(0.5 * theta), 2.)); wpi = (float) sin(theta); N2p1 = (N2 << 1) + 1; /* debugging pa0mbo printf(" N2p1 is %d\n",N2p1); */ for (i = 0; i <= N2 >> 1; i++) { i1 = i << 1; i2 = i1 + 1; i3 = N2p1 - i2; i4 = i3 + 1; if (i == 0) { h1r = c1 * (*(buf + i1) + br); h1i = c1 * (*(buf + i2) - bi); h2r = -c2 * (*(buf + i2) + bi); h2i = c2 * (*(buf + i1) - br); *(buf + i1) = h1r + (wr * h2r) - (wi * h2i); *(buf + i2) = h1i + (wr * h2i) + (wi * h2r); br = h1r - (wr * h2r) + (wi * h2i); bi = -h1i + (wr * h2i) + (wi * h2r); } else { h1r = c1 * (*(buf + i1) + *(buf + i3)); h1i = c1 * (*(buf + i2) - *(buf + i4)); h2r = -c2 * (*(buf + i2) + *(buf + i4)); h2i = c2 * (*(buf + i1) - *(buf + i3)); *(buf + i1) = h1r + wr * h2r - wi * h2i; *(buf + i2) = h1i + wr * h2i + wi * h2r; *(buf + i3) = h1r - wr * h2r + wi * h2i; *(buf + i4) = -h1i + wr * h2i + wi * h2r; } wr = ((temp = wr) * wpr) - (wi * wpi) + wr; wi = (wi * wpr) + (temp * wpi) + wi; } if (forward == 1) *(buf + 1) = br; else cfft(buf, N2, forward); } /* cfft replaces float array x containing NC complex values (2*NC float values alternating real, imagininary, etc.) by its Fourier transform if forward is true, or by its inverse Fourier transform if forward is false, using a recursive Fast Fourier transform method due to Danielson and Lanczos. NC MUST be a power of 2. */ void bitreverse(float *, int); void cfft(float *buf, int N2, int forward) { int delta; int ND = N2 << 1; int mmax; float theta, wpr, wpi, wr, wi; float rtemp, itemp; int i, j, m; float scale; register float *bi, *be; bitreverse(buf, ND); for (mmax = 2; mmax < ND; mmax = delta) { delta = mmax << 1; theta = (float) (twopi / ((forward == 1) ? mmax : -mmax)); wpr = (float) (-2. * pow(sin(0.5 * theta), 2.)); wpi = (float) sin(theta); wr = 1.; wi = 0.; for (m = 0; m < mmax; m += 2) { for (i = m; i < ND; i += delta) { j = i + mmax; rtemp = (wr * *(buf + j)) - (wi * *(buf + j + 1)); itemp = (wr * *(buf + j + 1)) + (wi * *(buf + j)); *(buf + j) = *(buf + i) - rtemp; *(buf + j + 1) = *(buf + i + 1) - itemp; *(buf + i) += rtemp; *(buf + i + 1) += itemp; } wr = ((rtemp = wr) * wpr) - (wi * wpi) + wr; wi = (wi * wpr) + (rtemp * wpi) + wi; } } /* scale output */ /* scale = forward ? 1./ND : 2.; this is the original */ scale = (float) ((forward == 1) ? 1.0 : 1.0 / ND); if ((fabs(scale) - 1.0) < DBL_EPSILON) { bi = buf; be = buf + ND; while (bi < be) *bi++ *= scale; } } /* bitreverse places float array x containing N/2 complex values into bit-reversed order */ void bitreverse(float *buf, int N) { int i, j, m; for (i = j = 0; i < N; i += 2, j += m) { if (j > i) { float rtemp = *(buf + j); /* complex exchange */ float itemp = *(buf + j + 1); *(buf + j) = *(buf + i); *(buf + j + 1) = *(buf + i + 1); *(buf + i) = rtemp; *(buf + i + 1) = itemp; } for (m = N >> 1; m >= 2 && j >= m; m >>= 1) j -= m; } } qsstv_8.2.12/qsstv/drmrx/nrutil.cpp000664 001750 001750 00000042766 12440612574 017347 0ustar00jomajoma000000 000000 #if defined(__STDC__) || defined(ANSI) || defined(NRANSI) /* ANSI */ #include #include #include #define NR_END 1 #define FREE_ARG char* void nrerror(const char *error_text) /* Numerical Recipes standard error handler */ { fprintf(stderr, "Numerical Recipes run-time error...\n"); fprintf(stderr, "%s\n", error_text); fprintf(stderr, "...now exiting to system...\n"); exit(1); } // allocate a float vector with subscript range v[nl..nh] float *fvector(long nl, long nh) { float *v; v = (float *) malloc((size_t) ((nh - nl + 1 + NR_END) * sizeof(float))); if (!v) nrerror("allocation failure in vector()"); return v - nl + NR_END; } // allocate an int vector with subscript range v[nl..nh] int *ivector(long nl, long nh) { int *v; v = (int *) malloc((size_t) ((nh - nl + 1 + NR_END) * sizeof(int))); if (!v) nrerror("allocation failure in ivector()"); return v - nl + NR_END; } // allocate an unsigned char vector with subscript range v[nl..nh] unsigned char *cvector(long nl, long nh) { unsigned char *v; v = (unsigned char *) malloc((size_t) ((nh - nl + 1 + NR_END) * sizeof(unsigned char))); if (!v) nrerror("allocation failure in cvector()"); return v - nl + NR_END; } // allocate an unsigned long vector with subscript range v[nl..nh] unsigned long *lvector(long nl, long nh) { unsigned long *v; v = (unsigned long *) malloc((size_t) ((nh - nl + 1 + NR_END) * sizeof(long))); if (!v) nrerror("allocation failure in lvector()"); return v - nl + NR_END; } // allocate a double vector with subscript range v[nl..nh] double *dvector(long nl, long nh) { double *v; v = (double *) malloc((size_t) ((nh - nl + 1 + NR_END) * sizeof(double))); if (!v) nrerror("allocation failure in dvector()"); return v - nl + NR_END; } // allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] float **matrix(long nrl, long nrh, long ncl, long nch) { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; float **m; /* allocate pointers to rows */ m = (float **) malloc((size_t) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (float *) malloc((size_t) ((nrow * ncol + NR_END) * sizeof(float))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } // allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] double **dmatrix(long nrl, long nrh, long ncl, long nch) { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; double **m; /* allocate pointers to rows */ m = (double **) malloc((size_t) ((nrow + NR_END) * sizeof(double *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (double *) malloc((size_t) ((nrow * ncol + NR_END) * sizeof(double))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } // allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] int **imatrix(long nrl, long nrh, long ncl, long nch) { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; int **m; /* allocate pointers to rows */ m = (int **) malloc((size_t) ((nrow + NR_END) * sizeof(int *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (int *) malloc((size_t) ((nrow * ncol + NR_END) * sizeof(int))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long ,long newrl, long newcl) /* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ { long i, j, nrow = oldrh - oldrl + 1, ncol = oldcl - newcl; float **m; /* allocate array of pointers to rows */ m = (float **) malloc((size_t) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure in submatrix()"); m += NR_END; m -= newrl; /* set pointers to rows */ for (i = oldrl, j = newrl; i <= oldrh; i++, j++) m[j] = a[i] + ncol; /* return pointer to array of pointers to rows */ return m; } float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch) /* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 and ncol=nch-ncl+1. The routine should be called with the address &a[0][0] as the first argument. */ { long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; float **m; /* allocate pointers to rows */ m = (float **) malloc((size_t) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure in convert_matrix()"); m += NR_END; m -= nrl; /* set pointers to rows */ m[nrl] = a - ncl; for (i = 1, j = nrl + 1; i < nrow; i++, j++) m[j] = m[j - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh) /* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ { long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1, ndep = ndh - ndl + 1; float ***t; /* allocate pointers to pointers to rows */ t = (float ***) malloc((size_t) ((nrow + NR_END) * sizeof(float **))); if (!t) nrerror("allocation failure 1 in f3tensor()"); t += NR_END; t -= nrl; /* allocate pointers to rows and set pointers to them */ t[nrl] = (float **) malloc((size_t) ((nrow * ncol + NR_END) * sizeof(float *))); if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()"); t[nrl] += NR_END; t[nrl] -= ncl; /* allocate rows and set pointers to them */ t[nrl][ncl] = (float *) malloc((size_t) ((nrow * ncol * ndep + NR_END) * sizeof(float))); if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()"); t[nrl][ncl] += NR_END; t[nrl][ncl] -= ndl; for (j = ncl + 1; j <= nch; j++) t[nrl][j] = t[nrl][j - 1] + ndep; for (i = nrl + 1; i <= nrh; i++) { t[i] = t[i - 1] + ncol; t[i][ncl] = t[i - 1][ncl] + ncol * ndep; for (j = ncl + 1; j <= nch; j++) t[i][j] = t[i][j - 1] + ndep; } /* return pointer to array of pointers to rows */ return t; } void free_fvector(float *v, long nl, long ) /* free a float vector allocated with vector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_ivector(int *v, long nl, long ) /* free an int vector allocated with ivector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_cvector(unsigned char *v, long nl, long ) /* free an unsigned char vector allocated with cvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_lvector(unsigned long *v, long nl, long ) /* free an unsigned long vector allocated with lvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_dvector(double *v, long nl, long ) /* free a double vector allocated with dvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_matrix(float **m, long nrl, long , long ncl, long ) /* free a float matrix allocated by matrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_dmatrix(double **m, long nrl, long , long ncl, long ) /* free a double matrix allocated by dmatrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_imatrix(int **m, long nrl, long , long ncl, long ) /* free an int matrix allocated by imatrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_submatrix(float **b, long nrl, long , long , long ) /* free a submatrix allocated by submatrix() */ { free((FREE_ARG) (b + nrl - NR_END)); } void free_convert_matrix(float **b, long nrl, long , long , long ) /* free a matrix allocated by convert_matrix() */ { free((FREE_ARG) (b + nrl - NR_END)); } void free_f3tensor(float ***t, long nrl, long , long ncl, long , long ndl,long ) /* free a float f3tensor allocated by f3tensor() */ { free((FREE_ARG) (t[nrl][ncl] + ndl - NR_END)); free((FREE_ARG) (t[nrl] + ncl - NR_END)); free((FREE_ARG) (t + nrl - NR_END)); } #else /* ANSI */ /* traditional - K&R */ #include #define NR_END 1 #define FREE_ARG char* void nrerror(error_text) char error_text[]; /* Numerical Recipes standard error handler */ { void exit(); fprintf(stderr, "Numerical Recipes run-time error...\n"); fprintf(stderr, "%s\n", error_text); fprintf(stderr, "...now exiting to system...\n"); exit(1); } float *vector(nl, nh) long nh, nl; /* allocate a float vector with subscript range v[nl..nh] */ { float *v; v = (float *) malloc((unsigned int) ((nh - nl + 1 + NR_END) * sizeof(float))); if (!v) nrerror("allocation failure in vector()"); return v - nl + NR_END; } int *ivector(nl, nh) long nh, nl; /* allocate an int vector with subscript range v[nl..nh] */ { int *v; v = (int *) malloc((unsigned int) ((nh - nl + 1 + NR_END) * sizeof(int))); if (!v) nrerror("allocation failure in ivector()"); return v - nl + NR_END; } unsigned char *cvector(nl, nh) long nh, nl; /* allocate an unsigned char vector with subscript range v[nl..nh] */ { unsigned char *v; v = (unsigned char *) malloc((unsigned int) ((nh - nl + 1 + NR_END) * sizeof(unsigned char))); if (!v) nrerror("allocation failure in cvector()"); return v - nl + NR_END; } unsigned long *lvector(nl, nh) long nh, nl; /* allocate an unsigned long vector with subscript range v[nl..nh] */ { unsigned long *v; v = (unsigned long *) malloc((unsigned int) ((nh - nl + 1 + NR_END) * sizeof(long))); if (!v) nrerror("allocation failure in lvector()"); return v - nl + NR_END; } double *dvector(nl, nh) long nh, nl; /* allocate a double vector with subscript range v[nl..nh] */ { double *v; v = (double *) malloc((unsigned int) ((nh - nl + 1 + NR_END) * sizeof(double))); if (!v) nrerror("allocation failure in dvector()"); return v - nl + NR_END; } float **matrix(nrl, nrh, ncl, nch) long nch, ncl, nrh, nrl; /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; float **m; /* allocate pointers to rows */ m = (float **) malloc((unsigned int) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (float *) malloc((unsigned int) ((nrow * ncol + NR_END) * sizeof(float))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } double **dmatrix(nrl, nrh, ncl, nch) long nch, ncl, nrh, nrl; /* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; double **m; /* allocate pointers to rows */ m = (double **) malloc((unsigned int) ((nrow + NR_END) * sizeof(double *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (double *) malloc((unsigned int) ((nrow * ncol + NR_END) * sizeof(double))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } int **imatrix(nrl, nrh, ncl, nch) long nch, ncl, nrh, nrl; /* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; int **m; /* allocate pointers to rows */ m = (int **) malloc((unsigned int) ((nrow + NR_END) * sizeof(int *))); if (!m) nrerror("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl] = (int *) malloc((unsigned int) ((nrow * ncol + NR_END) * sizeof(int))); if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } float **submatrix(a, oldrl, oldrh, oldcl, oldch, newrl, newcl) float **a; long newcl, newrl, oldch, oldcl, oldrh, oldrl; /* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ { long i, j, nrow = oldrh - oldrl + 1, ncol = oldcl - newcl; float **m; /* allocate array of pointers to rows */ m = (float **) malloc((unsigned int) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure in submatrix()"); m += NR_END; m -= newrl; /* set pointers to rows */ for (i = oldrl, j = newrl; i <= oldrh; i++, j++) m[j] = a[i] + ncol; /* return pointer to array of pointers to rows */ return m; } float **convert_matrix(a, nrl, nrh, ncl, nch) float *a; long nch, ncl, nrh, nrl; /* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 and ncol=nch-ncl+1. The routine should be called with the address &a[0][0] as the first argument. */ { long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; float **m; /* allocate pointers to rows */ m = (float **) malloc((unsigned int) ((nrow + NR_END) * sizeof(float *))); if (!m) nrerror("allocation failure in convert_matrix()"); m += NR_END; m -= nrl; /* set pointers to rows */ m[nrl] = a - ncl; for (i = 1, j = nrl + 1; i < nrow; i++, j++) m[j] = m[j - 1] + ncol; /* return pointer to array of pointers to rows */ return m; } float ***f3tensor(nrl, nrh, ncl, nch, ndl, ndh) long nch, ncl, ndh, ndl, nrh, nrl; /* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ { long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1, ndep = ndh - ndl + 1; float ***t; /* allocate pointers to pointers to rows */ t = (float ***) malloc((unsigned int) ((nrow + NR_END) * sizeof(float **))); if (!t) nrerror("allocation failure 1 in f3tensor()"); t += NR_END; t -= nrl; /* allocate pointers to rows and set pointers to them */ t[nrl] = (float **) malloc((unsigned int) ((nrow * ncol + NR_END) * sizeof(float *))); if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()"); t[nrl] += NR_END; t[nrl] -= ncl; /* allocate rows and set pointers to them */ t[nrl][ncl] = (float *) malloc((unsigned int) ((nrow * ncol * ndep + NR_END) * sizeof(float))); if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()"); t[nrl][ncl] += NR_END; t[nrl][ncl] -= ndl; for (j = ncl + 1; j <= nch; j++) t[nrl][j] = t[nrl][j - 1] + ndep; for (i = nrl + 1; i <= nrh; i++) { t[i] = t[i - 1] + ncol; t[i][ncl] = t[i - 1][ncl] + ncol * ndep; for (j = ncl + 1; j <= nch; j++) t[i][j] = t[i][j - 1] + ndep; } /* return pointer to array of pointers to rows */ return t; } void free_vector(v, nl, nh) float *v; long nh, nl; /* free a float vector allocated with vector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_ivector(v, nl, nh) int *v; long nh, nl; /* free an int vector allocated with ivector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_cvector(v, nl, nh) long nh, nl; unsigned char *v; /* free an unsigned char vector allocated with cvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_lvector(v, nl, nh) long nh, nl; unsigned long *v; /* free an unsigned long vector allocated with lvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_dvector(v, nl, nh) double *v; long nh, nl; /* free a double vector allocated with dvector() */ { free((FREE_ARG) (v + nl - NR_END)); } void free_matrix(m, nrl, nrh, ncl, nch) float **m; long nch, ncl, nrh, nrl; /* free a float matrix allocated by matrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_dmatrix(m, nrl, nrh, ncl, nch) double **m; long nch, ncl, nrh, nrl; /* free a double matrix allocated by dmatrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_imatrix(m, nrl, nrh, ncl, nch) int **m; long nch, ncl, nrh, nrl; /* free an int matrix allocated by imatrix() */ { free((FREE_ARG) (m[nrl] + ncl - NR_END)); free((FREE_ARG) (m + nrl - NR_END)); } void free_submatrix(b, nrl, nrh, ncl, nch) float **b; long nch, ncl, nrh, nrl; /* free a submatrix allocated by submatrix() */ { free((FREE_ARG) (b + nrl - NR_END)); } void free_convert_matrix(b, nrl, nrh, ncl, nch) float **b; long nch, ncl, nrh, nrl; /* free a matrix allocated by convert_matrix() */ { free((FREE_ARG) (b + nrl - NR_END)); } void free_f3tensor(t, nrl, nrh, ncl, nch, ndl, ndh) float ***t; long nch, ncl, ndh, ndl, nrh, nrl; /* free a float f3tensor allocated by f3tensor() */ { free((FREE_ARG) (t[nrl][ncl] + ndl - NR_END)); free((FREE_ARG) (t[nrl] + ncl - NR_END)); free((FREE_ARG) (t + nrl - NR_END)); } #endif /* ANSI */ qsstv_8.2.12/qsstv/drmrx/nrutil.h000664 001750 001750 00000006541 12440612574 017003 0ustar00jomajoma000000 000000 #ifndef _NR_UTILS_H_ #define _NR_UTILS_H_ /* static float sqrarg; #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) */ /* static double dsqrarg; #define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg) */ /* static double dmaxarg1,dmaxarg2; #define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ?\ (dmaxarg1) : (dmaxarg2)) static double dminarg1,dminarg2; #define DMIN(a,b) (dminarg1=(a),dminarg2=(b),(dminarg1) < (dminarg2) ?\ (dminarg1) : (dminarg2)) static float maxarg1,maxarg2; #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ (maxarg1) : (maxarg2)) static float minarg1,minarg2; #define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\ (minarg1) : (minarg2)) static long lmaxarg1,lmaxarg2; #define LMAX(a,b) (lmaxarg1=(a),lmaxarg2=(b),(lmaxarg1) > (lmaxarg2) ?\ (lmaxarg1) : (lmaxarg2)) static long lminarg1,lminarg2; #define LMIN(a,b) (lminarg1=(a),lminarg2=(b),(lminarg1) < (lminarg2) ?\ (lminarg1) : (lminarg2)) static int imaxarg1,imaxarg2; #define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\ (imaxarg1) : (imaxarg2)) static int iminarg1,iminarg2; #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ (iminarg1) : (iminarg2)) */ #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) #if defined(__STDC__) || defined(ANSI) || defined(NRANSI) /* ANSI */ void nrerror (const char error_text[]); float *fvector (long nl, long nh); int *ivector (long nl, long nh); unsigned char *cvector (long nl, long nh); unsigned long *lvector (long nl, long nh); double *dvector (long nl, long nh); float **matrix (long nrl, long nrh, long ncl, long nch); double **dmatrix (long nrl, long nrh, long ncl, long nch); int **imatrix (long nrl, long nrh, long ncl, long nch); float **submatrix (float **a, long oldrl, long oldrh, long oldcl, long oldch, long newrl, long newcl); float **convert_matrix (float *a, long nrl, long nrh, long ncl, long nch); float ***f3tensor (long nrl, long nrh, long ncl, long nch, long ndl, long ndh); void free_fvector (float *v, long nl, long nh); void free_ivector (int *v, long nl, long nh); void free_cvector (unsigned char *v, long nl, long nh); void free_lvector (unsigned long *v, long nl, long nh); void free_dvector (double *v, long nl, long nh); void free_matrix (float **m, long nrl, long nrh, long ncl, long nch); void free_dmatrix (double **m, long nrl, long nrh, long ncl, long nch); void free_imatrix (int **m, long nrl, long nrh, long ncl, long nch); void free_submatrix (float **b, long nrl, long nrh, long ncl, long nch); void free_convert_matrix (float **b, long nrl, long nrh, long ncl, long nch); void free_f3tensor (float ***t, long nrl, long nrh, long ncl, long nch, long ndl, long ndh); #else /* ANSI */ /* traditional - K&R */ void nrerror (); float *vector (); float **matrix (); float **submatrix (); float **convert_matrix (); float ***f3tensor (); double *dvector (); double **dmatrix (); int *ivector (); int **imatrix (); unsigned char *cvector (); unsigned long *lvector (); void free_vector (); void free_dvector (); void free_ivector (); void free_cvector (); void free_lvector (); void free_matrix (); void free_submatrix (); void free_convert_matrix (); void free_dmatrix (); void free_imatrix (); void free_f3tensor (); #endif /* ANSI */ #endif /* _NR_UTILS_H_ */ qsstv_8.2.12/qsstv/drmrx/psdcmean.cpp000664 001750 001750 00000004650 12440612574 017612 0ustar00jomajoma000000 000000 /* * File psdcmean.c * * Calculates mean powerspectrum of complex input data * using blocklength lblock and nblocks as number * of blocks to be processed. * * Author M.Bos - PA0MBO * Date Feb 21st 2009 * * resulting power spectral density of complex input * signal in rsbuf is stored in cpsd[] * length of datablock to be processed is lblock * nblocks is the nuber of blocks of input data * to be processed. * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include void cfft(float *, int, int); void psdcmean(float *rsbuf, float *cpsd, int lblock, int nblocks) { float *pinput; int i, j; float tmpinbuf[2048]; float result[512]; /* check space */ if (lblock > 1024) { printf("not enough temp space\b"); exit(EXIT_FAILURE); } /* clear array result before accumulating new data */ for (i = 0; i < (lblock / 2); i++) { result[i] = 0.0; } /* loop over all blocks taking care to keep track of ptr in input */ pinput = rsbuf; for (j = 0; j < nblocks; j++) { /* Now fill tmpinbuf with converted data from input */ for (i = 0; i < lblock; i++) { tmpinbuf[i * 2] = pinput[2 * i]; tmpinbuf[i * 2 + 1] = pinput[2 * i + 1]; } cfft(tmpinbuf, lblock / 2, 1); for (i = 1; i < lblock / 2; ++i) { result[i] += sqrt(tmpinbuf[i * 2] * tmpinbuf[i * 2] + tmpinbuf[i * 2 + 1] * tmpinbuf[i * 2 + 1]); } pinput += 2 * lblock; /* update pointer in input data */ } for (i = 0; i < lblock / 2; i++) { result[i] = (float) (10.0 * log(result[i] + 1.0e-8) / 2.305 - 14.0); } /* interchange halfs of cpsd buffer as in matlab code from plot_input_spectrum in diorama */ for (i = 1; i < lblock / 4; i++) { cpsd[i] = result[lblock / 4 + i]; cpsd[i + lblock / 4 - 1] = result[i]; } } qsstv_8.2.12/qsstv/drmrx/psdmean.cpp000664 001750 001750 00000004106 12440612574 017443 0ustar00jomajoma000000 000000 /* * File psdmean.c * * Calculates mean powerspectrum of input data * using blocklength lblock and nblocks as number * of blocks to be processed. * * Author M.Bos - PA0MBO * Date Feb 21st 2009 * * resulting power spectral density of real input data * vector input[] is stored in psd[] * lblock is the length of the block of data to be * processed and nblock is the number of data blocks * to be processed * */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ #include #include #include #include #include void rfft(float *, int, int); void psdmean(float *input, float *psd, int lblock, int nblocks) { float *pinput; int i, j; float tmpinbuf[1024]; /* check for space allocated */ if (lblock > 1024) { printf("lblokc param too large in call psdmean\n"); exit(EXIT_FAILURE); } /* clear array psd before accumulating new data */ for (i = 0; i < lblock / 2; i++) { psd[i] = 0.0; } /* loop over all blocks taking care to keep track of ptr in input */ pinput = input; for (j = 0; j < nblocks; j++) { /* Now fill tmpinbuf with converted data from input */ for (i = 0; i < lblock; i++) { tmpinbuf[i] = pinput[i]; } rfft(tmpinbuf, lblock / 2, 1); for (i = 1; i < lblock / 2; ++i) { psd[i] += sqrt(tmpinbuf[i * 2] * tmpinbuf[i * 2] + tmpinbuf[2 * i + 1] * tmpinbuf[2 * i + 1]); } pinput += lblock; /* update pointer in input data */ } for (i = 1; i < lblock / 2; ++i) psd[i] = (float) (10.0 * log(psd[i] + 1.0e-8) / 2.3025 - 14.0); } qsstv_8.2.12/qsstv/drmrx/resamplefilter.h000664 001750 001750 00000007001 12440612574 020474 0ustar00jomajoma000000 000000 /* Automatically generated file with MATLAB */ /* File name: "ResampleFilter.m" */ /* Filter taps in time-domain */ #ifndef _RESAMPLEFILTER_H_ #define _RESAMPLEFILTER_H_ #define RES_FILT_NUM_TAPS_PER_PHASE 12 #define INTERP_DECIM_I_D 10 /* Filter for ratios close to 1 */ static float fResTaps1To1[INTERP_DECIM_I_D][RES_FILT_NUM_TAPS_PER_PHASE] = { {-0.00129181992672801360f, 0.00561586829442904840f, -0.01349857823816511800f, 0.02541150940858524100f, -0.04267869501534898200f, 0.07724474282951483700f, 0.96609875058711103000f, -0.01641812005088002400f, -0.00427135103965109450f, 0.00726225824406205160f, -0.00544188094946287510f, 0.00266742068076876060f }, {-0.00207886551285772290f, 0.00866090598717600930f, -0.02161960909069559500f, 0.04383507935997314800f, -0.08302470868585065700f, 0.18738870090358245000f, 0.93524350914423104000f, -0.09031872116141286000f, 0.02909509423931267600f, -0.00897188476756275060f, 0.00178311012364952820f, 0.00010586149691723067f }, {-0.00287519800425638110f, 0.01143197533872717000f, -0.02889142869399521600f, 0.06060641890050100900f, -0.12152802242786863000f, 0.30933747340895279000f, 0.87539536840978205000f, -0.14271415809850990000f, 0.05516985095031713000f, -0.02205265100214613000f, 0.00761119378345958850f, -0.00187713739944610450f }, {-0.00354120720771153910f, 0.01351098086300389300f, -0.03433664370844288100f, 0.07367662235517660800f, -0.15398027155782226000f, 0.43728178746780866000f, 0.79013921003423337000f, -0.17341770937821352000f, 0.07263788052016696700f, -0.03120859084480779800f, 0.01170664402374247200f, -0.00319259334815649940f }, {-0.00391755659664638590f, 0.01447751287549226700f, -0.03701682481313090000f, 0.08107302414568577600f, -0.17606165300033697000f, 0.56464344237183917000f, 0.68451472884717957000f, -0.18369620562420094000f, 0.08111657494320076400f, -0.03614676421513295800f, 0.01396276906259418800f, -0.00384568128202934270f }, {-0.00384568128202934270f, 0.01396276906259418800f, -0.03614676421513295800f, 0.08111657494320076400f, -0.18369620562420094000f, 0.68451472884717957000f, 0.56464344237183917000f, -0.17606165300033697000f, 0.08107302414568577600f, -0.03701682481313090000f, 0.01447751287549226700f, -0.00391755659664638590f }, {-0.00319259334815649940f, 0.01170664402374247200f, -0.03120859084480779800f, 0.07263788052016696700f, -0.17341770937821352000f, 0.79013921003423337000f, 0.43728178746780866000f, -0.15398027155782226000f, 0.07367662235517660800f, -0.03433664370844288100f, 0.01351098086300389300f, -0.00354120720771153910f }, {-0.00187713739944610450f, 0.00761119378345958850f, -0.02205265100214613000f, 0.05516985095031713000f, -0.14271415809850990000f, 0.87539536840978205000f, 0.30933747340895279000f, -0.12152802242786863000f, 0.06060641890050100900f, -0.02889142869399521600f, 0.01143197533872717000f, -0.00287519800425638110f }, {0.00010586149691723067f, 0.00178311012364952820f, -0.00897188476756275060f, 0.02909509423931267600f, -0.09031872116141286000f, 0.93524350914423104000f, 0.18738870090358245000f, -0.08302470868585065700f, 0.04383507935997314800f, -0.02161960909069559500f, 0.00866090598717600930f, -0.00207886551285772290f }, {0.00266742068076876060f, -0.00544188094946287510f, 0.00726225824406205160f, -0.00427135103965109450f, -0.01641812005088002400f, 0.96609875058711103000f, 0.07724474282951483700f, -0.04267869501534898200f, 0.02541150940858524100f, -0.01349857823816511800f, 0.00561586829442904840f, -0.00129181992672801360f } }; #endif /* _RESAMPLEFILTER_H_ */ qsstv_8.2.12/qsstv/drmrx/sourcedecoder.cpp000664 001750 001750 00000055412 12440612574 020650 0ustar00jomajoma000000 000000 #include "sourcedecoder.h" #include "drm.h" #include "qsstvglobal.h" #include "drmproto.h" #include #include #include "configparams.h" #include "dispatcher.h" #include #include #include "utils/reedsolomoncoder.h" #include #include "drmrx/demodulator.h" #include "utils/ftp.h" #include "configparams.h" #include "utils/qjp2io.h" #include "utils/hybridcrypt.h" #include "logbook/logbook.h" #include "drmrx/drmstatusframe.h" sourceDecoder::sourceDecoder(QObject *parent) : QObject(parent) { } void sourceDecoder::init() { lastTransportBlockPtr=NULL; transportBlockPtrList.clear(); bodyTotalSegments=0; checkIt=false; erasureList.clear(); lastContinuityIndex=-1; } /*! \brief decode of valid data block • header 8 bits. • data field n bytes. • CRC 16 bits. \return bool return true if successful */ bool sourceDecoder::decode() { double checksum; int N_partB; // if(!demodulatorPtr->isTimeSync()) if (channel_decoded_data_buffer_data_valid != 1) return false; if (audio_data_flag == 0) { addToLog("audio decoding not implemented in qsstv !\n",LOGDRMSRC); return false; } addToLog("Datapacket received",LOGPERFORM); N_partB = (int) (length_decoded_data/ 8); addToLog(QString("N-partB lenght=%1").arg(N_partB),LOGDRMSRC); if(N_partB>PACKETBUFFERLEN) { addToLog(QString("packet buffer length exceeded: lenght=%1").arg(N_partB),LOGDRMMOT); } bits2bytes (channel_decoded_data_buffer, N_partB * 8, packetBuffer); crc16_bytewise(&checksum, packetBuffer,N_partB); if(fabs (checksum) <= DBL_EPSILON) { if(!setupDataBlock(packetBuffer,true,N_partB)) { msc_valid=INVALID; return false; } } else { msc_valid=INVALID; return false; } // at this point we have a dataPacket we now check header / data and buils a transport stream switch(currentDataPacket.dataGroupType) { case MOTDATA: addToLog("Datasegment",LOGDRMSRC); addDataSegment(); break; case MOTHEAD: addToLog("Headersegment",LOGDRMSRC); addHeaderSegment(); break; default: return false; break; } return true; } bool sourceDecoder::setupDataBlock(unsigned char *buffer,bool crcIsOK,int len) { currentDataBlock.length=len; unsigned char header=buffer[0]; unsigned int availableBytes; const char *bufPtr; currentDataBlock.ba=QByteArray((char *)buffer,len); currentDataBlock.firstFlag=currentDataBlock.lastFlag=false; if(header & 0x80) currentDataBlock.firstFlag = true; if(header & 0x40) currentDataBlock.lastFlag = true; currentDataBlock.packetID = (header & 0x30) >> 4; currentDataBlock.PPI = (header & 0x8) >> 3; currentDataBlock.continuityIndex = (header & 0x7); currentDataBlock.log(); if ((currentDataBlock.PPI != 0) && (crcIsOK)) { availableBytes=buffer[1]; bufPtr=(const char *)&buffer[2]; } else { availableBytes=len-3; bufPtr=(const char *)&buffer[1]; } if(currentDataBlock.firstFlag) { holdingBuffer.clear(); lastContinuityIndex=currentDataBlock.continuityIndex; } else { if(lastContinuityIndex<0) { return false; } lastContinuityIndex=(lastContinuityIndex+1)%8; if(currentDataBlock.continuityIndex!=lastContinuityIndex) { lastContinuityIndex=-1; return false; } } holdingBuffer.append(bufPtr,availableBytes); if(currentDataBlock.lastFlag) { return setupDataPacket(holdingBuffer); } return false; } void dataBlock::log() { addToLog(QString("FFlag %1,LFlag %2, PacketID %3,PPI %4,ContIdx %5, CRC %6 len %7") .arg(firstFlag).arg(lastFlag).arg(packetID).arg(PPI).arg(continuityIndex).arg(crcOK).arg(length),LOGDRMMOT); } //MSC Header Description 2 bytes or 4 bytes if Extension field // First Byte // B7 Extension Flag Header has 2 more bytes in the Extension field // B6 CRC Flag MOT has CRC // B5 Session Flag MOT last flag and segment number present. // B4 UserAccess Flag Mot user access field present. // B3-B0 Data Group Type // 0 0 0 0 (0) General data; // 0 0 0 1 (1) CA messages (for example ECMs or EMMs: see subclause 9.3.2.1); // 0 0 1 0 (2) General data and CA parameters (for example, DGCA); // 0 0 1 1 (3) MOT header information; // 0 1 0 0 (4) MOT data // 0 1 0 1 (5) MOT data and CA parameters. //Second Byte // B7-B4 Continuity Index // B3-B0 Repetition Index // 2 more extension bytes if flag is set // B15-B0 Extension Field - no further specifications // Session Header (presence indicated by Session Flag // if last flag and segment number present // B15 last segment // B14-B0 segment number // user access fields // B7-B5 rfa (not used) // B4 TransportID present flag // B3-B0 length of user access fields // if set // B15-B0 TransportID // other bytes filled with End user address field // This is followed with a 2 bytes Segmentation header // B15-B13 Repetition Count (not used) // B12-B0 Length of the data that follows bool sourceDecoder::setupDataPacket(QByteArray ba) { double checksum; unsigned char lengthIndicator; unsigned char header; currentDataPacket.ba=ba; // drop crc header=ba.at(0); currentDataPacket.transportID =0xFFFF; currentDataPacket.extFlag=false; currentDataPacket.crcFlag=false; currentDataPacket.sessionFlag=false; currentDataPacket.userFlag=false; currentDataPacket.lastSegment=false; currentDataPacket.crcOK=currentDataBlock.crcOK; if(header&0x10) currentDataPacket.userFlag=true; currentDataPacket.dataGroupType=(edataGroupType)(header&0x07); if(header&0x80) currentDataPacket.extFlag=true; if(header&0x20) currentDataPacket.sessionFlag=true; if(header&0x40) { currentDataPacket.crcFlag=true; crc16_bytewise (&checksum,(unsigned char *)currentDataPacket.ba.data(),currentDataPacket.ba.count()); if (fabs (checksum) <= DBL_EPSILON) { currentDataPacket.crcOK=true; } else { currentDataPacket.crcOK=false; msc_valid=INVALID; return false; } currentDataPacket.chop(2); // drop crc } currentDataPacket.advance(2); //skip header and continuity bits if(currentDataPacket.extFlag) currentDataPacket.advance(2); // just skip the extension bytes if(currentDataPacket.sessionFlag) { currentDataPacket.segmentNumber = (((unsigned char)(currentDataPacket.ba.at(0)) & 0x7F))*256+ ((unsigned char)currentDataPacket.ba.at(1)) ; if(currentDataPacket.ba.at(0)&0x80) { currentDataPacket.lastSegment=true; } currentSegmentNumber=currentDataPacket.segmentNumber; currentDataPacket.advance(2); } if (currentDataPacket.userFlag) { currentDataPacket.userAccessField = (unsigned char)(currentDataPacket.ba.at(0)); currentDataPacket.advance(1); lengthIndicator = (currentDataPacket.userAccessField& 0xF); if((currentDataPacket.userAccessField & 0x10) && (lengthIndicator>=2)) currentDataPacket.transportID = (((unsigned char)(currentDataPacket.ba.at(0))))*256+ ((unsigned char)currentDataPacket.ba.at(1)) ; currentDataPacket.advance(lengthIndicator); } currentDataPacket.segmentSize=(((unsigned char)(currentDataPacket.ba.at(0)) & 0x1F))*256+ ((unsigned char)currentDataPacket.ba.at(1)); currentDataPacket.advance(2); currentDataPacket.lenght=currentDataPacket.ba.count(); currentDataPacket.log(); return true; } void dataPacket::log() { addToLog(QString("extF %1,dType %2, sessionF %3, lastSegment %4, segment# %5, userF %6, transportId %7, len %8") .arg(extFlag).arg(dataGroupType).arg(sessionFlag).arg(lastSegment).arg(segmentNumber).arg(userFlag).arg(transportID).arg(lenght),LOGDRMMOT); } bool sourceDecoder::addHeaderSegment() { transportBlock *tbPtr; addToLog(QString("Header segsize: %1").arg(currentDataPacket.segmentSize),LOGDRMSRC); tbPtr=getTransporPtr(currentDataPacket.transportID,true); if(!tbPtr->alreadyReceived) msc_valid=VALID; else { msc_valid=ALREADYRECEIVED; return true; } tbPtr->headerReceived=true; unsigned char *dataPtr=(unsigned char *)currentDataPacket.ba.data(); unsigned char PLI; unsigned char paramID; unsigned char extBit; unsigned short dataFieldLength; tbPtr->bodySize = (((unsigned int)dataPtr[0]) << 20) + (((unsigned int)dataPtr[1]) << 12) + (((unsigned int)dataPtr[2]) << 4) + ((((unsigned int)dataPtr[3]) & 0xF0) >> 4); tbPtr->headerSize = (((unsigned int)dataPtr[3] & 0x0F) << 9) + (((unsigned int)dataPtr[4]) << 1) + ((((unsigned int)dataPtr[5]) & 0x80) >> 7); tbPtr->contentType = (((unsigned int)dataPtr[5] & 0x7E) >> 1); tbPtr->contentSubtype = ((((unsigned int)dataPtr[5]) & 0x1) <<8) +((unsigned int)dataPtr[6]); currentDataPacket.advance(7); // size of header core // The header core is followed by a number of parameter blocks // the first byte of every parameter block contains a 2-bits PLI (B7 and B6) indicating the type of parameter block. while(currentDataPacket.ba.count()) // todo { PLI=dataPtr[0]>>6; paramID=dataPtr[0]&0x3F; switch (PLI) { case 0: currentDataPacket.advance(1); break; case 1: loadParams(tbPtr,paramID,1); currentDataPacket.advance(2); break; case 2: loadParams(tbPtr,paramID,4); currentDataPacket.advance(5); break; case 3: extBit=dataPtr[0]&0x80; if(extBit) { dataFieldLength=256*(dataPtr[0]&0x7F)+dataPtr[1]; currentDataPacket.advance(2); } else { dataFieldLength=dataPtr[0]&0x7F; currentDataPacket.advance(1); } loadParams(tbPtr,paramID,dataFieldLength); currentDataPacket.advance(dataFieldLength); break; } } return true; } void sourceDecoder::loadParams(transportBlock *tbPtr,unsigned char paramID,int len) { rxDRMStatusEvent *stce; QString tmp,t; switch(paramID) { case 5: // expiration break; case 6: break; case 12: tbPtr->fileName=QString(currentDataPacket.ba.data()+1).left(len-1); stce= new rxDRMStatusEvent(QString("%1").arg(tbPtr->fileName)); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done break; default: break; } } void sourceDecoder::addDataSegment() { int i; transportBlock *tbPtr; tbPtr=getTransporPtr(currentDataPacket.transportID,true); rxTransportID=currentDataPacket.transportID; if(callsignValid) tbPtr->callsign=drmCallsign; addToLog(QString("Data segsize: %1 segment# %2").arg(currentDataPacket.segmentSize).arg(currentDataPacket.segmentNumber),LOGDRMSRC); bodyTotalSegments=tbPtr->totalSegments; if(!tbPtr->alreadyReceived) msc_valid=VALID; else { msc_valid=ALREADYRECEIVED; // return; } if(currentDataPacket.lastSegment) { tbPtr->totalSegments=currentDataPacket.segmentNumber+1; tbPtr->lastSegmentReceived=true; } else { tbPtr->defaultSegmentSize=currentDataPacket.segmentSize; } if(tbPtr->defaultSegmentSize==0) { // qDebug() << "def seg size not set"; } for(i=tbPtr->dataSegmentPtrList.count();i<=currentDataPacket.segmentNumber;i++) { tbPtr->dataSegmentPtrList.append(new dataSegment(tbPtr->defaultSegmentSize)); } if(!tbPtr->dataSegmentPtrList.at(currentDataPacket.segmentNumber)->hasData()) { checkIt=true; } else { msc_valid=ALREADYRECEIVED; } if(tbPtr->alreadyReceived) { msc_valid=ALREADYRECEIVED; checkIt=false; } if(tbPtr->totalSegmentstotalSegments=currentDataPacket.segmentNumber+1; rxSegments=tbPtr->segmentsReceived; // bytesReceived=rxSegments*tbPtr->defaultSegmentSize; tbPtr->dataSegmentPtrList.at(currentDataPacket.segmentNumber)->setData(currentDataPacket.ba,currentDataPacket.segmentNumber,true); writeData(tbPtr); } void sourceDecoder::writeData(transportBlock *tbPtr) { int i; QByteArray ba; int length=0; erasureList.clear(); erasureList.append(tbPtr->totalSegments); erasureList.append(tbPtr->defaultSegmentSize); for(i=0;idataSegmentPtrList.count();i++) { if(!tbPtr->dataSegmentPtrList.at(i)->hasData()) { erasureList.append(i); ba.append(QByteArray(tbPtr->defaultSegmentSize,0x00)); } else { ba.append(tbPtr->dataSegmentPtrList.at(i)->data); } length+=tbPtr->dataSegmentPtrList.at(i)->data.size(); // qDebug()<< "block" << i<< "len" << tbPtr->dataSegmentPtrList.at(i)->data.size() ; } tbPtr->segmentsReceived=0; drmBlockList.clear(); for(i=0;idataSegmentPtrList.count();i++) { if(tbPtr->dataSegmentPtrList.at(i)->hasData()) { drmBlockList.append(i); tbPtr->segmentsReceived++; } } if(tbPtr->isAlmostComplete()<63) return ; if(!tbPtr->lastSegmentReceived) return; checkSaveImage(ba,tbPtr); } void sourceDecoder::saveImage(transportBlock *tbPtr) { int i; eftpError ftpResult; QByteArray hybridBa; hybridCrypt hc; QImage test; displayTextEvent *stce; displayMBoxEvent *stmb=0; QString t; ftpInterface ftpIntf("Save Image FTP"); bool done=false; bool textMode=false; QString downloadF; bool saveOK=false; if(tbPtr->alreadyReceived) return ; if(tbPtr->fileName.isEmpty()) return ; lastAvgSNR=avgSNR; isHybrid=false; if(tbPtr->fileName.left(3)=="de_") { isHybrid=true; if(enableHybridRx) { downloadF=rxImagesPath+"/"+tbPtr->fileName; for(i=0;idataSegmentPtrList.count();i++) { hybridBa+=tbPtr->dataSegmentPtrList.at(i)->data; } if(hc.deCrypt(&hybridBa)) { ftpIntf.setupConnection(hc.host(),hc.port(),hc.user(),hc.passwd(),hc.dir()+"/"+hybridFtpHybridFilesDirectory); ftpResult=ftpIntf.downloadFile(tbPtr->fileName,downloadF); switch(ftpResult) { case FTPOK: break; case FTPERROR: stmb= new displayMBoxEvent("FTP Error",QString("Host: %1: %2").arg(ftpRemoteHost).arg(ftpIntf.getLastError())); break; case FTPNAMEERROR: stmb= new displayMBoxEvent("FTP Error",QString("Host: %1, Error in filename").arg(ftpRemoteHost)); break; case FTPCANCELED: stmb= new displayMBoxEvent("FTP Error",QString("Connection to %1 Canceled").arg(ftpRemoteHost)); break; case FTPTIMEOUT: stmb= new displayMBoxEvent("FTP Error",QString("Connection to %1 timed out").arg(ftpRemoteHost)); break; } if(ftpResult!=FTPOK) { QApplication::postEvent( dispatcherPtr, stmb ); // Qt will delete it when done tbPtr->setAlreadyReceived(true); return; } } else { stmb= new displayMBoxEvent("Hybrid Error","No file downloaded"); QApplication::postEvent( dispatcherPtr, stmb ); // Qt will delete it when done return; } } else { downloadF.clear(); } tbPtr->newFileName=downloadF; } if(tbPtr->newFileName.isEmpty()) return ; // test=readJP2Image(tbPtr->newFileName); if(!test.load(tbPtr->newFileName)) { test=readJP2Image(tbPtr->newFileName); if(test.isNull()) { // maybe text QFileInfo finfo(tbPtr->newFileName); if((finfo.suffix()=="txt") || (finfo.suffix()=="chat") ) { QFile fi(tbPtr->newFileName); if(!fi.open(QIODevice::ReadOnly)) return; t=fi.readAll(); stce= new displayTextEvent(t); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done textMode=true; } } saveOK=true; } else { saveOK=true; } if(saveOK) { QFileInfo tfi(tbPtr->newFileName); QString modestr(tfi.fileName()); modestr+=" "; if(isHybrid) modestr+="Hybrid "; modestr+=compactModeToString(tbPtr->modeCode); logBookPtr->logQSO(tbPtr->callsign,modestr); } tbPtr->setAlreadyReceived(true); if(!textMode) { saveDRMImageEvent *ce = new saveDRMImageEvent(tbPtr->newFileName); ce->waitFor(&done); QApplication::postEvent(dispatcherPtr, ce); while(!done) { usleep(10); } checkIt=false; } } bool sourceDecoder::checkSaveImage(QByteArray ba,transportBlock *tbPtr) { prepareFixEvent *pe; QFile outFile; reedSolomonCoder rsd; QString fileName; QString extension; fileName=rxImagesPath+"/"+tbPtr->fileName; tbPtr->newFileName=fileName; QByteArray baFile; QByteArray *baFilePtr; if(!checkIt) return false; QFileInfo qfinf(fileName); extension=qfinf.suffix().toLower(); if((extension=="rs1") || (extension=="rs2") ||(extension=="rs3")||(extension=="rs4")) { // try to decode if(tbPtr->alreadyReceived) return false; if(!rsd.decode(ba,fileName,tbPtr->newFileName,baFile,extension,erasureList)) return false; baFilePtr=&baFile; } else { if(!tbPtr->isComplete()) return false; tbPtr->newFileName=fileName; if((tbPtr->fileName=="bsr.bin")&&(!tbPtr->alreadyReceived)) { tbPtr->setAlreadyReceived(true); pe = new prepareFixEvent(ba); QApplication::postEvent(dispatcherPtr, pe); return false; } baFilePtr=&ba; } if(!tbPtr->alreadyReceived) { outFile.setFileName(tbPtr->newFileName); if(outFile.open(QIODevice::WriteOnly)<=0) { outFile.close(); return false; } outFile.write(*baFilePtr); outFile.close(); erasureList.clear(); saveImage(tbPtr); } return false; } QList *sourceDecoder::getBSR() { int i; transportBlock *tbPtr; bsrList.clear(); for(i=0;ialreadyReceived) continue; if(tbPtr->fileName=="bsr.bin") continue; bsrList.append(bsrBlock(tbPtr)); } return &bsrList; } bool sourceDecoder::storeBSR(transportBlock *tb, bool compat) { int i; int needsFiller; int prevErasure=0; // QByteArray ba; erasureList.clear(); erasureList.append(tb->totalSegments); erasureList.append(tb->defaultSegmentSize); for(i=0;idataSegmentPtrList.count();i++) { if(!tb->dataSegmentPtrList.at(i)->hasData()) { erasureList.append(i); // ba.append(QByteArray(tb->defaultSegmentSize,0x00)); } else { // ba.append(tb->dataSegmentPtrList.at(i)->data); } // length+=tb->dataSegmentPtrList.at(i)->data.size(); // qDebug()<< "block" << i<< "len" << tbPtr->dataSegmentPtrList.at(i)->data.size() ; } tb->baBSR.clear(); if(erasureList.count()<3) return false; //erasurelist has already totalSegments and defaultSegmentSize tb->baBSR.append(QString::number(tb->transportID).toLatin1().data()); tb->baBSR.append("\n"); tb->baBSR.append("H_OK\n"); tb->baBSR.append(QString::number(erasureList.at(1)).toLatin1().data()); tb->baBSR.append("\n"); tb->baBSR.append(QString::number(erasureList.at(2)).toLatin1().data()); tb->baBSR.append("\n"); prevErasure=erasureList.at(2); needsFiller=false; for(i=3;ibaBSR.append(QString::number(-1).toLatin1().data()); tb->baBSR.append("\n"); needsFiller=false; } tb->baBSR.append(QString::number(erasureList.at(i)).toLatin1().data()); tb->baBSR.append("\n"); } prevErasure=erasureList.at(i); } if(needsFiller) { tb->baBSR.append(QString::number(-1).toLatin1().data()); tb->baBSR.append("\n"); needsFiller=false; tb->baBSR.append(QString::number(erasureList.at(erasureList.count()-1)).toLatin1().data()); tb->baBSR.append("\n"); } tb->baBSR.append("-99\n"); if(!compat) { QString temp; tb->baBSR.append(tb->fileName+"\n"); temp=QString::number(tb->modeCode); while(temp.length()<5) temp.prepend("0"); tb->baBSR.append(temp); } return true; } transportBlock *sourceDecoder::getTransporPtr(unsigned short tId,bool create) { int i; rxDRMStatusEvent *stce; bool found=false; for(i=0;itransportID==tId) { found=true; break; } } if(found) lastTransportBlockPtr=transportBlockPtrList.at(i); else if (create) { callsignValid=false; stce= new rxDRMStatusEvent(""); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done if(transportBlockPtrList.count()>=MAXTRANSPORTLISTS) { //delete the oldest transportBlockPtrList.removeFirst(); } for(i=0;ifileName=="bsr.bin") { transportBlockPtrList.takeAt(i); // qDebug()<< "deleting bsr.bin"; } else i++; } transportBlockPtrList.append(new transportBlock(tId)); lastTransportBlockPtr=transportBlockPtrList.last(); lastTransportBlockPtr->robMode=robustness_mode; lastTransportBlockPtr->interLeaver=interleaver_depth_new; lastTransportBlockPtr->mscMode=msc_mode_new; // qam lastTransportBlockPtr->mpx=multiplex_description.PL_PartB; lastTransportBlockPtr->spectrum=spectrum_occupancy_new; // remap msc_new to modeCode int mCode=1; //default QAM16 if(msc_mode_new==3) mCode=0; if(msc_mode_new==0) mCode=2; int protection=0; if(multiplex_description.PL_PartB==1) protection=1; lastTransportBlockPtr->modeCode=robustness_mode*10000+spectrum_occupancy_new*1000+protection*100+mCode*10+interleaver_depth_new; } else { return NULL; } return lastTransportBlockPtr; } void sourceDecoder::removeTransporPtr(transportBlock * ptr) { int i; for(i=0;i #include #include #define PACKETBUFFERLEN 512 #define NUMSERVICES 4 #define MAXTRANSPORTLISTS 5 #include #include #include #include #include "qsstvdefs.h" enum edataGroupType {GENDATA,CAMESS,GENCA,MOTHEAD,MOTDATA,MOTDATACA}; struct dataSegment { dataSegment(int newSize) { crcOK=false; recovered=false; segmentNumber=-1; data.resize(newSize); data.fill(0XAA,newSize); } void setData(QByteArray ba,short int segNumber,bool crcok) { crcOK=crcok; data=ba; segmentNumber=segNumber; } void clearData() { data.clear(); } bool crcOK; bool recovered; short int segmentNumber; bool hasData() {return (crcOK||recovered);} QByteArray data; }; struct dataPacket { void log(); QByteArray ba; bool extFlag; bool crcFlag; bool sessionFlag; bool userFlag; bool crcOK; edataGroupType dataGroupType; unsigned char continuityIndex; unsigned char repetitionIndex; unsigned short segmentNumber; bool lastSegment; unsigned short transportID; unsigned char userAccessField; unsigned short segmentSize; int offset; int lenght; unsigned int advance(int numBytes) { ba.remove(0,numBytes); return ba.count(); } unsigned int chop(int numBytes) { ba.chop(numBytes); return ba.count(); } }; struct dataBlock { void log(); bool firstFlag; bool lastFlag; short packetID; bool PPI; unsigned char continuityIndex; bool crcOK; unsigned int length; QByteArray ba; }; struct transportBlock { transportBlock(unsigned short tId) { clear(); transportID=tId; } void clear() { totalSegments=0; headerReceived=false; segmentsReceived=0; bodySize=0; headerSize=0; alreadyReceived=false; // blockList.clear(); lastSegmentReceived=false; defaultSegmentSize=0; } bool isComplete() { if(!headerReceived) return false; if(segmentsReceivedclearData(); } } } unsigned short transportID; unsigned int bodySize; unsigned int headerSize; unsigned short contentType; unsigned short contentSubtype; unsigned int defaultSegmentSize; QString fileName; QString newFileName; bool headerReceived; bool alreadyReceived; unsigned short segmentsReceived; bool lastSegmentReceived; int totalSegments; QString callsign; // QList blockList; QVector dataSegmentPtrList; int robMode; int interLeaver; int mscMode; // qam int mpx; int spectrum; QByteArray baBSR; uint modeCode; //mode(A=0,B=1,E=2) BW(0=2.3,1=2.5) prot(High=0,LOW=1) QAM(4=0,16=1,64=2) ineterleaver }; struct bsrBlock { bsrBlock(transportBlock *tb) { tbPtr=tb; } transportBlock *tbPtr; }; class sourceDecoder : public QObject { Q_OBJECT public: explicit sourceDecoder(QObject *parent = 0); void init(); bool decode(); // bool hasStarted(){return started;} QList *getBSR(); bool checkSaveImage(QByteArray ba, transportBlock *tbPtr); void saveImage(transportBlock *tbPtr); bool storeBSR(transportBlock *tb,bool compat); private: bool setupDataBlock(unsigned char *buffer,bool crcIsOK,int len); bool setupDataPacket(QByteArray ba); void addDataSegment(); bool addHeaderSegment(); void loadParams(transportBlock *tbPtr, unsigned char paramID, int len); void writeData(transportBlock *tbPtr); transportBlock *getTransporPtr(unsigned short tId,bool create); void removeTransporPtr(transportBlock * ptr); unsigned char packetBuffer[PACKETBUFFERLEN]; dataBlock currentDataBlock; dataPacket currentDataPacket; QList transportBlockPtrList; transportBlock *lastTransportBlockPtr; QList erasureList; QByteArray holdingBuffer; short int lastContinuityIndex; bool checkIt; QList bsrList; bool isHybrid; }; #endif // SOURCEDECODER_H qsstv_8.2.12/qsstv/drmrx/structtemplates.h000664 001750 001750 00000010623 12440612574 020725 0ustar00jomajoma000000 000000 /* * File structtemplates.h * part of package RXAMADRM * M.Bos - PA0MBO * Date feb 21st 2009 */ /************************************************************************* * * PA0MBO * * COPYRIGHT (C) 2009 M.Bos * * This file is part of the distribution package RXAMADRM * * This package is free software and you can redistribute is * and/or modify it under the terms of the GNU General Public License * * More details can be found in the accompanying file COPYING *************************************************************************/ struct mplex_desc { int stream_lengths[2][6]; int PL_PartA; int PL_PartB; int HM_length; int PL_HM; }; struct audio_info { int ID[4]; int stream_ID[4]; int audio_coding[4]; int SBR_flag[4]; int audio_mode[4]; int sampling_rate[4]; int text_flag[4]; int enhancement_flag[4]; int coder_field[4]; int bytes_per_frame[4]; }; struct appl_info { int ID[4]; int stream_ID[4]; int packet_mode[4]; int data_unit_indicator[4]; int packet_ID[4]; int enhancement_flag[4]; int application_domain[4]; int packet_length[4]; int application_data[4][100]; /* pa0mbo checken for max later */ int appl_data_length[4]; int user_application_type[4]; int user_application_identifier[4]; char label[4][100]; /* pa0mbo check max 100 */ char language[4][100]; /* ibid */ char country[4][100]; /* inid */ int language_code[4]; int programme_type_code[4]; int bytes_per_frame[4]; }; struct stream_info { int number_of_audio_services; int number_of_data_services; int number_of_streams; int number_of_audio_streams; int number_of_data_streams; int audio_streams[4]; int data_streams[4]; int audio_services[4]; int data_services[4]; }; struct time_info { int day; int month; int year; int hours; int minutes; }; struct dflttmsg { int stream_no; int current_toggle; int first_last_flag; int command_flag; double field1; double field2; char segments[8][256]; /* pa0mbo check max dim 100 later */ char string[256]; int CRC_error; int first_seg_received; char current_segment[256]; /* check dim 256 later pa0mbo */ int current_segment_no; int current_segment_length; }; struct dfltdunitasmbly { int ID; int first_packet_received; int packet_ID; int continuity_index; int application_domain; char application_data[120000]; /* pa0mbo check max dim 1200 */ int CRC_error; char data_unit[120000]; int cnt_data_unit; }; struct dfltMOTdirasmbly { int transport_ID; int continuity_index; int current_segment_no; int body_complete; char body[120000]; /* pa0mbo check max dim 12000 */ int bodycnt; }; struct dfltMOTobjasmbly { int transport_ID; int header_continuity_index; int current_header_segment_no; int body_continuity_index; int current_body_segment_no; int header_complete; int body_complete; int doDelete; char header[900]; /* pa0mbo check max 900 dim */ int hdrcnt; //char body[120000]; /* pa0mbo check max dim 100 */ char body[140000]; //joma /* pa0mbo check max dim 100 */ int bodycnt; }; struct dfltMOTobjasmblyinfo { int transport_ID[120000]; /* pa0mbo check max dim 100 */ int cntID; }; struct dfltMOTobj { int ID; int content_type; int content_subtype; int creation_time; int start_validity; int expire_time; int trigger_time; int version_number; unsigned char repetition_distance[100]; /* pa0mbo check max 100 dim */ unsigned char group_reference[100]; /* pa0mbo check */ int priority; char label[16]; char content_name[30]; /* pa0mbo check max dim 30 */ char content_description[100]; /* pa0mbo check later */ unsigned char mime_type[100]; /* pa0mbo chack 100 dim later */ unsigned char compression_type; unsigned char header[900]; int hdrcnt; unsigned char body[1200000]; /* chck these dims 100 later */ int bodycnt; int error; }; struct shadowMOTobj { int transport_ID; int hdr_segment_count ; int hdr_highest_segm ; int hdr_segment_lengths[10]; int body_segment_lengths[2000]; char header [10][250]; int body_segment_count ; int body_highest_segm; int body_cnt; int header_cnt; char body[2000][250]; int body_complete; int header_complete; }; qsstv_8.2.12/qsstv/drmrx/viterbi_decode.cpp000664 001750 001750 00000024534 12440612574 020772 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 15.06.2004 */ /* Last change : 01.07.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* viterbi_decode.c (part of msd_hard) */ /* */ /******************************************************************************/ /* Description: */ /* Viterbi Decoder for Multi-Stage Decoding */ /* */ /******************************************************************************/ #include #include #include "viterbi_decode.h" int viterbi_decode(float *llr, int N, int N_PartA, signed char *puncturing1, signed char *puncturing2, signed char *puncturing3, char *infoout, char *cwout, int bitpos, int *Deinterleaver, int L, int N_tail, char *memory_ptr) { float *old_metrics, *new_metrics, inf = (float) 1e20; char *path_reg; signed char *puncture_ptr; void *swap_ptr; int symbol_index, j, symbol_pos, symbol_pos2, symbol_pos3; float symbols_acc[QOFB]; float metric_path2, metric_s1, metric_s2, metric_inc; char mask, codebits; int part, state, N_Part, path_reg_index, butterfly, info_index; if (!llr || !infoout || !cwout || !memory_ptr) { return ENOMEM; } /* debugging pa0mbo printf("viterbidecoder: N = %d, N_PartA = %d , L = %d, N_tail= %d STATES = %d\n", N, N_PartA, L, N_tail, STATES ); */ old_metrics = (float *) (memory_ptr + 0); new_metrics = (float *) (memory_ptr + STATES * sizeof(float)); path_reg = (char *) (memory_ptr + STATES * sizeof(float) + STATES * sizeof(float)); for (j = 1; j < STATES; j++) { old_metrics[j] = -inf; } old_metrics[0] = 0; symbol_index = 0; path_reg_index = 0; puncture_ptr = puncturing1 + 1; N_Part = N_PartA; /* pa0mbo debugging printf("address puncturing1 = %p \n", puncturing1); printf("inhoud :\n"); for (i=0; i < 10 ; i++) printf("%d\n", puncturing1[i]); printf("address puncturing2 = %p \n", puncturing2); printf("inhoud :\n"); for (i=0; i < 10 ; i++) printf("%d\n", puncturing2[i]); printf("address puncturing3 = %p \n", puncturing3); printf("inhoud :\n"); for (i=0; i < 10 ; i++) printf("%d\n", puncturing3[i]); */ for (part = 0; part < 3; part++) { while (symbol_index < N_Part) { symbol_pos = Deinterleaver[symbol_index]; symbols_acc[0] = -llr[symbol_pos]; symbols_acc[1] = llr[symbol_pos]; symbols_acc[2] = -llr[symbol_pos]; symbols_acc[3] = llr[symbol_pos]; /* printf(" part = %d symbol_index %d symbol_pos %d puncturing switch = %d N_Part %d\n", part, symbol_index, symbol_pos, (*puncture_ptr) , N_Part ) ; pa0mbo */ switch (*puncture_ptr) { case 3: symbol_pos = Deinterleaver[symbol_index + 1]; symbols_acc[0] += -llr[symbol_pos]; symbols_acc[1] += -llr[symbol_pos]; symbols_acc[2] += llr[symbol_pos]; symbols_acc[3] += llr[symbol_pos]; symbol_index += 2; break; case 5: symbol_pos = Deinterleaver[symbol_index + 1]; symbols_acc[0] += -llr[symbol_pos]; symbols_acc[1] += -llr[symbol_pos]; symbols_acc[2] += -llr[symbol_pos]; symbols_acc[3] += -llr[symbol_pos]; symbol_index += 2; break; case 7: symbol_pos = Deinterleaver[symbol_index + 1]; symbol_pos2 = Deinterleaver[symbol_index + 2]; symbols_acc[0] += -llr[symbol_pos] - llr[symbol_pos2]; symbols_acc[1] += -llr[symbol_pos] - llr[symbol_pos2]; symbols_acc[2] += llr[symbol_pos] - llr[symbol_pos2]; symbols_acc[3] += llr[symbol_pos] - llr[symbol_pos2]; symbol_index += 3; break; case 15: symbol_pos = Deinterleaver[symbol_index + 1]; symbol_pos2 = Deinterleaver[symbol_index + 2]; symbol_pos3 = Deinterleaver[symbol_index + 3]; symbols_acc[0] += -llr[symbol_pos] - llr[symbol_pos2] - llr[symbol_pos3]; symbols_acc[1] += -llr[symbol_pos] - llr[symbol_pos2] + llr[symbol_pos3]; symbols_acc[2] += llr[symbol_pos] - llr[symbol_pos2] - llr[symbol_pos3]; symbols_acc[3] += llr[symbol_pos] - llr[symbol_pos2] + llr[symbol_pos3]; symbol_index += 4; break; default: symbol_index++; } /* printf("puncture_ptr %p pp_increm = %d \n", puncture_ptr, *(puncture_ptr+1)); */ puncture_ptr += *(puncture_ptr + 1); symbols_acc[7] = -symbols_acc[0]; symbols_acc[6] = -symbols_acc[1]; symbols_acc[5] = -symbols_acc[2]; symbols_acc[4] = -symbols_acc[3]; for (butterfly = 0; butterfly < NOOFBF; butterfly++) { metric_s1 = old_metrics[butterfly]; metric_s2 = old_metrics[butterfly + NOOFBF]; metric_inc = symbols_acc[(int) CODER_OUTPUT[butterfly]]; new_metrics[2 * butterfly] = metric_s1 + metric_inc; path_reg[path_reg_index + 2 * butterfly] = 0; metric_path2 = metric_s2 - metric_inc; /* Add */ if (metric_path2 > new_metrics[2 * butterfly]) { /* Compare */ new_metrics[2 * butterfly] = metric_path2; path_reg[path_reg_index + 2 * butterfly] = 1; /* Select */ } new_metrics[2 * butterfly + 1] = metric_s1 - metric_inc; path_reg[path_reg_index + 2 * butterfly + 1] = 0; metric_path2 = metric_s2 + metric_inc; /* Add */ if (metric_path2 > new_metrics[2 * butterfly + 1]) { /* Compare */ new_metrics[2 * butterfly + 1] = metric_path2; path_reg[path_reg_index + 2 * butterfly + 1] = 1; /* Select */ } } /* are hard coded butterflies faster? */ path_reg_index += STATES; swap_ptr = old_metrics; old_metrics = new_metrics; new_metrics = (float *)swap_ptr; } if (part == 0) { puncture_ptr = puncturing2 + 1; N_Part = N - N_tail; } else { puncture_ptr = puncturing3 + 1; N_Part = N; } } /* trace back */ state = 0; symbol_index = N - 1; info_index = L - 1; N_Part = N - N_tail; path_reg_index -= STATES; puncture_ptr = puncturing3 + 1 - *puncturing3; for (part = 2; part >= 0; part--) { while (symbol_index >= N_Part) { infoout[info_index] = state & 0x1; /* information bit output */ info_index--; mask = 0 - ((state & 0x1) ^ path_reg[path_reg_index + state]); state = (state >> 1) | (path_reg[path_reg_index + state] * NOOFBF); /* code bits ouput and interleaving: */ codebits = CODER_OUTPUT[state & ~(NOOFBF)] ^ mask; switch (*puncture_ptr) { case 3: cwout[Deinterleaver[symbol_index]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index]] |= ((codebits & 0x2) >> 1) << bitpos; symbol_index -= 2; break; case 5: cwout[Deinterleaver[symbol_index]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index]] |= ((codebits & 0x4) >> 2) << bitpos; symbol_index -= 2; break; case 7: cwout[Deinterleaver[symbol_index]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index]] |= ((codebits & 0x4) >> 2) << bitpos; cwout[Deinterleaver[symbol_index - 1]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index - 1]] |= ((codebits & 0x2) >> 1) << bitpos; symbol_index -= 3; break; case 15: cwout[Deinterleaver[symbol_index]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index]] |= (codebits & 0x1) << bitpos; cwout[Deinterleaver[symbol_index - 1]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index - 1]] |= ((codebits & 0x4) >> 2) << bitpos; cwout[Deinterleaver[symbol_index - 2]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index - 2]] |= ((codebits & 0x2) >> 1) << bitpos; symbol_index -= 4; break; default: symbol_index--; } cwout[Deinterleaver[symbol_index + 1]] &= ~(0x1 << bitpos); cwout[Deinterleaver[symbol_index + 1]] |= (codebits & 0x1) << bitpos; path_reg_index -= STATES; puncture_ptr -= *(puncture_ptr - 1); } if (part == 2) { puncture_ptr = puncturing2 + 1 - *puncturing2; N_Part = N_PartA; } else { puncture_ptr = puncturing1 + 1 - *puncturing1; N_Part = 0; } } return 0; } qsstv_8.2.12/qsstv/drmrx/viterbi_decode.h000664 001750 001750 00000007170 12440612574 020434 0ustar00jomajoma000000 000000 /******************************************************************************/ /* */ /* University of Kaiserslautern, Institute of Communications Engineering */ /* Copyright (C) 2004 Torsten Schorr */ /* */ /* Author(s) : Torsten Schorr (schorr@eit.uni-kl.de) */ /* Project start: 15.06.2004 */ /* Last change : 30.06.2004 */ /* */ /******************************************************************************/ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* viterbi_decode.h (part of msd_hard) */ /* */ /******************************************************************************/ /* Description: */ /* function headers and constants for viterbi_decode.c */ /* */ /******************************************************************************/ #ifndef STATES #define STATES 64 /* number of states */ #endif /* */ #ifndef NOOFBF #define NOOFBF 32 /* number of butterflies */ #endif /* */ #ifndef QOFB #define QOFB 8 /* number of different output patterns per input symbol */ #endif /* */ #ifndef NOPB #define NOPB 4 /* number of parity bits */ #endif /* */ /* decoder output for zero input, states 1:32 */ const char CODER_OUTPUT[] = { 0, 6, 3, 5, 3, 5, 0, 6, 4, 2, 7, 1, 7, 1, 4, 2, 1, 7, 2, 4, 2, 4, 1, 7, 5, 3, 6, 0, 6, 0, 5, 3 }; int viterbi_decode (float *llr, int N, int N_PartA, signed char *puncturing1, signed char *puncturing2, signed char *puncturing3, char *infoout, char *cwout, int bitpos, int *Deinterleaver, int L, int N_tail, char *memory_ptr); qsstv_8.2.12/qsstv/drmtx/bsrform.cpp000664 001750 001750 00000004244 12440612574 017473 0ustar00jomajoma000000 000000 #include "bsrform.h" #include "ui_bsrform.h" #include "drmrx/drmstatusframe.h" #include "qsstvglobal.h" bsrForm::bsrForm(QWidget *parent) : QDialog(parent), ui(new Ui::bsrForm) { ui->setupUi(this); connect(ui->bsrComboBox,SIGNAL(currentIndexChanged(int)),this, SLOT(slotBSRSelection(int))); connect(ui->cancelPushButton,SIGNAL(clicked()),this,SLOT(slotCanceled())); connect(ui->easypalPushButton,SIGNAL(clicked()),this,SLOT(slotEasypal())); connect(ui->compatiblePushButton,SIGNAL(clicked()),this,SLOT(slotCompatible())); } bsrForm::~bsrForm() { delete ui; } void bsrForm::init() { int i; bsrPtr=srcDecoder.getBSR(); if(bsrPtr->count()==0) { ui->infoTextEdit->clear(); ui->infoTextEdit->appendPlainText("No BSR available"); return; } for(i=bsrPtr->count()-1;i>=0;i--) //latest first { ui->bsrComboBox->addItem(bsrPtr->at(i).tbPtr->fileName); } slotBSRSelection(0); } bool bsrForm::hasBSR() { return (bsrPtr->count()>0); } QByteArray *bsrForm::getBA(bool compat) { int i; i=bsrPtr->count()-1-ui->bsrComboBox->currentIndex(); if(bsrPtr->count()>0) { if(srcDecoder.storeBSR(bsrPtr->at(i).tbPtr,compat)) { drmParams.robMode=bsrPtr->at(i).tbPtr->robMode; drmParams.interleaver=bsrPtr->at(i).tbPtr->interLeaver; drmParams.qam=bsrPtr->at(i).tbPtr->mscMode; drmParams.protection=bsrPtr->at(i).tbPtr->mpx; drmParams.bandwith=bsrPtr->at(i).tbPtr->spectrum; return(&bsrPtr->at(i).tbPtr->baBSR); } } return NULL; } void bsrForm::slotBSRSelection(int idx) { int i; transportBlock *tbPtr; i=bsrPtr->count()-1-idx; ui->infoTextEdit->clear(); tbPtr=bsrPtr->at(i).tbPtr; ui->infoTextEdit->appendPlainText(tbPtr->callsign); ui->infoTextEdit->appendPlainText("Segments received: "+QString::number(tbPtr->segmentsReceived)); ui->infoTextEdit->appendPlainText("Total Segments: "+QString::number(tbPtr->totalSegments)); ui->infoTextEdit->appendPlainText(modeToString(tbPtr->modeCode)); } void bsrForm::slotCanceled() { done(CANCEL); } void bsrForm::slotEasypal() { done(EASYPAL); } void bsrForm::slotCompatible() { done (COMPAT); } qsstv_8.2.12/qsstv/drmtx/bsrform.h000664 001750 001750 00000001263 12440612574 017136 0ustar00jomajoma000000 000000 #ifndef BSRFORM_H #define BSRFORM_H #include #include "drmrx/sourcedecoder.h" #include "drmtx/drmtransmitter.h" namespace Ui { class bsrForm; } class bsrForm : public QDialog { Q_OBJECT public: enum eResult {CANCEL,EASYPAL,COMPAT}; explicit bsrForm(QWidget *parent = 0); ~bsrForm(); void init(); QByteArray *getBA(bool compat); bool hasBSR(); drmTxParams getDRMParams() {return drmParams;} public slots: void slotCompatible(); void slotEasypal(); void slotCanceled(); private slots: void slotBSRSelection(int); private: Ui::bsrForm *ui; void displayInfo(int idx); QList *bsrPtr; drmTxParams drmParams; }; #endif // BSRFORM_H qsstv_8.2.12/qsstv/drmtx/bsrform.ui000664 001750 001750 00000004007 12440612574 017323 0ustar00jomajoma000000 000000 bsrForm 0 0 514 367 BSR Send BSR (latest on top) Qt::Horizontal 40 20 Cancel Easypal Compatible Qt::Horizontal 40 20 qsstv_8.2.12/qsstv/drmtx/config.h000664 001750 001750 00000005771 12440612574 016741 0ustar00jomajoma000000 000000 /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FFTW3_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `faac' library (-lfaac). */ /* #undef HAVE_LIBFAAC */ /* Define to 1 if you have the `faad' library (-lfaad). */ /* #undef HAVE_LIBFAAD */ /* Define if you have Hamlib */ /* #undef HAVE_LIBHAMLIB */ /* Define to 1 if you have the `pcap' library (-lpcap). */ /* #undef HAVE_LIBPCAP */ /* Define to 1 if you have the `qwt' library (-lqwt). */ /* #undef HAVE_LIBQWT */ /* Define to 1 if you have the `rt' library (-lrt). */ #define HAVE_LIBRT 1 /* Define if you have libsndfile */ /* #undef HAVE_LIBSNDFILE */ /* Define to 1 if you have the `z' library (-lz). */ #define HAVE_LIBZ 0 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define if you have Hamlib >= 1.2.1 */ /* #undef HAVE_RIG_PARSE_MODE */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "drm" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define PACKAGE_NAME "" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you want to use the ALSA audio lib */ #define USE_ALSA 1 /* Define if you want to use the faac library */ /* #undef USE_FAAC_LIBRARY */ /* Define if you want to use the faad2 library */ /* #undef USE_FAAD2_LIBRARY */ /* Define if you want to use the jack audio lib */ /* #undef USE_JACK */ /* Define if you want to use the OSS audio lib */ /* #undef USE_OSS */ /* Define if you want to use the portaudio audio lib */ /* #undef USE_PORTAUDIO */ /* Define if you want to use the QT GUI */ /* #undef USE_QT_GUI */ /* Version number of package */ #define VERSION "1.12b" qsstv_8.2.12/qsstv/drmtx/drmtransmitter.cpp000664 001750 001750 00000006136 12440612574 021102 0ustar00jomajoma000000 000000 #include "drmtransmitter.h" #include "configparams.h" // timing table; int numTxFrames; int partTable[BWs][MODES][PROTECTIONS][QAMS]= { { {{96,160,240},{67,140,201}}, {{49,103,149},{96,160,240}}, {{67,112,168},{49,83,124}} }, { {{104,174,261},{78,163,235}}, {{54,113,163},{104,174,261}}, {{78,130,196},{54,90,135}} } }; drmTransmitter::drmTransmitter() { DRMTransmitter=NULL; } drmTransmitter::~drmTransmitter() { } void drmTransmitter::init(QByteArray *ba, QString name, QString format, drmTxParams params) { if(DRMTransmitter) delete DRMTransmitter; dataLength=ba->count(); DRMTransmitter=new CDRMTransmitter; // int picSize; ERobMode RobMod; ESpecOcc BW ; CParameter::ESymIntMod eNewDepth; ECodScheme eNewScheme; CMSCProtLev eNewMSCPre; CService Service; DRMTransmitter->init_base(); // DRMTransmitter.GetSoundOutInterface()->SetDev(nr_devout); DRMTransmitter->GetAudSrcEnc()->ClearPicFileNames(); TransmParam = DRMTransmitter->GetParameters(); // picSize=ba->size(); DRMTransmitter->GetAudSrcEnc()->SetPicFileName(ba,name,format); switch (params.robMode) { case 0 : RobMod = RM_ROBUSTNESS_MODE_A; break; case 1 : RobMod = RM_ROBUSTNESS_MODE_B ; break ; default: RobMod = RM_ROBUSTNESS_MODE_E ; break; } switch (params.bandwith) { case 0 : BW = SO_0; break; default : BW = SO_1 ; break ; } TransmParam->InitCellMapTable(RobMod , BW); switch (params.interleaver) { case 0 : eNewDepth = CParameter::SI_LONG; break ; default : eNewDepth = CParameter::SI_SHORT; break; } TransmParam->SetInterleaverDepth(eNewDepth); switch (params.qam) { case 0 : eNewScheme = CS_1_SM ; //4Bit QAM break; case 1 : eNewScheme = CS_2_SM ; //16Bit QAM break ; default : eNewScheme = CS_3_SM; // 64Bit QAM break; } TransmParam->SetMSCCodingScheme(eNewScheme); switch (params.protection) { case 1 : eNewMSCPre.iPartB = 1; //Norm break; default: eNewMSCPre.iPartB = 0 ; //High break ; } TransmParam->SetMSCProtLev(eNewMSCPre, false); Service.iServiceDescr=0; Service.iServiceID=0; Service.iLanguage=5; Service.strLabel=params.callsign.toLatin1().data(); TransmParam->SetServiceParameters(0,Service); DRMTransmitter->Init(); // calculate transmision time duration=(double)(numTxFrames)*0.4*1.005; // 1.005 ->some extra time for buffers } void drmTransmitter::start(bool startTx) { if(startTx) { stopDRM=false; DRMTransmitter->Start(); } else { stopDRM=true; } } drmTxParams modeToParams(uint mode) { drmTxParams prm; prm.robMode=mode/10000; mode-=(mode/10000)*10000; prm.bandwith=mode/1000; mode-=(mode/1000)*1000; prm.protection=mode/100; mode-=(mode/100)*100; prm.qam=mode/10; prm.interleaver=0; prm.callsign=myCallsign; return prm; } uint paramsToMode(drmTxParams prm) { uint mode=1; mode+=prm.robMode*10000; mode+=prm.bandwith*1000; mode+=prm.protection*100; mode+=prm.qam*10; return mode; } qsstv_8.2.12/qsstv/drmtx/drmtransmitter.h000664 001750 001750 00000001413 12440612574 020540 0ustar00jomajoma000000 000000 #ifndef DRMTRANSMITTER_H #define DRMTRANSMITTER_H #include "common/GlobalDefinitions.h" #include "common/DrmTransmitter.h" struct drmTxParams { int robMode; int qam; int bandwith; int interleaver; int protection; QString callsign; int reedSolomon; }; class drmTransmitter { public: drmTransmitter(); ~drmTransmitter(); void init(QByteArray *ba, QString name, QString format, drmTxParams params); void start(bool startTx); double getDuration() {return duration;} // expressed in seconds double transmissionTime; private: CDRMTransmitter *DRMTransmitter; CParameter* TransmParam ; int dataLength; double duration; }; drmTxParams modeToParams(uint mode); uint paramsToMode(drmTxParams prm); extern int numTxFrames; #endif // DRMTRANSMITTER_H qsstv_8.2.12/qsstv/dsp/downsamplefilter.cpp000664 001750 001750 00000010374 12450753733 021035 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "downsamplefilter.h" #include "configparams.h" #include "utils/supportfunctions.h" #define VOLINTEGRATOR 0.0001 downsampleFilter::downsampleFilter() { filteredDataBuffer=0; filterParams=0; samplesI=0; samplesQ=0; filterLength=0; } downsampleFilter::~downsampleFilter() { if(filteredDataBuffer) delete [] filteredDataBuffer; if(filterParams) delete [] filterParams; } downsampleFilter::downsampleFilter(unsigned int len, const FILTERPARAMTYPE *fparam, unsigned int filterLen, bool scaled) { filteredDataBuffer=0; filterParams=0; samplesI=0; samplesQ=0; filterLength=0; setFilterParams(fparam,filterLen,scaled); allocate(len); init(); } void downsampleFilter::allocate(unsigned int len) { length=len; if(filteredDataBuffer) delete [] filteredDataBuffer; filteredDataBuffer=new DSPFLOAT [len]; } void downsampleFilter::init() { unsigned int i; for(i=0;i2600) temp=prevTemp; prevTemp=temp; filteredDataBuffer[k]=temp; avgVolume=avgVolume*(1-volIntegrator)+sqrt(resI*resI+resQ*resQ)*volIntegrator; volumeBuffer[k]=(int)avgVolume; } } void filter::processIQ(DSPFLOAT *data, DSPFLOAT *output,int len) { FILTERPARAMTYPE resQ=0; const FILTERPARAMTYPE *cf1; DSPFLOAT *fp1; unsigned int i; int k; for (k=0;k #define FILTERPARAMTYPE DSPFLOAT //#define FILTERPARAMTYPE FILTERPARAMTYPE #define RXNUMTAPS 251 #define TXWFNUMTAPS 121 #define NUMTAPSPOST 0 #define NUMRXFILTERS 1 //#define DWSBANDPASS #ifdef DWSBANDPASS #define DSAMPLEFILTERLEN 360 #else #define DSAMPLEFILTERLEN 180 #endif enum efilterType {FNARROW,FWIDE}; enum epostFilterType {NONE}; //extern const DSPFLOAT sharp1200BP[RXNUMTAPS]; extern const FILTERPARAMTYPE wide1200BP[RXNUMTAPS]; extern const FILTERPARAMTYPE wide600Hz[RXNUMTAPS]; //extern const DSPFLOAT wideVolume[RXNUMTAPS]; //extern const DSPFLOAT veryWideVolume[RXNUMTAPS]; //extern const DSPFLOAT narrowRX[RXNUMTAPS]; //extern const DSPFLOAT wideRX[RXNUMTAPS]; //extern const DSPFLOAT wideRXBLFIR[RXNUMTAPS]; //extern const DSPFLOAT narrowRXBLFIR[RXNUMTAPS]; extern const FILTERPARAMTYPE downSampleFilterParam[DSAMPLEFILTERLEN]; extern const FILTERPARAMTYPE wfFilter[TXWFNUMTAPS]; //extern const DSPFLOAT wideVolumeFilter[RXNUMTAPS]; DSPFLOAT calculateGain(const DSPFLOAT *fp,unsigned int len); struct sfilters { const QString filterName; const FILTERPARAMTYPE *filterPtr; DSPFLOAT centerFrequency; }; extern sfilters filterStruct[NUMRXFILTERS]; #endif qsstv_8.2.12/qsstv/dsp/nco.h000664 001750 001750 00000006454 12440612574 015702 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2004 by Johan Maes - ON4QZ * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef NCO_H #define NCO_H #include #include "qsstvglobal.h" #include /** @author Johan Maes */ /** Numerical Controlled Oscillator The next value for the sine and/or cosine is calculated each time the function is called */ class NCO // numerical controlled oscillator { public: /** create an instance of the NCO with a given frequency \warning the frequency is the normilized frequency i.e F/samplingrate; */ NCO(DSPFLOAT freq=0.5) { init(freq); } ~NCO() { } /** initialize the oscilator This function is automatically called from the constructor \param[in] frequency the frequency the oscillator must be running at \warning the frequency is the normilized frequency i.e F/samplingrate; */ void init(DSPFLOAT frequency) { w=(2*frequency*M_PI); b=2.*cos(w); s1=sin(-w); s2=sin(-2.*w); c1=sin(M_PI/2.-w); c2=sin(M_PI/2.-2.*w); } /** get the sine and cosine values \param[out] sinVal sine value \param[out] cosVal cosine value */ void getSinCos(DSPFLOAT &sinVal,DSPFLOAT &cosVal) { sinVal=b*s1-s2; s2=s1; s1=sinVal; cosVal=b*c1-c2; c2=c1; c1=cosVal; } /** get the sine value \return sine value */ DSPFLOAT getSine() { float sinVal=b*s1-s2; s2=s1; return(s1=sinVal); } /** produce the I & Q values \param[out] I the I component (val multiplied by a sine) \param[out] Q the Q component (val multiplied by a cosine) \param[in] val the real value of the sample */ void multiply(DSPFLOAT &i, DSPFLOAT &q,DSPFLOAT val) { DSPFLOAT t=b*s1-s2; i=val*t; s2=s1; s1=t; t=b*c1-c2; c2=c1; q=val*t; c1=t; } private: DSPFLOAT w; DSPFLOAT b; DSPFLOAT s1,s2; DSPFLOAT c1,c2; }; #endif qsstv_8.2.12/qsstv/dsp/synthes.cpp000664 001750 001750 00000012273 12440612574 017147 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2004 by Johan Maes - ON4QZ * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "synthes.h" #include "qsstvglobal.h" #include "sound/soundio.h" #include "sound/waterfalltext.h" #include "utils/supportfunctions.h" /* To generate the frequency, we have to calculate the instant phase jump of the signal by dividing the frequency by the SR. We multiply this by the number of entries in the sine lookup table. This value is added to the old index of the sine table. */ synthesizer *synthesPtr; synthesizer::synthesizer(double txSmpClock) { // generate the table int i; txSamplingClock=txSmpClock; addToLog(QString("synthes: tx sampling clock=%1").arg(txSamplingClock),LOGSOUND); for (i=0;igetLength(); while ((dataPtr=waterfallPtr->nextLine())!=NULL) { addToLog(QString("sending id len=%1").arg(len),LOGSYNTHES); for (i=0;itxBuffer.put(filter(sample))) { usleep(2000); } } // buffer must already contain correct stereo information void synthesizer::writeBuffer(quint32 *buffer, int len) { while((!soundIOPtr->txBuffer.put(buffer,len)) && (!soundIOPtr->stoppedPlaying())) { usleep(2000); } } void synthesizer::setFilter(efilterType txFilterType) { // filterLength=TXNUMTAPS; switch (txFilterType) { // case F400: // case F600: // case F1000: // case F800: //filterI=f800TX; default: break; } } //void synthesizer::fillBuffer() //{ // unsigned int i; // unsigned int sz; // sz=soundIOPtr->txBuffer.getBufferSize(); // for(i=0;i<50000;i++) // { // soundIOPtr->txBuffer.put((SOUNDFRAME)(round(nextSample(2300)))); // } // for(;i<(sz);i++) // { // soundIOPtr->txBuffer.put((SOUNDFRAME)(round(nextSample(1500)))); // } // for(;itxBuffer.put((SOUNDFRAME)(round(0))); // } // addToLog(QString("buffercount %1").arg(soundIOPtr->txBuffer.getWriteIndex()),LOGSYNTHES); //} qsstv_8.2.12/qsstv/dsp/synthes.h000664 001750 001750 00000005135 12440612574 016613 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2004 by Johan Maes - ON4QZ * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef SYNTHES_H #define SYNTHES_H #include #include "filterparam.h" #define SINTABLEN 2048 class synthesizer { public: synthesizer(double txSmpClock); ~synthesizer(); double nextSample(double freq) { double temp; int t; temp=(freq/txSamplingClock)*(double)SINTABLEN+oldAngle; oldAngle=fmod(temp,SINTABLEN); t=(int)(oldAngle+0.5); return sineTable[t%SINTABLEN]; } void sendTone(double duration,double lowerFrequency,double upperFrequency, bool concat); void sendSamples(unsigned int numSamples,double frequency); void sendSweep(unsigned int duration,double lowerFrequency, double upperFrequency); void sendSilence(double duration); void sendSample(double freq); void setFilter(efilterType txFilterType); void sendWFText(); void writeBuffer(quint32 *buffer,int len); private: double txSamplingClock; double oldAngle; double sineTable[SINTABLEN]; const float *filterI; unsigned int filterLength; SOUNDFRAME filter(double sample); void write(double sample); double sample; double adjust; // void fillBuffer(); //only for test }; #endif qsstv_8.2.12/qsstv/editor/editor.cpp000664 001750 001750 00000022440 12440612574 017435 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "editor.h" #include #include "qsstvglobal.h" #include "utils/supportfunctions.h" #include "editorview.h" #include "configparams.h" #include "dispatcher.h" /*! constructor */ editor::editor(QWidget *parent,Qt::WindowFlags flags): QMainWindow(parent,flags) { ev=new editorView(this); setCentralWidget (ev); initActions(); initMenubar(); statusBar()->showMessage("Select a tool"); setMinimumSize(640,480); resize(640,480); addToLog (QString(" editor create: %1") .arg(QString::number((ulong)this,16)),LOGEDIT); setWindowTitle("QSSTV Editor"); } /*! destructor (saves settings on deletion) */ editor::~editor() { addToLog (QString(" editor delete: %1") .arg(QString::number((ulong)this,16)),LOGEDIT); writeSettings(); } /*! reads the settings (saved images for tx,rx,templates) */ void editor::readSettings() { QSettings qSettings; qSettings.beginGroup ("Editor" ); int windowWidth = qSettings.value( "windowWidth", 640 ).toInt(); int windowHeight = qSettings.value( "windowHeight", 480 ).toInt(); int windowX = qSettings.value( "windowX", -1 ).toInt(); int windowY = qSettings.value( "windowY", -1 ).toInt(); if ( windowX != -1 || windowY != -1 ) move ( windowX, windowY ); resize ( windowWidth, windowHeight ); qSettings.endGroup(); } /*! writes the settings (saved images for tx,rx,templates) */ void editor::writeSettings() { QSettings qSettings; qSettings.beginGroup ("Editor" ); qSettings.setValue ( "windowWidth", width() ); qSettings.setValue ( "windowHeight", height() ); qSettings.setValue ( "windowX", x() ); qSettings.setValue ( "windowY", y() ); qSettings.endGroup(); } void editor::initActions() { fileNew = new QAction(QIcon(":/icons/filenew.png"),tr("&New"),this); fileNew->setShortcut(tr("Ctrl+N")); fileNew->setStatusTip(tr("Create a new image")); connect(fileNew, SIGNAL(triggered()), this, SLOT(slotFileNew())); fileOpen = new QAction(QIcon(":/icons/fileopen.png"),tr("&Open"),this); fileOpen->setShortcut(tr("Ctrl+O")); fileOpen->setStatusTip(tr("Open an image file")); connect(fileOpen, SIGNAL(triggered()), this, SLOT(slotFileOpen())); fileSave = new QAction(QIcon(":/icons/filesave.png"),tr("&Save file .."),this); fileSave->setStatusTip(tr("Save the file under the same name and format")); connect(fileSave, SIGNAL(triggered()), this, SLOT(slotFileSave())); fileSaveImage = new QAction(tr("Save &Image file .."),this); fileSaveImage->setStatusTip(tr("Save the file in PNG format")); connect(fileSaveImage, SIGNAL(triggered()), this, SLOT(slotFileSaveImage())); fileSaveTemplate = new QAction(("Save &Template .."),this); fileSaveTemplate->setStatusTip(tr("Save template file ")); connect(fileSaveTemplate, SIGNAL(triggered()), this, SLOT(slotFileSaveTemplate())); fileQuit = new QAction(tr("Quit"),this); fileQuit->setShortcut(tr("Ctrl+Q")); fileQuit->setStatusTip(tr("Quits the editor")); connect(fileQuit, SIGNAL(triggered()), this, SLOT(slotFileQuit())); clearAll= new QAction(QIcon(":/icons/eraser.png"),tr("Clear &All"),this); clearAll->setShortcut(tr("Ctrl+A")); clearAll->setStatusTip(tr("Delete all objects and fill the background with the background color")); connect(clearAll, SIGNAL(triggered()), ev, SLOT(slotClearAll())); copy= new QAction(tr("Copy"),this); copy->setShortcut(tr("Ctrl+C")); connect(copy, SIGNAL(triggered()), ev->getScene(), SLOT(slotCopy())); paste= new QAction(tr("Paste"),this); paste->setShortcut(tr("Ctrl+V")); connect(paste, SIGNAL(triggered()), ev->getScene(), SLOT(slotPaste())); deleteAction=new QAction(tr("&Delete"),this); deleteAction->setShortcut(tr("Del")); connect(deleteAction, SIGNAL(triggered()), ev->getScene(), SLOT(slotDeleteItem())); dump= new QAction(tr("dump"),this); connect(dump, SIGNAL(triggered()), ev, SLOT(slotDump())); } void editor::initMenubar() { fileMenu=menuBar()->addMenu(tr("&File")); editMenu=menuBar()->addMenu(tr("&Edit")); fileMenu->addAction(fileNew); fileMenu->addAction(fileOpen); fileMenu->addAction(fileSave); fileMenu->addAction(fileSaveImage); fileMenu->addAction(fileSaveTemplate); fileMenu->addAction(fileQuit); editMenu->addAction(deleteAction); editMenu->addAction(copy); editMenu->addAction(paste); editMenu->addAction(clearAll); editMenu->addAction(dump); } void editor::slotFileNew() { if(ev->isModified()) { switch( QMessageBox::information( this, "Editor", "The document has not been saved as a template\n", "&Continue Anyway","Cancel",NULL, -1, // Enter == button 0 1 ) ) { // Escape == button 2 case 0: // Continu clicked break; case 1: // Cancel clicked return; break; } } ev->slotClearAll(); localFile.close(); localFile.setFileName(""); } void editor::slotFileOpen() { /* QFileDialog *fd = new QFileDialog(this,0,true); fd->show();*/ dirDialog d(this,0); QString s=d.openFileName(txImagesPath,"*.png *.gif *.jpg *.templ"); if (s==QString::null) return ; if (s.isEmpty()) return ; localFile.setFileName(s); ev->open(localFile); addToLog("localfile after open = " + localFile.fileName(),LOGEDIT); } /*! \fn editor::slotFileSave() \brief save file under same name and same type */ void editor::slotFileSave() { if(localFile.fileName().isEmpty()) { slotFileSaveTemplate(); return; } if(ev->getScene()->getImageType()==editorScene::FLATIMAGE) { addToLog("localfile to save = " + localFile.fileName(),LOGEDIT); ev->save(localFile,false); } else { ev->save(localFile,true); } } void editor::slotFileSaveImage() { dirDialog d((QWidget *)this,"Editor"); QString s(localFile.fileName()); if(s.isEmpty()) { s=txImagesPath; } s=d.saveFileName(s,"*.png","png"); if (s==QString::null) return ; if (s.isEmpty()) return ; localFile.setFileName(s); ev->save(localFile,false); } void editor::slotFileSaveTemplate() { dirDialog d((QWidget *)this,"Browse"); QString s(localFile.fileName()); if(s.isEmpty()) { s=templatesPath; } s=d.saveFileName(s,"*.templ","templ"); if (s==QString::null) return ; if (s.isEmpty()) return ; localFile.setFileName(s); ev->save(localFile,true); } void editor::slotFileQuit() { close(); } void editor::closeEvent(QCloseEvent *e) { if(ev->isModified()) { QMessageBox msgBox; msgBox.setText("The document has been modified."); msgBox.setInformativeText("Do you want to save your changes?"); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Save); int ret = msgBox.exec(); switch (ret) { case QMessageBox::Save: slotFileSave(); break; case QMessageBox::Discard: // Don't Save was clicked break; case QMessageBox::Cancel: return; break; default: // should never be reached break; } } editorFinishedEvent *ce = new editorFinishedEvent(true,localFile.fileName()); QApplication::postEvent(dispatcherPtr, ce ); // Qt will delete it when done emit imageAvailable(ev->getImage()); writeSettings(); e->accept(); } //bool editor::render(QImage **im,QString fn) //{ // if(!openFile(fn)) return false; // *im=ev->getScene()->renderImage(); // addToLog(QString("editor: render size: %1 x %2").arg((*im)->size().width()).arg((*im)->size().height()),LOGEDIT); // return true; //} bool editor::setImage(QImage *im) { ev->setImage(im); return true; } bool editor::openFile(QString fn) { QFile f(fn); localFile.setFileName(fn); return ev->open(f); } qsstv_8.2.12/qsstv/editor/editor.h000664 001750 001750 00000005146 12440612574 017106 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef EDITOR_H #define EDITOR_H #include #include #include class editorView; /*! Mainwindow for the image gallery This editor allows the creation of images and templates. */ /*! @author Johan Maes - ON4QZ */ class editor : public QMainWindow { Q_OBJECT public: editor(QWidget *parent=0,Qt::WindowFlags flags = 0); ~editor(); // void editImage(QImage *ima); bool openFile(QString fn); void readSettings(); // bool render(QImage **im,QString fn); bool setImage(QImage *im); public slots: void slotFileNew(); void slotFileOpen(); void slotFileSave(); void slotFileSaveImage(); void slotFileSaveTemplate(); void slotFileQuit(); private: editorView *ev; void closeEvent(QCloseEvent *); void initActions(); void initMenubar(); void writeSettings(); QAction *fileNew; QAction *fileOpen; QAction *fileSave; QAction *fileSaveImage; QAction *fileSaveTemplate; QAction *fileQuit; QAction *clearAll; QAction *copy; QAction *paste; QAction *deleteAction; QAction *dump; QMenu *fileMenu; QMenu *editMenu; QFile localFile; QFile externalFile; }; #endif qsstv_8.2.12/qsstv/editor/editorform.ui000664 001750 001750 00000135120 12440612574 020154 0ustar00jomajoma000000 000000 editorForm 0 0 808 520 0 0 Adobe Helvetica 9 Editor true 0 0 80 22 16777215 22 100 22 16777215 22 false QFontComboBox::ScalableFonts Bitstream Charter 22 22 22 22 Sans Serif 75 true B true 22 22 22 22 75 true true I true 22 22 22 22 75 true true U true Pen width Qt::Horizontal 298 24 Fill ... 22 22 QToolButton::MenuButtonPopup Qt::NoArrow Line ... 22 22 QToolButton::MenuButtonPopup Gradient ... 22 22 QToolButton::MenuButtonPopup Qt::Horizontal 40 20 2 2 2 1 2 30 30 :/icons/arrow.png:/icons/arrow.png 22 22 true 30 30 :/icons/fcircle.png:/icons/fcircle.png 22 22 true 30 30 :/icons/frect.png:/icons/frect.png 22 22 true 30 30 :/icons/line.png:/icons/line.png 22 22 true 30 30 :/icons/image.png:/icons/image.png 22 22 true 30 30 :/icons/replay.png:/icons/replay.png 22 22 true 30 30 :/icons/text.png:/icons/text.png 22 22 true Qt::Vertical 45 88 2 Qt::Vertical 2 4 QFrame::Box QFrame::Plain 4 Qt::Vertical 2 4 0 0 0 0 V-Shear Qt::AlignCenter false Qt::Horizontal 2 20 0 0 0 0 40 16777215 -25 25 5 Qt::Vertical QSlider::TicksAbove 5 Qt::Horizontal 2 20 0 0 80 30 16777215 16777215 0 170 0 0 0 255 0 170 0 0 0 255 0 0 255 0 0 255 true QFrame::Panel QFrame::Sunken 3 true 4 QLCDNumber::Dec QLCDNumber::Filled 0.000000000000000 0 Qt::Vertical 20 40 0 0 60 25 60 16777215 H-Shear Qt::AlignCenter false 0 0 100 30 16777215 30 255 0 0 255 0 0 255 0 0 -25 25 1 5 Qt::Horizontal QSlider::TicksBelow 5 0 0 80 30 100 30 0 170 0 0 0 255 0 170 0 0 0 255 0 0 255 0 0 255 true QFrame::Panel QFrame::Sunken 3 true 4 QLCDNumber::Dec QLCDNumber::Filled 0.000000000000000 0 0 0 60 25 60 50 Rotate Qt::AlignCenter false Qt::Horizontal 40 20 80 80 80 80 255 255 255 128 128 128 192 192 192 160 160 160 64 64 64 85 85 85 255 255 255 255 255 255 255 255 255 0 0 0 128 128 128 0 0 0 64 64 64 255 255 220 0 0 0 255 255 255 128 128 128 192 192 192 160 160 160 64 64 64 85 85 85 255 255 255 255 255 255 255 255 255 0 0 0 128 128 128 0 0 0 64 64 64 255 255 220 0 0 0 64 64 64 128 128 128 192 192 192 160 160 160 64 64 64 85 85 85 64 64 64 255 255 255 64 64 64 128 128 128 128 128 128 0 0 0 128 128 128 255 255 220 0 0 0 0 359 0 Qt::Vertical false false true 10.000000000000000 true Qt::Horizontal 40 20 0 0 80 30 80 30 0 170 0 0 0 255 0 170 0 0 0 255 0 0 255 0 0 255 true QFrame::Panel QFrame::Sunken 3 true 4 QLCDNumber::Dec QLCDNumber::Filled 0.000000000000000 0 qsstv_8.2.12/qsstv/editor/editorscene.cpp000664 001750 001750 00000044754 12440612574 020467 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include "editorscene.h" #include "gradientdialog.h" #include "qsstvglobal.h" #include "ui_textform.h" #include "gallerywidget.h" #include "utils/qjp2io.h" editorScene::editorScene(QGraphicsView *parent) : QGraphicsScene(parent) { contextMenu=new QMenu(); arrange = new QMenu( "Arrange"); arrange->setTearOffEnabled(true); arrange->addAction("Forward",this,SLOT(slotSendForward())); arrange->addAction("Backward",this,SLOT(slotSendBackward())); arrange->addAction("Bring to front",this,SLOT(slotBringToFront())); arrange->addAction("Send to back",this,SLOT(slotSendToBack())); contextMenu->addMenu(arrange); contextMenu->addSeparator(); contextMenu->addAction("Change Text",this,SLOT(slotChangeText())); // contextMenu->addAction("Copy",this,SLOT(slotCopy())); // contextMenu->addAction("Paste",this,SLOT(slotPaste())); contextMenu->addSeparator(); contextMenu->addAction("Delete",this,SLOT(slotDeleteItem())); contextMenu->addAction("Expand",this,SLOT(slotExpand())); contextMenu->addAction("Lock",this,SLOT(slotLock())); contextMenu->addAction("Unlock",this,SLOT(slotUnlock())); zMax=0; pasted=false; copyItem=NULL; mode=MOVE; imageType=NONE; localImage=NULL; rotate=0; vShear=0; hShear=0; border=QRectF(0,0,0,0); borderItemPtr=NULL; penWidth=1; } editorScene::~editorScene() { if(localImage!=NULL) delete localImage; if((!pasted) &&(copyItem!=NULL)) delete copyItem; delete arrange; delete contextMenu; } bool editorScene::load(QFile &f) { bool borderSet=false; QImage im; itemBase *item; quint32 magic; QString version; quint16 streamVersion; int type; if(!f.open(QIODevice::ReadOnly)) return false; QDataStream str(&f); str >> magic; if (magic != MAGICNUMBER) { //try to load an image f.reset(); if(im.load(&f,0)) { addToLog("image loaded",LOGEDIT); imageType=FLATIMAGE; setImage(&im); border=QRect(0,0,im.width(),im.height()); borderSet=true; f.close(); return true; } else { addToLog("image failed to load",LOGEDIT); f.close(); return false; } } imageType=TEMPLATE; str >> version; // at this moment we do not use the version str >> streamVersion; str.setVersion(streamVersion); while (!str.atEnd()) { str >> type; switch (type) { case itemBase::RECTANGLE: item=new itemRectangle(contextMenu); break; case itemBase::ELLIPSE: item=new itemEllipse(contextMenu); break; case itemBase::LINE: item=new itemLine(contextMenu); break; case itemBase::TEXT: item=new itemText(contextMenu); break; case itemBase::IMAGE: item=new itemImage(contextMenu); break; case itemBase::REPLAY: item=new itemReplayImage(contextMenu); break; case itemBase::SBORDER: borderSet=true; item=new itemImage(contextMenu); item->load(str); border=item->rect(); delete item; continue; break; default: addToLog("Error in datastream",LOGEDIT); f.close(); return false; break; } item->load(str); addItem(item); // item->setTransform(); //itemSetup(item); } //border=sceneRect(); optimizeDepth(); if(!borderSet) border=QRectF(0,0,320,256); addToLog(QString("border position %1,%2 size: %3 x %4 border set=%5") .arg(border.topLeft().x()).arg(border.topLeft().y()) .arg(border.width()).arg(border.height()).arg(borderSet),LOGEDIT); f.close(); setSceneRect(border); return true; } QImage *editorScene::renderImage(int w,int h) { clearSelection(); if (localImage!=NULL) delete localImage; //border=sceneRect(); if(w==0) { localImage=new QImage(border.width(),border.height(),QImage::Format_ARGB32_Premultiplied); } else { localImage=new QImage(w,h,QImage::Format_ARGB32_Premultiplied); } addToLog(QString("editorScene: pre-render size: %1 x %2").arg(localImage->size().width()).arg(localImage->size().height()),LOGEDIT); QPainter painter(localImage); painter.setRenderHint(QPainter::Antialiasing); //setSceneRect(0,0,localImage->width(),localImage->height()); localImage->fill(0); render(&painter); addToLog(QString("editor: post-render size: %1 x %2").arg(localImage->size().width()).arg(localImage->size().height()),LOGEDIT); return localImage; } void editorScene::flattenImage(int w,int h) { if (localImage!=NULL) delete localImage; setSceneRect(border); // border=sceneRect(); localImage=new QImage(w,h,QImage::Format_ARGB32_Premultiplied); convertText(); convertReplayImage(); QPainter painter(localImage); painter.setRenderHint(QPainter::Antialiasing); // setSceneRect(0,0,localImage->width(),localImage->height()); localImage->fill(0); render(&painter); } void editorScene::convertReplayImage() { QString fn; QImage im; fn=galleryWidgetPtr->getLastRxImage(); if(fn.right(4).toUpper()==".JP2") { im=readJP2Image(fn); } else { im.load(fn); } if(im.isNull()) return; //itemBase *it; foreach(QGraphicsItem *t,items()) { //it=qgraphicsitem_cast(t); if(t->type()==itemBase::REPLAY) { itemReplayImage *itt=qgraphicsitem_cast(t); itt->setImage(im); } } } void editorScene::convertText() { //itemBase *it; foreach(QGraphicsItem *t,items()) { // it=qgraphicsitem_cast(t); if(t->type()==itemBase::TEXT) { itemText *itt=qgraphicsitem_cast(t); // itt->setText(textConversion(itt->text())); itt->setText(mexp.convert(itt->text())); } } } //QString editorScene::textConversion(QString str) //{ // int i,j; // QChar c; // convertedText.clear(); // bool special=false; // for (i=0;i(t); if(t->type()>itemBase::BASE) { it->save(str); } } f.close(); return true; } void editorScene::setMode(eMode m) { mode = m; if(mode==INSERT) clearSelection () ; } void editorScene::setItemType(itemBase::egraphType tp) { itemType = tp; } void editorScene::apply(changeFlags cf) { QPen p; itemBase *it; if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { it=qgraphicsitem_cast(t); if(cf & DFILLCOLOR) { it->setBrush(fillColor); } if(cf & DLINECOLOR) { p=it->pen(); p.setColor(lineColor); it->setPen(p); } if(cf & DPEN) { p=it->pen(); p.setWidth(penWidth); it->setPen(p); } if(cf & DGRADIENT) { gradientDialog gd; sgradientParam tmp; tmp=gd.param(); it->setGradient(tmp); it->update(); } if(cf & DTRANSFORM) { it->setTransform(rotate,hShear,vShear); } if(t->type()==itemBase::TEXT) { itemText *itt=qgraphicsitem_cast(t); if(cf & DFONT) itt->setFont(font); if(cf & DTEXT) itt->setText(text); } it->update(); } } void editorScene::clearAll() { foreach(QGraphicsItem *t,items()) { if((t->type()>itemBase::BASE) && (t->type()!=itemBase::SBORDER)) { removeItem(t); delete t; } } } void editorScene::itemSetup(itemBase *item) { QPen p; gradientDialog gd; sgradientParam tmp; tmp=gd.param(); item->setGradient(tmp); item->setTransform(rotate,hShear,vShear); p=item->pen(); p.setColor(lineColor); p.setWidth(penWidth); item->setPen(p); item->setBrush(fillColor); item->setZValue(zMax); zMax+=1; addItem(item); } void editorScene::setImage(QImage *im) { itemBase *item; item=new itemImage(contextMenu); item->setImage(*im); item->setRect(0,0,im->width(),im->height()); itemSetup(item); item->setPos(QPointF(0,0)); item->setSelected(true); emit changeSize(im->width(),im->height()); } void editorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) { itemBase *item; QImage im; if (mouseEvent->button() == Qt::LeftButton) { switch(mode) { case INSERT: switch(itemType) { case itemBase::RECTANGLE: item=new itemRectangle(contextMenu); itemSetup(item); item->setPos(mouseEvent->scenePos()); break; case itemBase::LINE: item=new itemLine(contextMenu); itemSetup(item); item->setPos(mouseEvent->scenePos()); break; case itemBase::ELLIPSE: item=new itemEllipse(contextMenu); itemSetup(item); item->setPos(mouseEvent->scenePos()); break; case itemBase::TEXT: if (!text.isEmpty()) { item=new itemText(contextMenu); item->setFont(font); item->setText(text); itemSetup(item); item->setPos(mouseEvent->scenePos()); } break; case itemBase::IMAGE: if(im.load(fl)) { item=new itemImage(contextMenu); item->setImage(im); itemSetup(item); item->setPos(mouseEvent->scenePos()); } break; case itemBase::REPLAY: item=new itemReplayImage(contextMenu); itemSetup(item); item->setPos(mouseEvent->scenePos()); break; case itemBase::SBORDER: case itemBase::BASE: break; } break; case MOVE: if(!selectedItems().isEmpty()) { item=qgraphicsitem_cast(selectedItems().first()); } break; case PICK: break; } } QGraphicsScene::mousePressEvent(mouseEvent); } void editorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { QGraphicsScene::mouseMoveEvent(mouseEvent); } void editorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) { itemBase *item; if(mode==MOVE) { if(!selectedItems().isEmpty()) { item=qgraphicsitem_cast(selectedItems().first()); emit itemSelected(item); } } else if(mode==PICK) { emit colorSelected(mouseEvent->scenePos()); ((QGraphicsView *)parent())->setCursor(Qt::ArrowCursor); } mode=MOVE; QGraphicsScene::mouseReleaseEvent(mouseEvent); } void editorScene::slotCopy() { itemBase *item; if((!pasted) &&(copyItem!=NULL)) delete copyItem; if(selectedItems().isEmpty()) return; // nothing to do item=qgraphicsitem_cast(selectedItems().first()); makeCopy(item); } void editorScene::makeCopy(itemBase *it) { itemBase *item=it; itemBase::egraphType type=(itemBase::egraphType)item->type(); switch(type) { case itemBase::RECTANGLE: copyItem=new itemRectangle(item->getParam().menu); break; case itemBase::LINE: copyItem=new itemLine(item->getParam().menu); break; case itemBase::ELLIPSE: copyItem=new itemEllipse(item->getParam().menu); break; case itemBase::TEXT: copyItem=new itemText(item->getParam().menu); break; case itemBase::IMAGE: copyItem=new itemImage(item->getParam().menu); break; case itemBase::REPLAY: copyItem=new itemReplayImage(item->getParam().menu); break; default: return; } copyItem->setParam(item->getParam()); copyItem->setPos(item->pos()+QPointF(10,10)); pasted=false; } void editorScene::slotPaste() { clearSelection(); copyItem->setZValue(zMax+1); zMax+=1; addItem(copyItem); pasted=true, makeCopy(copyItem); clearSelection(); } void editorScene::slotExpand() { itemBase *it; if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { it=qgraphicsitem_cast(t); if(it->type()!=itemBase::TEXT) { it->setRect(border); it->setPos(0,0); } } } void editorScene::slotChangeText() { if(selectedItems().isEmpty()) return; // nothing to do itemText *item=qgraphicsitem_cast(selectedItems().first()); if(!item) { return; } if(item->type()!=itemBase::TEXT) return; QDialog d(0); Ui::textForm t; t.setupUi(&d); t.lineEdit->setText(item->text()); if(d.exec()==QDialog::Accepted) { item->setText(t.lineEdit->text()); } } void editorScene::slotDeleteItem() { if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { removeItem(t); delete t; } } void editorScene::slotLock() { itemBase *it; if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { it=qgraphicsitem_cast(t); it->setLocked(true); } } void editorScene::slotUnlock() { itemBase *it; if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { it=qgraphicsitem_cast(t); it->setLocked(false); } } void editorScene::slotBringToFront() { if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { zMax+=1; t->setZValue(zMax); } optimizeDepth(); } void editorScene::slotSendToBack() { if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { t->setZValue(0.5); } optimizeDepth(); } void editorScene::slotSendBackward() { if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { t->setZValue(t->zValue()-1.5); } optimizeDepth(); } void editorScene::slotSendForward() { if(selectedItems().isEmpty()) return; // nothing to do foreach(QGraphicsItem *t,selectedItems()) { t->setZValue(t->zValue()+1.5); } optimizeDepth(); } void editorScene::optimizeDepth() { itemBase *it; zMax=items().count(); qreal i=0; foreach(QGraphicsItem *t,items(itemsBoundingRect ())) { it=qgraphicsitem_cast(t); if(it->type()==itemBase::SBORDER) { it->setZValue(0.1); } else if(it->type()>itemBase::BASE) { it->setZValue(zMax-i); i+=1; } addToLog(QString("optimize_1 type=%1 pos=%2,%3 resctPos=%4,%5").arg(it->getTypeStr()).arg(t->pos().x()).arg(t->pos().y()).arg(it->rect().x()).arg(it->rect().y()),LOGEDIT); addToLog(QString("Boundingrect t=%1 %2,%3 %4,%5").arg(it->getTypeStr()).arg(it->boundingRect().x()).arg(it->boundingRect().y()).arg(it->boundingRect().width()).arg(it->boundingRect().height()),LOGEDIT); } //optimize position } void editorScene::addBorder(int w,int h) { if (borderItemPtr==NULL) { borderItemPtr=new itemBorder(contextMenu); } itemSetup(borderItemPtr); borderItemPtr->setPos(0,0); borderItemPtr->setRect(0,0,w,h); border=QRectF(0,0,w,h); slotSendToBack(); } void editorScene::overlay(QImage *ima) { clearSelection(); // addToLog(QString("overlay: before number of items: %1").arg(items().count()),LOGEDIT); // itemBase *item; // item=new itemImage(contextMenu); // item->setImage(*ima); // itemSetup(item); // item->setPos(0,0); // item->setRect(0,0,ima->width(),ima->height()); // item->setSelected(true); // slotSendToBack(); // clearSelection(); // addToLog(QString("overlay: after number of items: %1").arg(items().count()),LOGEDIT); // flattenImage(ima->width(),ima->height()); setSceneRect(border); // border=sceneRect(); if (localImage!=NULL) delete localImage; localImage=new QImage(ima->copy()); // localImage=ima; convertText(); convertReplayImage(); QPainter painter(localImage); painter.setRenderHint(QPainter::Antialiasing); // setSceneRect(0,0,localImage->width(),localImage->height()); // localImage->fill(0); render(&painter,QRectF(),QRectF(),Qt::IgnoreAspectRatio); } void editorScene::addConversion(QChar tag,QString value,bool clear) { if(clear) mexp.clear(); mexp.addConversion(tag,value); } qsstv_8.2.12/qsstv/editor/editorscene.h000664 001750 001750 00000010271 12440612574 020117 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef EDITORSCENE_H #define EDITORSCENE_H #include //#include "graphics.h" #include "graphicitems.h" #include "utils/supportfunctions.h" #include "utils/macroexpansion.h" class QGraphicsSceneMouseEvent; #define CHANGECOLOR #define CHANGE class editorScene : public QGraphicsScene { Q_OBJECT public: enum eImageType { NONE, /*!< no image defined */ FLATIMAGE, /*!< loaded image is a simple image (png,jpeg,...) */ TEMPLATE /*!< loaded image is a template file */ }; enum eMode { MOVE, INSERT,PICK}; enum doChange {DNOCHANGE = 0, DFILLCOLOR = 1, DLINECOLOR=2, DGRADIENT=4,DTEXT = 8,DFONT=16,DPEN=32,DTRANSFORM=64}; Q_DECLARE_FLAGS(changeFlags, doChange); editorScene(QGraphicsView *parent=0); ~editorScene(); QColor fillColor; QColor lineColor; QGradient gradient; QColor gradientColor; QFont font; QString text; QString fl; double penWidth; void apply(changeFlags cf); void clearAll(); QRectF border; int rotate; qreal hShear; qreal vShear; bool load(QFile &f); bool save(QFile &f,bool templ); void setImage(QImage *im); eMode mode; eImageType getImageType(){return imageType;} QImage *renderImage(int w, int h); macroExpansion mexp; void overlay(QImage *ima); void addBorder(int w,int h); QImage *getImagePtr() {return localImage;} void addConversion(QChar tag,QString value,bool clear=false); // bool event(QEvent *); public slots: void setMode(eMode m); void setItemType(itemBase::egraphType tp); // void editorLostFocus(DiagramTextItem *item); void slotCopy(); void slotPaste(); void slotExpand(); void slotDeleteItem(); void slotLock(); void slotUnlock(); void slotBringToFront(); void slotSendToBack(); void slotSendBackward(); void slotSendForward(); void slotChangeText(); signals: // void itemInserted(itemBase *itm); // void textInserted(itemBase *itm); void changeSize(int,int); void itemSelected(itemBase *itm); void colorSelected( const QPointF &p); protected: void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); private: itemBase *copyItem; itemBase::egraphType itemType; bool leftButtonDown; bool pasted; qreal zMax; QPointF startPoint; // Context menus QMenu *contextMenu; QMenu *arrange; void optimizeDepth(); void itemSetup(itemBase *item); void makeCopy(itemBase *it); eImageType imageType; QImage *localImage; void flattenImage(int w,int h); void convertText(); // QString textConversion(QString str); // QString convertedText; itemBase *borderItemPtr; void convertReplayImage(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(editorScene::changeFlags) #endif qsstv_8.2.12/qsstv/editor/editorview.cpp000664 001750 001750 00000041444 12440612574 020335 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "editorview.h" #include "qsstvglobal.h" #include "utils/supportfunctions.h" #include "graphicitems.h" #include "gradientdialog.h" #include "ui_textform.h" #define TBFILL 0 #define TBLINE 1 #define TBGRAD 2 #define NUMCOLORSELECTORS 12 static QColor defaultColors[NUMCOLORSELECTORS]= { qRgba( 0, 0, 0,255), qRgba(255,255,255,255), qRgba(255, 0, 0,255), qRgba( 0,255, 0,255), qRgba( 0, 0,255,255), qRgba(128,128,128,255), qRgba(255, 0, 0,128), qRgba( 0,255, 0,128), qRgba( 0, 0,255,128), qRgba(255,255, 0,128), qRgba( 0,255,255,128), qRgba(255, 0,255,128) }; struct sCanvasSize { const QString s; int width; int height; }; #define SIZES 7 sCanvasSize canvasSizeArray[SIZES]= { {"160x120",160,120}, {"320x240",320,240}, {"320x256",320,256}, {"500x400",500,400}, {"500x496",500,496}, {"640x496",640,496}, {"800x616",800,616} }; int s; #define BORDER 4 /** editorview */ editorView::editorView(QWidget *parent):QWidget(parent), Ui::editorForm() { setupUi(this); scene=new editorScene(canvas); canvas->setScene(scene); // canvas->setFixedSize(800,700);; pickMode=NOPICK; //border= new QGraphicsRectItem(0,0,320,256); // scene->border=border->rect(); // scene->addItem(border); scene->setMode(editorScene::MOVE); scene->setItemType(itemBase::BASE); for (int i=0; iaddItem(canvasSizeArray[i].s); readSettings(); sizeComboBox->setCurrentIndex(canvasSizeIndex); scene->setSceneRect(0,0,canvasSizeArray[canvasSizeIndex].width,canvasSizeArray[canvasSizeIndex].height); connect(scene,SIGNAL(itemSelected(itemBase*)),SLOT(slotItemSelected(itemBase*))); connect(sizeComboBox, SIGNAL(activated(int)), SLOT(slotChangeCanvasSize(int))); connect(arrowPushButton,SIGNAL(clicked()),SLOT(slotArrow())); connect(rectanglePushButton,SIGNAL(clicked()),SLOT(slotRectangle())); connect(circlePushButton,SIGNAL(clicked()),SLOT(slotCircle())); connect(replayPushButton,SIGNAL(clicked()),SLOT(slotReplay())); connect(imagePushButton,SIGNAL(clicked()),SLOT(slotImage())); connect(linePushButton,SIGNAL(clicked()),SLOT(slotLine())); connect(textPushButton,SIGNAL(clicked()),SLOT(slotText())); rotateLCD->display( " 0'" ); connect(rotateDial, SIGNAL(valueChanged(int)),SLOT(slotRotateChanged(int)) ); hshearLCD->display( "0.00" ); vshearLCD->display( "0.00" ); connect(hshearSlider, SIGNAL(valueChanged(int)),SLOT(slotShearChanged(int)) ); connect(vshearSlider, SIGNAL(valueChanged(int)),SLOT(slotShearChanged(int)) ); //connect (scene,SIGNAL(changeSize(int,int)),SLOT(slotChangeCanvasSize(int,int))); // connect(textLineEdit, SIGNAL(textChanged(const QString &)),SLOT(slotTextReturnPressed(const QString &)) ); // slotRotateChanged(0); // slotShearChanged(0); fontComboBox->setCurrentIndex(currentFontIndex); connect(fontComboBox,SIGNAL(currentFontChanged(const QFont &)),SLOT(slotFontChanged(const QFont &))); fontSizeSpinBox->setRange(6, 180); fontSizeSpinBox->setValue(currentPointSize); scene->font.setPointSize(fontSizeSpinBox->value()); connect(fontSizeSpinBox,SIGNAL( valueChanged (int)),SLOT(slotFontSizeChanged(int))); penWidthSpinBox->setRange(0,99); penWidthSpinBox->setValue(currentPenWidth); connect(penWidthSpinBox,SIGNAL( valueChanged (double)),SLOT(slotPenWidthChanged(double))); boldButton->setChecked(scene->font.bold()); italicButton->setChecked(scene->font.italic()); underlineButton->setChecked(scene->font.underline()); connect(boldButton,SIGNAL( clicked(bool)),SLOT(slotBold(bool))); connect(italicButton,SIGNAL( clicked(bool)),SLOT(slotItalic(bool))); connect(underlineButton,SIGNAL( clicked(bool)),SLOT(slotUnderline(bool))); QAction *action; action = new QAction("Color Picker", this); action->setData(TBFILL); connect(action, SIGNAL(triggered()),this,SLOT(slotColorPicker())); fillToolButton->setMenu(createColorMenu(SLOT(slotColorDialog()),TBFILL,"Select Color")); fillToolButton->menu()->addAction(action); // scene->fillColor=QColor(127,127,0); fillToolButton->setIcon(createColorToolButtonIcon(":/icons/colorfill.png", scene->fillColor)); connect(fillToolButton, SIGNAL(clicked()),this, SLOT(slotButtonTriggered())); action = new QAction("Color Picker", this); action->setData(TBLINE); connect(action, SIGNAL(triggered()),this,SLOT(slotColorPicker())); lineToolButton->setMenu(createColorMenu(SLOT(slotColorDialog()),TBLINE,"Select Color")); lineToolButton->menu()->addAction(action); lineToolButton->setIcon(createColorToolButtonIcon(":/icons/colorline.png", scene->lineColor)); connect(lineToolButton, SIGNAL(clicked()),this, SLOT(slotButtonTriggered())); connect(scene,SIGNAL(colorSelected( const QPointF &)),this,SLOT(slotColorPicked(const QPointF &))); gradientToolButton->setMenu(createColorMenu(SLOT(slotGradientDialog()),TBGRAD,"Select Gradient")); gradientToolButton->setIcon(createColorToolButtonIcon(":/icons/gradient.png", scene->gradientColor)); connect(gradientToolButton, SIGNAL(clicked()),this, SLOT(slotButtonTriggered())); // setup the defaults slotRotateChanged(0); setTransform(); slotFontChanged(fontComboBox->currentFont()); slotPenWidthChanged(currentPenWidth); slotChangeCanvasSize(canvasSizeIndex); slotDump(); modified=false; } editorView::~editorView() { writeSettings(); } /*! reads the settings (saved images for tx,rx,templates) */ void editorView::readSettings() { QSettings qSettings; qSettings.beginGroup ("Editor"); canvasSizeIndex=qSettings.value("canvassizeindex", 2 ).toInt(); currentFontIndex=qSettings.value("currentfontindex", 2 ).toInt(); currentPointSize=qSettings.value("currentpointSize", 24).toInt(); currentPenWidth=qSettings.value("currentpenwidth", 1).toDouble(); scene->font = qSettings.value("fillcolor", qApp->font()).value(); scene->fillColor = qSettings.value("fillcolor", QColor(Qt::white)).value(); scene->lineColor = qSettings.value("linecolor", QColor(Qt::black )).value(); scene->gradientColor = qSettings.value("gradientcolor",QColor( Qt::red )).value(); qSettings.endGroup(); } /*! writes the settings (saved images for tx,rx,templates) */ void editorView::writeSettings() { QSettings qSettings; qSettings.beginGroup ("Editor" ); qSettings.setValue ("canvassizeindex", sizeComboBox->currentIndex()); qSettings.setValue ("currentfontindex", fontComboBox->currentIndex()); qSettings.setValue ("currentpenwidth", penWidthSpinBox->value()); qSettings.setValue ("currentpointsize",fontSizeSpinBox->value()); qSettings.setValue ("fillcolor", scene->fillColor); qSettings.setValue ("linecolor", scene->lineColor); qSettings.setValue ("gradientcolor", scene->gradientColor); qSettings.endGroup(); } void editorView::slotArrow() { } void editorView::slotRectangle() { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::RECTANGLE); modified=true; } void editorView::slotCircle() { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::ELLIPSE); modified=true; } void editorView::slotText() { QDialog d(this); Ui::textForm t; t.setupUi(&d); t.lineEdit->setText(txt); if(d.exec()==QDialog::Accepted) { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::TEXT); scene->text=t.lineEdit->text(); txt=t.lineEdit->text(); scene->apply(editorScene::DTEXT); } modified=true; } void editorView::slotLine() { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::LINE); modified=true; } void editorView::slotColorPicker() { int tp; colorPickImage=scene->renderImage(0,0); addToLog(QString("colorpicker triggered size %1 x %2").arg(colorPickImage->width()).arg(colorPickImage->height()),LOGEDIT); QAction *act; act=qobject_cast(sender()); tp=act->data().toInt(); if (tp==TBFILL) { pickMode=PICKFILLCOLOR; } else if (tp==TBLINE) { pickMode=PICKLINECOLOR; } scene->setMode(editorScene::PICK); //setCursor(Qt::ArrowCursor); } void editorView::slotColorPicked(const QPointF &p) { QRgb c=colorPickImage->pixel(p.x(),p.y()); addToLog(QString("Picked color r=%1,g=%2,b=%3 alpha=%4").arg(qRed(c)).arg(qGreen(c)).arg(qBlue(c)).arg(qAlpha(c)),LOGEDIT); if(pickMode==PICKFILLCOLOR) { scene->fillColor.setRgba(c); fillToolButton->setIcon(createColorToolButtonIcon(":/icons/colorfill.png",scene->fillColor)); } else { scene->lineColor.setRgba(c); lineToolButton->setIcon(createColorToolButtonIcon(":/icons/colorline.png",scene->lineColor)); } canvas->setCursor(Qt::ArrowCursor); } void editorView::slotImage() { QString fileName; dirDialog dd((QWidget *)this,"editor"); scene->fl=dd.openFileName(QString()); scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::IMAGE); modified=true; } void editorView::slotReplay() { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::REPLAY); modified=true; } //void editorView::slotChangeCanvasSize(int w,int h) //{ // canvas->setSceneRect(0,0,w,h); // border->setRect(0,0,w,h); // scene->border=border->rect(); // modified=true; //} void editorView::slotChangeCanvasSize(int index) { rotateDial->setValue(0); hshearSlider->setValue(0); vshearSlider->setValue(0); setTransform(); scene->addBorder(canvasSizeArray[index].width,canvasSizeArray[index].height); canvas->setSceneRect(0,0,canvasSizeArray[index].width,canvasSizeArray[index].height); modified=true; } void editorView::slotFontChanged(const QFont &f) { scene->font=f; scene->font.setPointSize(fontSizeSpinBox->value()); scene->font.setBold(boldButton->isChecked()); scene->font.setItalic(italicButton->isChecked()); scene->font.setUnderline(underlineButton->isChecked()); scene->apply(editorScene::DFONT); modified=true; } void editorView::slotFontSizeChanged(int sz) { scene->font.setPointSize(sz); scene->apply(editorScene::DFONT); modified=true; } void editorView::slotPenWidthChanged(double pw) { scene->penWidth=pw; scene->apply(editorScene::DPEN); modified=true; } void editorView::slotBold(bool b) { scene->font.setBold(b); scene->apply(editorScene::DFONT); modified=true; } void editorView::slotItalic(bool b) { scene->font.setItalic(b); scene->apply(editorScene::DFONT); modified=true; } void editorView::slotUnderline(bool b) { scene->font.setUnderline(b); scene->apply(editorScene::DFONT); modified=true; } /*! \todo image insert check if this is used */ void editorView::setImage(QImage *) { scene->setMode(editorScene::INSERT); scene->setItemType(itemBase::IMAGE); modified=true; } void editorView::slotClearAll() { scene->clearAll(); } void editorView::slotButtonTriggered() { QToolButton *act; act=qobject_cast(sender()); if (act==fillToolButton) { scene->apply(editorScene::DFILLCOLOR); } else if (act==lineToolButton) { scene->apply(editorScene::DLINECOLOR); } else if (act==gradientToolButton) { scene->apply(editorScene::DGRADIENT); } else { return; } } void editorView::slotColorDialog() { int tp; QAction *act; QColor c; act=qobject_cast(sender()); tp=act->data().toInt(); switch(tp) { case TBFILL: c=QColorDialog::getColor(scene->fillColor,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) { scene->fillColor=c; fillToolButton->setIcon(createColorToolButtonIcon(":/icons/colorfill.png",scene->fillColor)); } break; case TBLINE: c=QColorDialog::getColor(scene->lineColor,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) { scene->lineColor=c; lineToolButton->setIcon(createColorToolButtonIcon(":/icons/colorline.png",scene->lineColor)); } break; default: qDebug() << "Error in slotColorDialog"; break; } } void editorView::slotGradientDialog() { gradientDialog gDiag(this); gDiag.selectGradient(); } void editorView::save(QFile &f,bool templ) { scene->save(f,templ); modified=false; } bool editorView::open(QFile &f) { if(!scene->load(f)) return false; slotDump(); return true; } void editorView::setTransform() { // int r=450-rotateDial->value(); // if ( r >= 360 ) r-=360; int r=rotateDial->value(); scene->rotate=r; scene->hShear=(double)hshearSlider->value()/10.; scene->vShear=(double)vshearSlider->value()/10.; scene->apply(editorScene::DTRANSFORM); } /*! \todo check if used */ void editorView::slotTextReturnPressed(const QString &) { } void editorView::slotRotateChanged(int) { QString tmp; // int r=450-rotateDial->value(); // if ( r >= 360 ) r-=360; int r=rotateDial->value(); tmp.sprintf( "%3i'", r ); rotateLCD->display( tmp ); setTransform(); } void editorView::slotShearChanged(int) { QString tmp; double shearVal; QSlider *sl; sl=qobject_cast(sender()); shearVal=((double)sl->value())/10; tmp.sprintf( "%1.3f", shearVal ); if ( shearVal >= 0 ) tmp.insert( 0, " " ); if(sl==hshearSlider) { hshearLCD->display( tmp ); } else { vshearLCD->display( tmp ); } setTransform(); } QIcon editorView::createColorToolButtonIcon(const QString &imageFile, QColor color) { QPixmap pixmap(22, 30); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); QPixmap image(imageFile); QRect target(0, 0, 22, 22); QRect source(0, 0, 22, 22); painter.fillRect(QRect(0, 22, 22, 8), color); painter.drawPixmap(target, image, source); return QIcon(pixmap); } QMenu *editorView::createColorMenu(const char * slot,int type,QString text) { QMenu *colorMenu = new QMenu; QAction *action = new QAction(text, this); action->setData(type); connect(action, SIGNAL(triggered()),this,slot); colorMenu->addAction(action); return colorMenu; } void editorView::slotItemSelected(itemBase* ib) { sitemParam p; p=ib->getParam(); if(p.type==itemBase::TEXT) { fontComboBox->setCurrentFont(p.font); fontSizeSpinBox->setValue(p.font.pointSize()); boldButton->setChecked(p.font.bold()); underlineButton->setChecked(p.font.underline()); italicButton->setChecked(p.font.italic()); } penWidthSpinBox->setValue(p.pen.widthF()); // int rot=p.rotation-450; // if ( rot <0) // rot+= 360; int rot=p.rotation; rotateDial->setValue(rot); hshearSlider->setValue((int)(p.hShear*10)); vshearSlider->setValue((int)(p.vShear*10)); } void editorView::slotDump() { QString t; int i; QList l=scene->items(); itemBase *b; addToLog(QString("dump editorView of items: %1").arg(l.count()),LOGEDIT); //exclude border for(i=0;itype()>=itemBase::BASE) { b=qgraphicsitem_cast(l.at(i)); switch((int)b->type()) { case itemBase::TEXT: t="Text:"; break; case itemBase::LINE: t="Line:"; break; case itemBase::IMAGE: t="Image:"; break; case itemBase::RECTANGLE: t="Rectangle:"; break; case itemBase::ELLIPSE: t="Ellipse:"; break; case itemBase::SBORDER: t="Border:"; break; default: t=QString("Ill: %1").arg(l.at(i)->type()); break; } addToLog(QString("editorViewItems %1 pos=%2,%3 rectxy=%4,%5 size=%6x%7 depth=%8") .arg(t) .arg(b->pos().x()).arg(b->pos().y()) .arg(b->rect().x()).arg(b->rect().y()) .arg(b->rect().width()).arg(b->rect().height()) .arg(b->zValue()),LOGEDIT); } } } qsstv_8.2.12/qsstv/editor/editorview.h000664 001750 001750 00000006636 12440612574 020006 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef EDITORVIEW_H #define EDITORVIEW_H #include #include "editorscene.h" #include "ui_editorform.h" /** @author Johan Maes - ON4QZ */ class editorForm; enum eactionType {SELECT,COLORPICK,RECTANGLE,ELLIPSE,LINE,IMAGE,TEXT}; enum ePickMode {NOPICK, PICKFILLCOLOR,PICKLINECOLOR}; /** Widget to display the various canvasItems */ class editorView : public QWidget,private Ui::editorForm { Q_OBJECT public: editorView(QWidget *parent = 0); ~editorView(); void readSettings(); void writeSettings(); bool isModified() {return modified;} bool open(QFile &f); void save(QFile &f,bool templ); QImage *getImage() { return image;} void setImage(QImage *ima); editorScene *getScene() {return scene;} public slots: void slotChangeCanvasSize(int); // void slotChangeCanvasSize(int w,int h); // paint actions void slotArrow(); void slotRectangle(); void slotCircle(); void slotColorPicker(); void slotColorPicked(const QPointF &p); void slotText(); void slotImage(); void slotReplay(); void slotLine(); void slotClearAll(); //Font void slotFontChanged(const QFont &); void slotFontSizeChanged(int); void slotPenWidthChanged(double); void slotBold(bool); void slotItalic(bool); void slotUnderline(bool); //Color void slotColorDialog(); void slotGradientDialog(); void slotButtonTriggered(); //Transform void slotRotateChanged(int); void slotShearChanged(int); // void slotShearRotateChanged(double,int); //item feedback void slotItemSelected(itemBase*); //Debug void slotDump(); void slotTextReturnPressed(const QString &); private: editorScene *scene; bool modified; QImage *image; void setTransform(); QIcon createColorToolButtonIcon(const QString &imageFile, QColor color); QMenu *createColorMenu(const char *,int,QString text); int canvasSizeIndex; int currentPointSize; int currentFontIndex; double currentPenWidth; QString txt; QImage *colorPickImage; ePickMode pickMode; }; #endif qsstv_8.2.12/qsstv/editor/gradientdialog.cpp000664 001750 001750 00000024130 12440612574 021122 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "gradientdialog.h" #include "qsstvdefs.h" #include gradientDialog::gradientDialog(QWidget *parent):QDialog(parent), Ui::gradientForm() { setupUi(this); readSettings(); connect(color1Button,SIGNAL(clicked()),SLOT(slotColorDialog())); connect(color2Button,SIGNAL(clicked()),SLOT(slotColorDialog())); connect(color3Button,SIGNAL(clicked()),SLOT(slotColorDialog())); connect(color4Button,SIGNAL(clicked()),SLOT(slotColorDialog())); previewLabel->setBackgroundRole(QPalette::Base); g=NULL; slotUpdate(); connect(pos1SpinBox,SIGNAL(valueChanged(int)),SLOT(slotUpdate())); connect(pos2SpinBox,SIGNAL(valueChanged(int)),SLOT(slotUpdate())); connect(pos3SpinBox,SIGNAL(valueChanged(int)),SLOT(slotUpdate())); connect(pos4SpinBox,SIGNAL(valueChanged(int)),SLOT(slotUpdate())); connect(dial,SIGNAL(valueChanged(int)),SLOT(slotUpdate())); connect(noGradientButton,SIGNAL(clicked()),SLOT(slotUpdate())); connect(linearGradientButton,SIGNAL(clicked()),SLOT(slotUpdate())); connect(radialGradientButton,SIGNAL(clicked()),SLOT(slotUpdate())); connect(conicalGradientButton,SIGNAL(clicked()),SLOT(slotUpdate())); } gradientDialog::~gradientDialog() { writeSettings(); if(g==NULL) delete g; } void gradientDialog::readSettings() { QSettings qSettings; qSettings.beginGroup ("Editor"); gParam.color1 = qSettings.value("gradcolor1", QColor(Qt::red)).value(); gParam.color2 = qSettings.value("gradcolor2", QColor(Qt::green )).value(); gParam.color3 = qSettings.value("gradcolor3", QColor(Qt::yellow)).value(); gParam.color4 = qSettings.value("gradcolor4", QColor(Qt::blue )).value(); gParam.pos1=qSettings.value("gradpos1", 0 ).toInt(); gParam.pos2=qSettings.value("gradpos2", 0 ).toInt(); gParam.pos3=qSettings.value("gradpos3", 0 ).toInt(); gParam.pos4=qSettings.value("gradpos4", 0 ).toInt(); pos1SpinBox->setValue(gParam.pos1); pos2SpinBox->setValue(gParam.pos2); pos3SpinBox->setValue(gParam.pos3); pos4SpinBox->setValue(gParam.pos4); gParam.direction=qSettings.value("graddirection", 0 ).toInt(); dial->setValue((gParam.direction+90)%360); if(qSettings.value("nogradbutton", 1 ).toBool()) { noGradientButton->setChecked(true); gParam.type=sgradientParam::NONE; } else if(qSettings.value("lineargradbutton", 0 ).toBool()) { linearGradientButton->setChecked(true); gParam.type=sgradientParam::LINEAR;; } else if(qSettings.value("radialgradbutton", 0 ).toBool()) { radialGradientButton->setChecked(true); gParam.type=sgradientParam::RADIAL; } else if(qSettings.value("conicalgradbutton", 0 ).toBool()) { conicalGradientButton->setChecked(true); gParam.type=sgradientParam::CONICAL; } qSettings.endGroup(); } void gradientDialog::writeSettings() { QSettings qSettings; qSettings.beginGroup ("Editor" ); qSettings.setValue ("gradcolor1", gParam.color1); qSettings.setValue ("gradcolor2", gParam.color2); qSettings.setValue ("gradcolor3", gParam.color3); qSettings.setValue ("gradcolor4", gParam.color4); qSettings.setValue ("gradpos1", gParam.pos1); qSettings.setValue ("gradpos2", gParam.pos2); qSettings.setValue ("gradpos3", gParam.pos3); qSettings.setValue ("gradpos4", gParam.pos4); qSettings.setValue ("graddirection", gParam.direction); qSettings.setValue ("nogradbutton",noGradientButton->isChecked()); qSettings.setValue ("lineargradbutton",linearGradientButton->isChecked()); qSettings.setValue ("radialgradbutton",radialGradientButton->isChecked()); qSettings.setValue ("conicalgradbutton",conicalGradientButton->isChecked()); qSettings.endGroup(); } void sgradientParam::load(QDataStream &str) { int t; str >> color1; str >> color2; str >> color3; str >> color4; str >> pos1; str >> pos2; str >> pos3; str >>pos4; str >> t; type=(gType)t; str >> direction; } void sgradientParam::save(QDataStream &str) { str << color1; str << color2; str << color3; str << color4; str << pos1; str << pos2; str << pos3; str << pos4; str << (int)type; str << direction; } void gradientDialog::slotColorDialog() { QColor c; QPushButton *act=qobject_cast(sender()); if (act==color1Button) { c=QColorDialog::getColor(gParam.color1,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) gParam.color1=c; } else if (act==color2Button) { c=QColorDialog::getColor(gParam.color2,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) gParam.color2=c; } else if (act==color3Button) { c=QColorDialog::getColor(gParam.color3,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) gParam.color3=c; } else if (act==color4Button) { c=QColorDialog::getColor(gParam.color4,this,"",QColorDialog::ShowAlphaChannel); if (c.isValid()) gParam.color4=c; } slotUpdate(); } /*! \todo split param update from graphic creation */ void gradientDialog::slotUpdate() { QString s; QPalette palette; QBrush brush; gParam.direction=(270+dial->value())%360; gParam.pos1=pos1SpinBox->value(); gParam.pos2=pos2SpinBox->value(); gParam.pos3=pos3SpinBox->value(); gParam.pos4=pos4SpinBox->value(); if(noGradientButton->isChecked()) gParam.type=sgradientParam::NONE; else if (linearGradientButton->isChecked()) gParam.type=sgradientParam::LINEAR; else if (radialGradientButton->isChecked()) gParam.type=sgradientParam::RADIAL; else if (conicalGradientButton->isChecked()) gParam.type=sgradientParam::CONICAL; s=gParam.color1.name(); color1Button->setStyleSheet("background-color: "+s+"; border-style: outset; border-width: 2px;border-radius: 10px; border-color: beige; padding: 6px"); s=gParam.color2.name(); color2Button->setStyleSheet("background-color: "+s+"; border-style: outset; border-width: 2px;border-radius: 10px; border-color: beige; padding: 6px"); s=gParam.color3.name(); color3Button->setStyleSheet("background-color: "+s+"; border-style: outset; border-width: 2px;border-radius: 10px; border-color: beige; padding: 6px"); s=gParam.color4.name(); color4Button->setStyleSheet("background-color: "+s+"; border-style: outset; border-width: 2px;border-radius: 10px; border-color: beige; padding: 6px"); // brush.setStyle(Qt::SolidPattern); // brush.setColor(gParam.color1); // palette.setBrush(QPalette::Active, QPalette::Button, brush); // color1Button->setPalette(palette); // brush.setColor(gParam.color2);11 // palette.setBrush(QPalette::Active, QPalette::Button, brush); // color2Button->setPalette(palette); // brush.setColor(gParam.color3); // palette.setBrush(QPalette::Active, QPalette::Button, brush); // color3Button->setPalette(palette); // brush.setColor(gParam.color4); // palette.setBrush(QPalette::Active, QPalette::Button, brush); // color4Button->setPalette(palette); brush.setStyle(Qt::SolidPattern); if(gParam.type!=sgradientParam::NONE) { QBrush br(buildGradient(gParam,previewLabel->rect())); palette.setBrush(QPalette::Active, QPalette::Base, br); } else { QBrush br(gParam.color1); palette.setBrush(QPalette::Active, QPalette::Base, br); } previewLabel->setPalette(palette); } void gradientDialog::selectGradient() { exec(); } void grSetup (sgradientParam prm,QGradient &g) { g.setColorAt(prm.pos1/100.,prm.color1); if(prm.pos2<=prm.pos1) return ; g.setColorAt(prm.pos2/100.,prm.color2); if(prm.pos3<=prm.pos2) return ; g.setColorAt(prm.pos3/100.,prm.color3); if(prm.pos4<=prm.pos3) return ; g.setColorAt(prm.pos4/100.,prm.color4); } QGradient buildGradient(sgradientParam prm, QRectF f) { qreal w=f.width(); qreal h=f.height(); qreal d=(double)prm.direction; qreal x1,y1,x2,y2; qreal temp; if(prm.type==sgradientParam::NONE) { QLinearGradient g(0,0,0,0); grSetup(prm,g); return g; } if(prm.type==sgradientParam::LINEAR) { if(fabs(w/2*tan(M_PI/2-d*M_PI/180))<=(w/2)) { x1=f.x()+w/2-(w/2*tan(M_PI/2-d*M_PI/180.)); y1=f.y()+h; x2=f.x()+w/2+(w/2*tan(M_PI/2-d*M_PI/180.)); y2=f.y(); if ((prm.direction>180) && (prm.direction<=359)) { temp=x1; x1=x2;x2=temp; temp=y1; y1=y2;y2=temp; } } else { x1=f.x(); y1=f.y()+h/2+(h/2*tan(d*M_PI/180.)); x2=f.x()+w; y2=f.y()+h/2-(h/2*tan(d*M_PI/180.)); if ((prm.direction>90) && (prm.direction<=270)) { temp=x1; x1=x2;x2=temp; temp=y1; y1=y2;y2=temp; } } QLinearGradient g(x1,y1,x2,y2); grSetup(prm,g); return g; } else if(prm.type==sgradientParam::RADIAL) { QRadialGradient g(QPointF(f.x()+f.width()/2,f.y()+f.height()/2),f.width()/2); grSetup(prm,g); return g; } else if(sgradientParam::CONICAL) { QConicalGradient g(QPointF(f.x()+f.width()/2,f.y()+f.height()/2),prm.direction); grSetup(prm,g); return g; } } qsstv_8.2.12/qsstv/editor/gradientdialog.h000664 001750 001750 00000004751 12440612574 020576 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef GRADIENTDIALOG_H #define GRADIENTDIALOG_H #include #include "ui_gradientform.h" struct sgradientParam { enum gType {NONE,LINEAR,RADIAL,CONICAL}; sgradientParam() { type=NONE; } QColor color1; QColor color2; QColor color3; QColor color4; int pos1; int pos2; int pos3; int pos4; gType type; int direction; void load(QDataStream &str); void save(QDataStream &str); }; /** @author Johan Maes - ON4QZ */ class gradientForm; /** Widget to disply the various canvasItems */ class gradientDialog : public QDialog,private Ui::gradientForm { Q_OBJECT public: gradientDialog(QWidget *parent = 0); ~gradientDialog(); void readSettings(); void writeSettings(); void selectGradient(); sgradientParam param() {return gParam;} // QGradient *constructGradient( QRectF f); public slots: void slotColorDialog(); void slotUpdate(); private: sgradientParam gParam; void update(); QGradient *g; }; QGradient buildGradient(sgradientParam prm, QRectF f); #endif qsstv_8.2.12/qsstv/editor/gradientform.ui000664 001750 001750 00000027035 12440612574 020470 0ustar00jomajoma000000 000000 gradientForm 0 0 300 330 300 330 300 330 9 Gradients QLayout::SetMinimumSize 45 16777215 Color Position true 45 16777215 100 45 16777215 100 45 16777215 100 45 16777215 100 Direction Qt::AlignCenter 0 0 170 0 0 170 0 0 170 0 0 0 360 1 90 90 true false true 10.000000000000000 true Qt::Vertical 20 40 130 100 130 100 Gradient type Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter None true Linear Radial Conical 130 100 130 100 0 255 127 0 255 127 255 255 255 true QFrame::Panel QFrame::Sunken 2 Qt::AlignCenter 0 0 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok false buttonBox accepted() gradientForm accept() 248 254 157 274 buttonBox rejected() gradientForm reject() 316 260 286 274 qsstv_8.2.12/qsstv/editor/graphicitems.cpp000664 001750 001750 00000040376 12440612574 020636 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "graphicitems.h" #include "qsstvglobal.h" #include "editorscene.h" /*! */ static QPainterPath qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen) { // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0 // if we pass a value of 0.0 to QPainterPathStroker::setWidth() const qreal penWidthZero = qreal(0.00000001); if (path == QPainterPath()) return path; QPainterPathStroker ps; ps.setCapStyle(pen.capStyle()); if (pen.widthF() <= 0.0) ps.setWidth(penWidthZero); else ps.setWidth(pen.widthF()); ps.setJoinStyle(pen.joinStyle()); ps.setMiterLimit(pen.miterLimit()); QPainterPath p = ps.createStroke(path); p.addPath(path); return p; } itemBase::itemBase(QMenu *cntxtMenu) { setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); setAcceptHoverEvents (true); param.locked=false; param.modified=true; param.menu=cntxtMenu; } void itemBase::highlightSelected(QPainter *painter,const QStyleOptionGraphicsItem *option) { /// qreal itemPenWidth = pen().widthF(); // const qreal pad = itemPenWidth / 2; // const qreal pad = itemPenWidth; const qreal penWidth = 0; // cosmetic pen const QColor fgcolor = option->palette.windowText().color(); const QColor bgcolor( // ensure good contrast against fgcolor fgcolor.red() > 127 ? 0 : 255, fgcolor.green() > 127 ? 0 : 255, fgcolor.blue() > 127 ? 0 : 255); painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine)); painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine)); painter->setBrush(Qt::NoBrush); painter->drawRect(boundingRect()); // painter->drawRect(boundingRect().adjusted(pad, pad, -pad, -pad)); } QPainterPath itemBase::shape() const { QPainterPath path; path.addRect(param.rct); return qt_graphicsItem_shapeFromPath(path,pen()); } void itemBase::setBrush(QColor c) { param.fillColor=c; QAbstractGraphicsShapeItem::setBrush(param.fillColor); } void itemBase::load(QDataStream &str) { // str << type(); this item is already read by the loader QTransform f; QPointF p; QRectF r; QColor c; QPen pn; QBrush br; QString t; QFont fnt; qreal z; str >> param.rotation; str >> param.hShear, str >> param.vShear; str >> z; setZValue(z); param.zValue=z; str >> p; setPos(p); str >> r; setRect(r); str >> c; param.fillColor=c; setBrush(c); str >> pn; setPen(pn); str >> br; QAbstractGraphicsShapeItem::setBrush(br); str >> param.locked; str >>param.im; str >>t; setText(t); str >>fnt; setFont(fnt); str >> param.line; param.gradient.load(str); setTransform (); } void itemBase::save(QDataStream &str) { str << type(); str << param.rotation; str << param.hShear, str << param.vShear; str << zValue(); str << pos(); str << rect(); str << param.fillColor; str << pen(); str << brush(); str << param.locked; str << param.im; str << param.txt; str << param.font; str << param.line; param.gradient.save(str); } void itemBase::setTransform () { QTransform tx; tx.translate(rect().x()+rect().width()/2,rect().y()+rect().height()/2); tx.shear(param.hShear,param.vShear); tx.rotate(param.rotation); tx.translate(-rect().x()-rect().width()/2,-rect().y()-rect().height()/2); QAbstractGraphicsShapeItem::setTransform(tx,false); update(); } void itemBase::setTransform ( int rot,double hs,double vs) { param.rotation=rot; param.hShear=hs; param.vShear=vs; setTransform (); } void itemBase::hoverMoveEvent ( QGraphicsSceneHoverEvent * event ) { if(((editorScene*)scene())->mode==editorScene::PICK) { setCursor(*cpCursor); return; } if(((editorScene*)scene())->mode==editorScene::INSERT) { setCursor(Qt::ArrowCursor); return; } if(param.locked) { grab = NO; setCursor(Qt::ForbiddenCursor); } else if(type()!=LINE) { grab = getCorner(event->pos()); if(type()==TEXT) grab=NO; if ((grab == CUL)|| (grab == CDR)) setCursor(Qt::SizeFDiagCursor); if ((grab == CUR)|| (grab == CDL)) setCursor(Qt::SizeBDiagCursor); if ((grab == HU) || (grab == HD)) setCursor(Qt::SizeVerCursor); if ((grab == VL) || (grab == VR)) setCursor(Qt::SizeHorCursor); if (grab == NO) setCursor(Qt::OpenHandCursor); } else { grab=NO; setCursor(Qt::CrossCursor); } //QAbstractGraphicsShapeItem::hoverEnterEvent(event); QAbstractGraphicsShapeItem::hoverMoveEvent(event); } itemBase::corner itemBase::getCorner( QPointF mouse) { double x = rect().x(); double y = rect().y(); double h = rect().height(); double w = rect().width(); double diff; diff=w; if (diff>h) diff=h; diff/=10; if (diff>10) diff=10; else if (diff<1) diff=1; QRectF cul (x,y, diff,diff); QRectF cur (x+w-diff,y, diff,diff); QRectF cdl (x,y+h-diff,diff,diff); QRectF cdr (x+w-diff,y+h-diff,diff,diff); QRectF hu (x+diff,y,w-(2*diff),diff); QRectF hd (x+diff,y+h-diff,w-(2*diff),diff); QRectF vl (x,y+diff,diff,h-(2*diff)); QRectF vr (x+w-diff,y+diff,diff,h-(2*diff)); if ( cul.contains(mouse) ) return CUL; if ( cur.contains(mouse) ) return CUR; if ( cdl.contains(mouse) ) return CDL; if ( cdr.contains(mouse) ) return CDR; if ( hu.contains(mouse) ) return HU; if ( hd.contains(mouse) ) return HD; if ( vl.contains(mouse) ) return VL; if ( vr.contains(mouse) ) return VR; return NO; } void itemBase::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) { if(((editorScene*)scene())->mode==editorScene::PICK) return; if(((editorScene*)scene())->mode==editorScene::INSERT) return; if(param.locked) return; QPointF mouse = event->pos(); //resize! prepareGeometryChange(); param.modified=true; switch ( grab) { case NO : QAbstractGraphicsShapeItem::mouseMoveEvent(event); break; case HD : if(mouse.y()-rect().y()>1) setRect(rect().x(),rect().y(),rect().width(),mouse.y()-rect().y()); break; case HU : if(rect().height()+(rect().y()-mouse.y())>0) setRect(rect().x(),mouse.y(),rect().width(),rect().height()+(rect().y()-mouse.y())); break; case VR : if(mouse.x()-rect().x()>1) setRect(rect().x(),rect().y(),mouse.x()-rect().x(),rect().height()); break; case VL : if(rect().width()+(rect().x()-mouse.x())>1) setRect(mouse.x(),rect().y(),rect().width()+(rect().x()-mouse.x()),rect().height()); break; case CDR : if(((mouse.x()-rect().x())>1)&&((mouse.y()-rect().y())>1)) setRect(rect().x(),rect().y(),mouse.x()-rect().x(),mouse.y()-rect().y()); break; case CUR : if(((mouse.x()-rect().x())>1)&&((rect().height()+(rect().y()-mouse.y()))>1)) setRect(rect().x(),mouse.y(),mouse.x()-rect().x(),rect().height()+(rect().y()-mouse.y())); break; case CDL : if(((rect().width()+(rect().x()-mouse.x()))>1)&&((mouse.y()-rect().y())>1)) setRect(mouse.x(),rect().y(),rect().width()+(rect().x()-mouse.x()),mouse.y()-rect().y()); break; case CUL : if(((rect().width()+(rect().x()-mouse.x()))>1)&&((rect().height()+(rect().y()-mouse.y()))>1)) setRect(mouse.x(),mouse.y(),rect().width()+(rect().x()-mouse.x()),rect().height()+(rect().y()-mouse.y())); break; } update(); } QString itemBase::getTypeStr() { QString tp; switch(type()) { case BASE: tp="Base"; break; case RECTANGLE: tp="Rectangle"; break; case ELLIPSE: tp="Ellipse"; break; case IMAGE: tp="Image"; break; case LINE: tp="Line"; break; case TEXT: tp="Text"; break; case REPLAY: tp="Replay"; break; case SBORDER: tp="SBorder"; break; } return tp; } void itemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { if(((editorScene*)scene())->mode==editorScene::PICK) return; setSelected(true); param.menu->exec(event->screenPos()); } // Text graphics itemText::itemText(QMenu *cntxtMenu): itemBase(cntxtMenu) { param.font.setFamily("Times"); param.font.setPointSize(24); param.font.setStyleStrategy(QFont::ForceOutline); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); setAcceptHoverEvents (true); } itemText::~itemText() { } void itemText::setText(const QString &t) { QPainterPath tt; prepareGeometryChange(); param.modified=true; param.txt=t; tt.addText(0, 0, param.font, param.txt); param.rct=tt.controlPointRect(); update(); } void itemText::setFont(QFont f) { QPainterPath tt; prepareGeometryChange(); param.modified=true; param.font=f; param.font.setStyleStrategy(QFont::ForceOutline); tt.addText(0, 0, param.font, param.txt); param.rct=tt.controlPointRect(); update(); } //QRectF itemText::boundingRect() const //{ // qreal d=pen().widthF(); // QPainterPath tt; // tt.addText(0, 0, param.font, param.txt); // return tt.controlPointRect().adjusted(-d/2,-d/2,d/2,d/2); //} void itemText::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { QPainterPath tt; tt.addText(0, 0, param.font, param.txt); if (param.modified) { param.modified=false; if(param.gradient.type!=sgradientParam::NONE) { QAbstractGraphicsShapeItem::setBrush(buildGradient(param.gradient,rect())); } else { QAbstractGraphicsShapeItem::setBrush(param.fillColor); } } painter->setPen(pen()); painter->setBrush(brush()); painter->setFont(param.font); painter->drawPath(tt); if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } itemRectangle::itemRectangle(QMenu *cntxtMenu): itemBase(cntxtMenu) { setRect(0,0,100,100); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); } void itemRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { // if (resized ) prepareGeometryChange(); if (param.modified) { param.modified=false; if(param.gradient.type!=sgradientParam::NONE) { QAbstractGraphicsShapeItem::setBrush(buildGradient(param.gradient,rect())); } else { QAbstractGraphicsShapeItem::setBrush(param.fillColor); } } painter->setPen(pen()); painter->setBrush(brush()); painter->drawRect(param.rct); if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } itemEllipse::itemEllipse(QMenu *cntxtMenu): itemBase(cntxtMenu) { setRect(0,0,100,100); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); } void itemEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { // if(resized) prepareGeometryChange(); if (param.modified) { param.modified=false; if(param.gradient.type!=sgradientParam::NONE) { QAbstractGraphicsShapeItem::setBrush(buildGradient(param.gradient,rect())); } else { QAbstractGraphicsShapeItem::setBrush(param.fillColor); } } painter->setPen(pen()); painter->setBrush(brush()); painter->drawEllipse(param.rct); if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } itemImage::itemImage(QMenu *cntxtMenu): itemBase(cntxtMenu) { setRect(0,0,100,100); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); } void itemImage::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { QImage tim; tim=param.im.scaled(param.rct.width(),param.rct.height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation); qreal pad=pen().widthF()/2; painter->drawImage(param.rct.adjusted(pad,pad,-pad,-pad),tim); painter->setBrush(Qt::NoBrush); painter->setPen(pen()); //painter->drawRect(param.rct); if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } itemLine::itemLine(QMenu *cntxtMenu): itemBase(cntxtMenu) { // setRect(0,0,100,100); param.line.setPoints(QPoint(0,0),QPoint(100,0)); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); } QPainterPath itemLine::shape() const { QPainterPath path; if (param.line.isNull()) return path; path.moveTo(param.line.p1()); path.lineTo(param.line.p2()); return qt_graphicsItem_shapeFromPath(path,pen()); } QRectF itemLine::boundingRect() const { if (pen().widthF() == 0.0) { const qreal x1 = param.line.p1().x(); const qreal x2 = param.line.p2().x(); const qreal y1 = param.line.p1().y(); const qreal y2 = param.line.p2().y(); qreal lx = qMin(x1, x2); qreal rx = qMax(x1, x2); qreal ty = qMin(y1, y2); qreal by = qMax(y1, y2); return QRectF(lx, ty, rx - lx, by - ty); } return shape().controlPointRect(); } void itemLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { // if (resized ) prepareGeometryChange(); painter->setPen(pen()); painter->setBrush(brush()); painter->drawLine(param.line); if (option->state & QStyle::State_Selected) // highlightSelected(painter,option); { const qreal penWidth = 0; // cosmetic pen const QColor fgcolor = option->palette.windowText().color(); const QColor bgcolor( // ensure good contrast against fgcolor fgcolor.red() > 127 ? 0 : 255, fgcolor.green() > 127 ? 0 : 255, fgcolor.blue() > 127 ? 0 : 255); painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine)); painter->setBrush(Qt::NoBrush); painter->strokePath(shape(),QPen(bgcolor, penWidth, Qt::SolidLine)); painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine)); painter->setBrush(Qt::NoBrush); painter->strokePath(shape(),QPen(option->palette.windowText(), 0, Qt::DashLine)); } } itemReplayImage::itemReplayImage(QMenu *cntxtMenu): itemBase(cntxtMenu) { setRect(0,0,100,100); setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); } void itemReplayImage::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { QImage tim; if (param.im.isNull()) { QBrush b(Qt::black,Qt::Dense5Pattern); painter->setPen(pen()); painter->setBrush(b); painter->drawRect(param.rct); } else { tim=param.im.scaled(param.rct.width(),param.rct.height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation); qreal pad=pen().widthF()/2; // painter->drawImage(param.rct.adjusted(pad,pad,-pad,-pad), param.im, param.im.rect()); painter->drawImage(param.rct.adjusted(pad,pad,-pad,-pad), tim); painter->setBrush(Qt::NoBrush); painter->setPen(pen()); } if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } itemBorder::itemBorder(QMenu *cntxtMenu): itemBase(cntxtMenu) { setRect(0,0,100,100); setFlags(QGraphicsItem::QGraphicsItem::ItemIgnoresTransformations); } void itemBorder::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *) { // if (resized ) prepareGeometryChange(); if (param.modified) { param.modified=false; if(param.gradient.type!=sgradientParam::NONE) { QAbstractGraphicsShapeItem::setBrush(buildGradient(param.gradient,rect())); } else { QAbstractGraphicsShapeItem::setBrush(param.fillColor); } } painter->setPen(pen()); painter->setBrush(Qt::NoBrush); painter->drawRect(param.rct); if (option->state & QStyle::State_Selected) highlightSelected(painter,option); } qsstv_8.2.12/qsstv/editor/graphicitems.h000664 001750 001750 00000014415 12440612574 020276 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef GRAPHICITEMS_H #define GRAPHICITEMS_H #include #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #include "gradientdialog.h" #include "qsstvdefs.h" struct sitemParam { // must be set before returning parameters qreal zValue; int type; QPen pen; QBrush brush; QPointF position; // are used dynamically, no need to setup QFont font; QString txt; int rotation; double hShear; double vShear; QImage im; sgradientParam gradient; QRectF rct; bool locked; QLineF line; bool modified; QColor fillColor; QMenu *menu; }; class itemBase : public QAbstractGraphicsShapeItem { public: enum egraphType {BASE=QGraphicsItem::UserType+1,RECTANGLE,ELLIPSE,IMAGE,LINE,TEXT,REPLAY,SBORDER}; itemBase(QMenu *cntxtMenu); virtual QRectF rect() { return param.rct;} virtual void setRect( const QRectF & rectangle ) { param.rct=rectangle; param.modified=true; } virtual void setRect( qreal x, qreal y, qreal width, qreal height ) { param.rct=QRectF(x,y,width,height); param.modified=true; } void hoverMoveEvent ( QGraphicsSceneHoverEvent * event ); void mouseMoveEvent ( QGraphicsSceneMouseEvent * event ); virtual QRectF boundingRect() const { return shape().controlPointRect(); } QString getTypeStr(); void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); void setLocked(bool b) {param.locked=b;} void setGradient(sgradientParam pm) { param.modified=true; param.gradient=pm;} void setBrush(QColor c); void setImage(QImage ima) {param.im=ima;} virtual QPainterPath shape() const; virtual void setText(const QString &) {}; virtual void setFont(QFont) { } QString text() const { return param.txt;} void load(QDataStream &str); void save(QDataStream &str); void setTransform ( int rot,double hs,double vs); sitemParam getParam() { param.zValue=zValue(); param.type=type(); param.pen=pen(); param.brush=brush(); param.position=pos(); return param; } void setParam(sitemParam sp) { setPen(sp.pen); setBrush(sp.fillColor); setFont(sp.font); // are used dynamically, no need to setup param.txt=sp.txt; param.rotation=sp.rotation; param.hShear=sp.hShear; param.vShear=sp.vShear; setTransform (param.rotation,param.hShear,param.vShear); param.im=sp.im; param.gradient=sp.gradient; param.rct=sp.rct; param.locked=sp.locked; param.line=sp.line; param.modified=true; param.fillColor=sp.fillColor; param.menu=sp.menu; } protected: void highlightSelected(QPainter *painter,const QStyleOptionGraphicsItem *option); sitemParam param; private: enum corner {CUL,CUR,CDL,CDR,HU,HD,VL,VR,NO}; void setTransform (); corner getCorner( QPointF mouse); bool grabbed; corner grab; }; class itemText : public itemBase { public: itemText(QMenu *cntxtMenu); ~itemText(); void setText(const QString &t); void setFont(QFont f); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); //QRectF boundingRect() const; int type() const {return TEXT;} void hover(){;} }; class itemRectangle : public itemBase { public: itemRectangle(QMenu *cntxtMenu); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); int type() const {return RECTANGLE;} }; class itemEllipse : public itemBase { public: itemEllipse(QMenu *cntxtMenu); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); // QRectF boundingRect() const; int type() const {return ELLIPSE;} }; class itemImage : public itemBase { public: itemImage(QMenu *cntxtMenu); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); // QRectF boundingRect() const; int type() const {return IMAGE;} }; class itemLine : public itemBase { public: itemLine(QMenu *cntxtMenu); void setRect( const QRectF & rectangle ) { prepareGeometryChange(); param.rct=rectangle; param.line.setPoints(param.rct.topLeft(),param.rct.bottomRight()); param.modified=true; } void setRect( qreal x, qreal y, qreal width, qreal height ) { prepareGeometryChange(); param.rct=QRectF(x,y,width,height); param.line.setLine(x,y,width,height); param.modified=true; } QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); QPainterPath shape() const; int type() const {return LINE;} }; class itemReplayImage : public itemBase { public: itemReplayImage(QMenu *cntxtMenu); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); int type() const {return REPLAY;} }; class itemBorder : public itemBase { public: itemBorder(QMenu *cntxtMenu); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); int type() const {return SBORDER;} }; #endif qsstv_8.2.12/qsstv/editor/qdialog_p.h000664 001750 001750 00000006572 12440612574 017563 0ustar00jomajoma000000 000000 /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QDIALOG_P_H #define QDIALOG_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "private/qwidget_p.h" #include "QtCore/qeventloop.h" #include "QtCore/qpointer.h" #include "QtGui/qdialog.h" #include "QtGui/qpushbutton.h" QT_BEGIN_NAMESPACE class QSizeGrip; class QDialogPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QDialog) public: QDialogPrivate() : mainDef(0), orientation(Qt::Horizontal),extension(0), doShowExtension(false), #ifndef QT_NO_SIZEGRIP resizer(0), sizeGripEnabled(false), #endif rescode(0), resetModalityTo(-1), wasModalitySet(true), eventLoop(0) {} QPointer mainDef; Qt::Orientation orientation; QWidget *extension; bool doShowExtension; QSize size, min, max; #ifndef QT_NO_SIZEGRIP QSizeGrip *resizer; bool sizeGripEnabled; #endif QPoint lastRMBPress; void setDefault(QPushButton *); void setMainDefault(QPushButton *); void hideDefault(); void resetModalitySetByOpen(); #ifdef Q_WS_WINCE_WM void _q_doneAction(); #endif #ifdef Q_WS_MAC virtual void mac_nativeDialogModalHelp() {} #endif int rescode; int resetModalityTo; bool wasModalitySet; QPointer eventLoop; }; QT_END_NAMESPACE #endif // QDIALOG_P_H qsstv_8.2.12/qsstv/editor/textform.ui000664 001750 001750 00000004220 12440612574 017646 0ustar00jomajoma000000 000000 textForm 0 0 284 103 Enter text Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok Qt::Horizontal 40 20 Qt::Vertical 20 19 buttonBox accepted() textForm accept() 248 254 157 274 buttonBox rejected() textForm reject() 316 260 286 274 qsstv_8.2.12/qsstv/icons/arrow.png000664 001750 001750 00000000452 12440612574 017127 0ustar00jomajoma000000 000000 ‰PNG  IHDRn½¤°bKGD½]ì^IDATxÚÍÒÁÀ Phöÿ¿Ü̃=ÊÍúB$q_‘ätÿ1câ¨ÁÄÑ#Ï¡BÇ¡{hn°æ+>àΗÊ<|s¥3ܯ Ó¯ßvÀE3Ç}jý› ¬üÖzI¼#ÎÿCtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com‘º!¸*tEXtSignature1b33aaff61d83f1bfdabf2d1ccd5cef4e†ÖIEND®B`‚qsstv_8.2.12/qsstv/icons/camera.png000664 001750 001750 00000003133 12440612574 017224 0ustar00jomajoma000000 000000 ‰PNG  IHDR szzôgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<íIDATxÚbüÿÿ?Ã@€bb`@î€pЀ; €X9ìììÂÂÂŒŒŒBÿþýûüîÝ» ?þüŒK3P£±±q°€€€Ø,©(ÍÀÊÊÊa30€T0ÿüýûÿÊ•+ž>}z €Aúôôôlùùù444²´ P=3PÝ¿>\*ìò¿Aíƒþ÷ïß@Ë»»»S¹¸¸þüùÃsˆzL3211üûûÈÿv3#Ã? øÒ¥ËžØ‹‘‘Qðºuë–+((°þþýd0ÌPôè- â#ŠL¿yó†áû÷ï lll`Ë!ÆÀ´”‡‡‡………áó§O ÿ˜^~ffægxðâóÿï Šò²Ò@Ϫ‹ªªª™ŠŠ +r°Á|¢aä0†ñ¡V/!!Á //¶ ¦çÐÒׯ_3üøñƒ…™™‹›‡aߥo ÏýaØyâ9C¦#7ƒ¡èï h Pø ³ä#BdÉû÷ï€i…èxf  KA¡s80M0ðññ1<þœáÅ‹`¶š4 ƒÈïÿ Zþ" zRL ŸžþÛ @(‰d,¸Ñ18˃äsåÀô»wïÃǾ|ù~`B‡"(T@ê@Ž~ú샆,Ãÿ¿Àï×_†sÿÕ ˆiþüù3Ö ðë×/8 `þƒ=zVr<Ì,9T]]———˜›^¼z‰?þÂ*H=@ðäɆ[·nÁR7Øp#`¾þöíX äCp|ƒ‚÷Õ«W@Cù^<ưsç6pÜ™-Ö[zãÆ °#@QRÏÉÉÉ€Ý »ˆÆä Gfƒ&"" ## Aü³gÏ0d¤§3ügcàäâeX¼x9ƒ§—Crr ØAÏ€ÁÒ² äPnå  &˜pÅ=Ld©¸¸8X(º@qÍÌÌÄPWSÍÀ(êÆP=é4CÓôc úžm [¶le8yâ8ØÇ èøúõ+¨@›+K@4Ìw KÊ8Ìæààk¥xá/^e?˜c_¾|‰’Ó` ô\€^á ;æüùóà”Ae-oÆ«[¯A¡¬hàõÃãÇá‰½Ö ¬i[­¢aEñ±cÇÀñ rHä[/aQÊë°¸ùüáÇ ÈU9r ,[Á*ä"gȉ@E0ˆ¯­­ Žc˜e ý°Ê  ìv÷î]p(Áó,7¸(ùT#g?d aB¯¯^½ .å@úaõL (ÈAj@…²ïa‰” Až  Å¬¦¦¦` èÕ..>rEn;ÀÊ UƒmE<ÉIÎùýÎïs~ùý9‡ž4nݺå‹F£‡t]oÏd2UŠ¢Ìµ´´|ÐÖÖ}œ û/ðøøøA>¶U7 Gb.P(UUáõzcÉd²©§§G+g+”ö÷÷‹SS¡ï<Ï…ÆÆÆ]55n‡,É$ ‹‚ ™Lz¶mÛöñãœZöûýÖ­[· UVV½ïr¹*càœƒˆÀ9‡ÝnçMMM¨®®ÞüøqçÁ½½½Bk[ë`¡ m€B¡€\.‡|>]×aš&J¥<ZZZ`·Û=»wï>V¼,ÆcccG¯\¹òU$A.—C¡P€ÏçCCCÖ¯_ÆJ¥ÚÛÛáp8À9~k\ñµ>|øö22-̓„EQ$egWWE£QRU•TU¥…»C”½yˆ‚çV²–m6mÚ”\ s8´gÏêïï'MÓÈ4MÊçó´0?A<÷™êUJ ¿C~¿ÿÅGY–G½w¹\g$Iêq»Ýذa:;;ÑÑѺº:(ŠQïÅ/ÿ', Wší×¶¢Âý6"pš1ÖJD|U(xš››‹ÓÓÓ¤ë:†Aœsz0¸¡RúÆýÑG™û©8{–(?AfêwJ_ßG¿üÜý€µ¬*ˆ(V,of³Ù4ç’$1vO§@Û3vBz&#w\› ÊPœÏãÇßtuuÙÊÖ±,ËÅH$r*‘H,“ó’IÔ!+VTU*˜NÁXÀ̇`.&ÀÅuXÃî¸ö½õÒeÁŠ¢'Ožü2‹M«ªº$k^ì!+6ÈŠMÕ³XHLBKOÂȇÁ9SêQ!FÞcŒI«ÀŒ1app0?55õu<‡¦=| XÃ'• Ȳ ’dEx&„Bj‹™ÌEœ¹ YwZNçšU`Ã0{÷îý!‹ÎÍÍ-éûsàÕo@V¬,VÔ:³¸ BËQÈÞAÛ‘N§/§R©ì*°¦iü~"K“““ŸÎÎÎòx<þî=É^Q²B´X‘KÏ ¿0¢m'Ò93><<üùª!"8ŽÆGÊùýþK###4??O¦i‘÷Súr3…/®£©ßÞ¦ðôÏŸ8q¢³lƒ@*•š~°&"êííýÀvƘÕçóA–e@y¼r,Ou ¤lÆt$½$‘H\œÁ€#ÀA˜ ØŸ›–DQòôÚ†¯çzιB£ýüþ—Ú¼¾¾‘?¦ë„™.ÿ[ìÝ·ÿÀo·•:’q)ó)©ogÞÊ÷¸wáyn§ÌõþãkÚ—h~Sܶ ÍGüj>Å# Å®(‚ɧx$ôˆB™ xÍ©æT3 ÕŠr¡9B+Êc¼xÏå³ÃÛ†·0o¼'Òwí§ÚRºx‡•ÅdÌáHÅB*!: ]Œ¤(¥S‚#mC¶®I²&'LËËÌ%ËtÃJ{±¬Lò²ÝEDf¶ÿÊENC*fø¡IEND®B`‚qsstv_8.2.12/qsstv/icons/colorpicker.png000664 001750 001750 00000000475 12440612574 020316 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;gAMA± üabKGDÿÿÿ ½§“ pHYs  ­#½utIMEÐ :.±»t¦ºIDATxœíÔ» Â0à?ˆÁ<•×ᘃ L6¸Aì’& ñSØ qì8]N²ü(>Ýù´ˆÀÔEB•JÜ[ás´G„~Ú„^@¥Â<Íwý»:8‡¾ªqÚU°€U4Â])¼,=ƒV$;ᄤƒfyJ÷˜$1<èU§ƒÊeZ“$BѺiĵ0µ Jï=s‘yéÕâºK¦z µð.¨ˆÐ97‚MÐó8°Ö¾¼ßø›žò}Œ¿ IEND®B`‚qsstv_8.2.12/qsstv/icons/colorselector.png000664 001750 001750 00000004065 12440612574 020660 0ustar00jomajoma000000 000000 ‰PNG  IHDR üí£sRGB®Îé pHYs  šœtIMEÛ/7€_”ÇIDATHÇ}VkŒ]UþÖ>çì½Ï9wfnçÕyØéL{K¡¼„SS-‰øC1þ11š¨Dcü勈HP#"Fc‚EJ„‚)˜‚¥ Õ”¥Óv˜™2™ûšû:Ͻüqfn§å±rœ»ïÉúÖ·¾o­»é¹½Ï–KEá}ÁY±Ñ‹5½Xíš<#‹sVZ7všv{µÑ±ÆÀ`ØÑºybv¹TXÛÏ|Á,@Bþ19øâjñ=«1”áŸ|Á<ޙ pˆóÕõ…“[¾V]s™0Ñ€è|vÓà¡Æ•‹ê£¤€ XHBôöáäÀYFF¥þs‡úšÝpӉѻB§—Ø\Ô ëö];s¾·œŸØfkëOÊ럜¥0dBLhƈç¯Y¼éÚ#²Þµ«è)aG*]¢Ðt SL Çû²§&7 ŽWcØçkì.Šëîmºó1Ã#Ä©LJ—êw¾²­²}¤åêgþÍ kÖúwÝ˲¶8zòùáòKž>¶l^þZÙ³ÓòNt&Ö gË·m»˜d°Å:òóSw¢á¼ˆSKX´ûÉx©wfæÜ'·Yœ²-Kk·œúl37Ô‹×ØE‡<–ФÊ[ņXƉ¬KØÉe;N OìÐÿùˆæ¨/b&¢ÚÜÜÈ¾ŸŸ_Ç'„%À,ؤ–žÎáàÀ#›OÃ{ºÕ>f‘YK0Ò =Ó‡3nÏÀ›¼Mœú~‡ÓbbÀÌIšú÷?hû~¤TªÔU{Ÿ¯e&/YcG¼‡Z~>Ñ5zÿàØ ™sˆ;f»rí‹¡¸³ÛÌÌe?13Åî©SÖ”¡RÝqÞY*…®*ji*¥…È~=b•ãIˆ¤²tcÓŒ=D.¼ O$œ·û¢zG ¿nYµ¯Ï#]5ÏÌa¹œ¾ð¯ — ¥ÌR†R6•º®\ &O]8V”&^½þù¸‘ ôŸ†SñÁ%PNù–÷­Ï̶R“O=4¡Ö¡R‘ÖR‘”‰Ðu·MÏÄaˆ ÖŒ©ÏÜZ·±d¡¦+¬J¢\OÊ@ o_@L« Ͼu¼¸÷¹Øó²Ú—?JeJ„Rv gçȲÎ/â´Ñ¹Ô,”ª@àN‹¸'©%™˜| >_~š$ã¿ýû~ u(e¨u T¨uñÐ:Ð:ÒúÚÊR­Ùl«M ˆ´UÚ\*@£ã”he â㘶¶$Äì±cÕw§³ž„Jµ-­z¤ÌwuŽ,cV aâ°§ T€ºS  ”ˆY¬j%ÑþŠ• •ʺµ-$e&IvÞ”²àú"Ð 4²”†‹PJ©H’eÏ ËÚ÷ècÍZ-Ì$]éø²‘VØ´yؾ¿¦Ù2ÙÀÄ´äÔ2Iì‹¥*À|`…•çοürìû‘R¡R绤T$e ÔEç-)·Žnl‹¼¼”ÅlçT Z=¢Xq+@‘­™wr$XiõÏ'þV £åJWÒE+é>ð¼êØ7ŽL’€aÃ>Ú}¤”€|ý2ѳi™Î+û×)Ío¿µÿØu³,í2Û…ð¹”]½½”¤Y§‡ÆßE³Â#• ûÄÆmg#‰‰SƒoÚ>ü°åy-Ç §å8¡ãRRFŽ®”*gÊkh»n캩ëmßzc¹\Þ·a/!’kýA¯Ý3TÏ eÅýþ±¡áBaÃæ+¤”RIé(©å(©)•”RH™HÙ”$q³ÙI¢š §R–R*%µr×”ŽwM'ìGl>s³bm»~´õs3{ž)˸úž?Û|Iyµ­W&3s…vOïø÷’%lxv oºÃˆTC·ì<Ö3F.….ýb÷õs%›Mš¦fUðEqAvúÓ'ü77²ÃýêÑ»I&âX|ëžC”3‰æÐu~ôì§jJÐÅUh0û±³çòñg‡ÇwƤ‡æ×ßP¼&¥”@3ƆK_ºy2P”¸X0Þ=/ìx£ØM`ÂGÂ0[MeîÛväñ±×Ö)Ýèüñá»-¶²Å¼r«®X¿¨\sx¾Ïxœ¸Öêºñ´{S®Üo· íÕÏ1Û6hï%µû®žx³kN01Áäý¯~¹;í`â À>ÿ_apûÕ'–µ{²jbÿKú¿YÜqUϽwÇhÉ¥Ô†1‚c%…×Ìóë+5±&À3TÕ?Ý—t¶³¯ ÓW¿aÝÜOO\¿à¸Ð€ÆQÙw´£ÏÊOí¼1v-ÕÀÊFÕ» hîš(|ãtÁ3¶!CxÿÍ®½j™ ]•§¶¾øçùM/&#óÒ…C°Ú¢áH†%Á6 :‘c•Üwß\÷ñF.°R&¬Îþ~€L9 ugïÛ;Íéä^1‡Mß4:Sm²~‹//ÅÛçhKµk µF€+½(uÿËé8TÜÅóIEND®B`‚qsstv_8.2.12/qsstv/icons/doubletone.png000664 001750 001750 00000000351 12440612574 020133 0ustar00jomajoma000000 000000 ‰PNG  IHDRðÍ­'bKGDÿÿÿ ½§“ pHYs  šœtIMEÝ !&Þ°wvIDAT8˵ÓÑ € Ыqݦ9¾j„´´%„áq@$áu<¤7v!hò‚Ö÷z8-B6ˆ…S‰l]@qérþéç.gÞbùŒÛåÐT]$ çÔRâ6,—ÃjwöoXn5‹XA¬¢så°žÚ­ +EÁNQD0„€IEND®B`‚qsstv_8.2.12/qsstv/icons/edit.png000664 001750 001750 00000002341 12440612574 016721 0ustar00jomajoma000000 000000 ‰PNG  IHDRþ¾ KbKGDÿÿÿ ½§“ pHYs  šœtIMEÝ hÇ ïnIDATHǵ”[l“eÇß×ÓÚ­t]»­ÛÊ6º+tƒ1YòMb‰˜xkðÆ`Ô;¯L$xab†.A§Qnt`8óasë¶²#£¥]Ù¡íׯ}½ —m%>WïûþŸ÷—ÿ÷=ÏûHBþÐþS ß/DZ% £F†és1šN*«ª¥V£Lôdö“A3g{Va˧¥ÑOjv ùÑ8ýñiQ]»IZîúú¤p­_ÛíÎýw®‰äÔ ˜â8üÆÀ$^mcHmãƒC­dt_ZÅû{Ïž{€’ŒáÏÊ:×tí`gx©TJx<©ÿÖ%¡Œ_F¨qí§±wýöؽ9›}”ç›úè¹ã¤ª<”ù¡ÌŽE2{IAww·8¸ïc¶·´²±¹9t~‘Ò#Èq€¸«€ù˜ŽálÊK¦1…(Œ[0¤uhmU¸_xâØëõJ€øêà„ Á;Œ«þS¢빯ìZôßMÆ$£ëÏó½õÇÊÎÓ2éa¿ g*¹¸x^¯W ƒâ›O“T±——¡Îç-[Ô{Ù!ޏ~AѨœ(»È‹c›p.×kV—âó¹¸ük6ÇË”ZÑ’\üZ  ³šÅœ6@q,ŒË€ïÞé£ÀQ‚£*L×±^š}Û¨®Ð£, ß5¶qaOeÖò_…àÄ(W 6ÔQQ«£«ógüÃ:ô‹ Æ° Y5<9µÈY–¥æ¨YõôbÔ7¿‚­r’ §/kÚÀ:-)䤑ÂÞ—S:S5'Iè"ô̲۷VZÒ±Æd£Ô¦§neW¯]#Ï,ˆçÜçúÙ+Œ>´º˜9¥GBFôsùL=œ£¸º~ùY‘m/E÷Sn×aÐIôNL±¥Õ˾±išâ,5Ï<Çl´9ýøê˜Ú¦°o«oÁ¬üÂÿû]‘Ÿ5‹N+S·ó],úÏVd™QipÕðƒ.ŽÁœµzÑU׉”#XÒÍdlgåšE5Ôéab?’ž™ nÇÛìÝw„ùÙY¼•¶†FÐ* ïµ·c-X‰Í½ɰ‚þ‘(¥ž­ÔÔ¸¥%ÁÊL€?]Èo 0Œ ‘%6UÙ˜‘—ŒÓÑÑÅ^DnU3±œ ¶lk“–jE`jd€­ 5aÏî6 lÛÇ •Ø\adWµ‘±¡^Ž?Ž"ô ŒràÀ±ì %’!pØs¹yú£EIJ2E<‘$:§À(¡)>û¼¡Á>´Í’GBðí‘C"=À‘oÆj1¡(*ÃcáLÒì|‚PdÏæfLf Þ6ŸtóÖmñáþýdg›(vºXa±óÎ[¯/ôu-(‰8·ÏŸa<ª „@IçdÀ¶r7ÏøêñÔ­Ë\¬«õHyyV‰Î(*J.vü_£³³S=ú%f‹§“"‡ƒ½o¾!=5x``@„B!N:…F£Á”“‹Û½Ϛʧÿ]üú@È ]¾IEND®B`‚qsstv_8.2.12/qsstv/icons/eraser.png000664 001750 001750 00000002312 12440612574 017253 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;sBIT|dˆtEXtSoftwarewww.inkscape.org›î<\IDAT8µ”[lUÆ¿sæÌÌ^fÝíôB—íUjƒQBE5\#Åš(©¶EéS­â˜Æð¤ÑhP#Ì&BˆüyéÒÕ„iÁ&Îù¢ Ùº*mYç¡Ã7Û[ŒË?Û¹!ëyÂ=½ÿ*ØöÔ×ÃÇiú¥Vn\iáÉÖ“|䨱ŸßZ{2?MqÏï'š1!„<áKÍþ¢rsóºâòG=cz2ÜÔ!Y: èˆÝÖ­³}—B­¾ýþTÏιþ¯`BˆüþÚ•¿QñÚ§OºR7§cpDb#jÆ`LÅ¡˜qFç»{¢Mã×í›ÙÈréS=Þ¯Ê_m¨(/}<ÛÑŠŽãÆù~<2é‡èÑ0<‡:ƒÃC(F´g«¼ÞëÃËLqÚVÜ&„ÈmY³³xÓæ/7®*r‰ƒ§1}ül}°+š O¹ ç׆€tËfxŸ]}‘w].²+i§l¾K§Ó™v¨¦æðK/nzEîïˆÈvYÉé šaÄ Œ‰€0 d{€¨ EÏøY$Eç¹çˆ šE©Iç\–•••444\~sûö²¨nÈŠ7µ¥ôÿtÁÊn£°@áKx] @4ä4—o­¼ÊFzÓ1н€P§‚E(555?”——W(Š"ýÕÕ…x<J)!€e𿹯åj}€“€C\óò¤]»Î4åÃ`0Š8šç }vQ[ÇÒÓÓ}ÙYYÅ„  s»Ã1 ž’À7½^Ø_´.ìênÍIõ¬þ§ Áß— ˜sz-wI¬Ãíù®-´ch2<‰!¶þ~fqÞåt: c6AæÀ°, G®w«¾©Ì—Æ1Õ†ž|¡¶iVûÞ/ûŒqÎu¦ëº%ÛlT’$ ŸŒÇb¡œœœIQ’ò!àœCdl,01á6bZ†t{Ôâ³.½™‰@Ž#°ïÌ­wÛ§ÛÌð;ƒ%“IS–$A¶Ù`w8`†:11¡.ÉÌWUÕ 1 fQJÁˆ†Ž'8‘—¤Æ÷ì0Î9O̶Ì4MÑ´äRŸÏ®¦¤ C’ehšæSeÔ4Œl&ŠL&¸uEPõ³iÞ©ßûï6u ¶Íw9_@pÏž=Ûš››¯êÉdÒíñ@d ’(BK”$ˆ³kœj;£Õ)îú£oCS‡¿‰sºÀlÝÉUoUUUõ–ââ·+,\êv»‰ªª#rGýþäѺºö#GŽìííí½`Aà?º+—˵b÷îÝ¿ÕÕÕ…ÀX}}ýTuuõAËÈ‹ŽÙûä® µ¤¤¤bÿþýëׯ/:wºÅÖ‚±ygy‚P$Š‹†¦­—Ŷ-ŠÅcã?‘NNÌþqcd©˜ðo~(7ýHmpÖ  èMè?Ñußá3z4Þ†÷‰ˆ¸ŽmئQX®•¦Ë3·Çk¹»SÀ<0Ì ­f§¶°o Ð=@·¿4]@èl® °ì;gɯwÕÏmk×[‚¾°î‹7{æøÓÝõç_ÿeþçñ¢AaÃT—_IEND®B`‚qsstv_8.2.12/qsstv/icons/filenew.png000664 001750 001750 00000001471 12440612574 017430 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ79ùHwÆIDAT8˵“[Ha†ŸæŸu77-×ÒÜŠˆXŸíx&\)Hl½E°û=âãüehJ *5Áë«íéPÒÛô³·ýîü9άj“éÏu¼´dÚP'…ÇËÈŒŒ’ê  {½¨T†çJíZ[yc—êײºÆdöRBúÛ3&‡ù1z 4%4"Þ³Äß~V%+Tí¢7Oç'¾ÆfRfØÓ[hñ…u[¸ñ¢^¸Åè¥3¹¬4€.%K–ùœžl»Â¸%ßå\ÞSèK‘+x¦òý•äg‹ÿ¤ÿžEó{ÿüþS!=p~/IEND®B`‚qsstv_8.2.12/qsstv/icons/fileopen.png000664 001750 001750 00000002514 12440612574 017577 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;gAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÞIDATxÚbüÿÿ?-@1ÒÊ`€b$UCyãI…þÏgec2øüù·âä.ëØÔI¨¢édAç„‹ï¯ßúòÿÎýoÿ³J¯Ç¥ €@A Ã@më)ƒªæSç÷xñÿë×ÿÿ_½úýÿýû¿ÿ§Ï»õ?9÷P6sˆQ>ñúÿ1†ÿ~ýe`øýçï? k¶?ýð}‹¾`Cç™zW'y~^V†?þ3üþýLsp03Ô´üðñÓOÅ¥³Q‚ €mËîýï¯Wöh0ˆþù›áéï ßbr‘e01”ûÅÀð÷/Â`¯î>þÂÐ<éÒ†ÝW .9<€ @,è©âPó³SOxÿü`¨ËÓgàâ†=ÿýûÏ £&À`k(ðïßÛ…{/1À  –¿ÿxôáéÙ >. rœx#òý—? 7¼d:èn†[ïÞ÷3è4‡)P €X]óéÅ'+SI‚†~øúÁ»öƒ‹ƒ’,Ø,u …Ï_ÿýþÃðabï^€º¡IZŒ¡jÞsÓ ÿþý÷ ÿ€é–á0lÿ@Ù[O¼cñ”g``8øl0;ÃÅóyï½ó hÔ€B Šõ{^3(¨Š2èI³0Šp1|Ê}ÿ ß~ügøöûà éj ?YYN݃ÊÈÄÀðöáw†WÇüeø÷Eñ @¡¼çð+†[KtÞ¾úÍÀ/ÌÂð‡áõg†7@üð9×÷@öO ºé݇¿ o^ÿdøöö Ãó«¯><ûúáãcÞ¿ê LÿËŸ?C÷ŸúÎ`«ËÇÀ ô«+Ãù[ŸDåøn=a`¸ôî‹×^¿ùËðò ˆþÃðíÃw†ï¾ |Ïðè+†o ¯Xþ²ðÃ-·ÄòšÜž|Çd-ÄŒ†—@W½bâc¸qè³ÿÌà`¥á¿þ1üòãç? k¿1üþLÜÜÜ@³€€˜ù—Ãÿ³@æÓ?`„|úÊÀpùÚ†p`²a`xÄÀ dx÷ùÃÇ/@Ã~ ø h·¿^¼øÆð—…‰ƒ5¹0ÿágøË°Ä pªØsü3ƒ?Ë/ <@ÏHƒƒ˜*ø$Y>¾ûÅð‡…‘Aèß¾ß?xÅ1( 03üûù“áß·Ÿ €Ùôû7`ð¼ý'üðñïW ðÇÈ2’‚€ˆ?1"uÑEübH@ A‚!sB2úddɾw»3»ÓÝUÕÕ3;ÇÉk;vK­ªî½ýôÛÕ O[«6É?þúQ]OT3³zBÓvĤdËÌê)fÅ,£j¨n¢qçŸ9ó£ÅwÍbõñÏ7>_Ôẞ¼ôʵKPqíê>Ÿ~ñ Ë&pá¹]>ûäýÇÒ}ãÞºýÁ·_ýðáá””. Õ°‰›¿rùÂyêzòÄm/šÜó»#è&‘a{UÕ ï_Üãå¯ð•ËO1–Ë)É8w*,Ѝ1©z·ßx•«Ï_dÿÒ³u/,›–å¢Á,?,œÄÍ”bœ4ï½õ:¥Jùq;äýxÍŒ““–£Çt!bfÛˆ{+º˜øí;¨eÌ2–}Ƚ¯ˆœ1bH4Ë–õ:p|Ò£<ŠXUBJÊr_R–ÿ˜”…¶]ºHJBJŠˆc$ç-Â:Xáîœß=‡ejרŠã“’™–ÌÎlÊd÷³IÅl:á(RröG;ÏÌxçÍ×pwBBH¤¤¨Ú`—õ-6ö/¿þ‰yH÷À,B"AÕ¶Ÿ] ‰ ¢Û­HI͘wïþËýû ª6\a®°Žö˜õâ;;5) IÒvaÈL•ª*ìíÕˆ€*Ôu¡®a:-˜ÁdRP-TUˆÝ·yœ”Õº#›±ZE‹n¤ê O!¡Ù¬¬íÄ1$Öë@qGÕpÏäüp7룻BýB²8ÄD ¼`f”â¸÷½Ïó0îcΛ¼ "¨(î[ˆÃ:²^´äl¬VËñäO«àì!ªæñŸuÛº5¾­Žç‹ë÷þ~pSâö_‡ä\F✠¥øÿæN¿¹îÎé‚âÎužÚöàÿßyK¼IEND®B`‚qsstv_8.2.12/qsstv/icons/frect.png000664 001750 001750 00000000612 12440612574 017076 0ustar00jomajoma000000 000000 ‰PNG  IHDRÚ}\ˆbKGDùC»?IDATxÚµ•1NÃPDßl¢ ‚6gà"œ„‚#@‹è‰–+p‘Ô”–"²D‘’Ø4û‰±ÿwbbV²ü·™ù3^ÏÂ?—çX¿MUÍ^42kG‚ (°Ê€ÑéÙùbH[¦Owà˜gÀàöê‚|Vtši’!’¼2ó3\Þ<L€ø ¶Ï ¦Ï/ql™ù£Ú¹Ý{ï@a›¼^ƒ«ö»—«ñÚ÷o*Û8fÁ™?ñ¾¡à‡©“ ëÆ©¾F Nk€í¬ ŠZ8)ß㶤­i(H´'&vû´¢N‚¾S´ ßÄôRóó/V¥ ŒÞ³Ê« Á—…ˆ½¾2ï>eˆëÏŽ pìÕ~”¾U:ø«‡Ý›<3#g;îƒ%0q]_8ãÎ*,œ&˜úUb…_ßÒÒ92»“{IEND®B`‚qsstv_8.2.12/qsstv/icons/gradient.png000664 001750 001750 00000001423 12440612574 017571 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l; pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF‰IDATxÚbüÿÿ?-@11Ð ŒÁ8ëËb Ãðçÿâß ¿#è_@±ß¿0Mù 7¶Zò?'$@Œ° `œùùÿi^†÷?Þ~c`xó A¿ù dg`xÄ~`šûù'Íý~c Ãÿ¥!Œ 1€‚»ä*FÈF0‚F(ŸMà±ô a+@± {Çdéc¨×Aèß¿AûõÂF`¹_(r„0(x?ì/ 3 3ff`b&&ͤ˜3¾™Aj™ØÀÅÅÅLL¬`Í`…`Ìå# ‰c$- #3üû  $ÿjäÚ q)Ø d(#̵ —32b1˜öH ¶4()ÅÀÊ Æì¬ì l¬l lœ œl ì@Èfa.n ½¸j1†„Õ`PPTDU@8 ¨´<„JB¨ï¨ÇšA»ÁÌplXÐÀÀàt@5Ø*Àô6@X³4 3 ÑY—… «8@!LøùY,Ì$ÌÆt1#(U£ïß?¸8@!\üû'$­cTƒô€ÓRª T3CÒ0 3+ñ]ÌK‚H. $ƒ@3+ÐÅËö,cÐSÖgà|M^Û9¸@Éë'ÃFö Ü@š‹a ’Á„”A~@r0E\›w žÓ˜!¹ † l‹  @(.ç8xöe† 1‘‘‘p¸ ÕF„’¥ù#W20üýƒ°„ÿÃèÿÃ@¨ø„‹ˆ‘Vu@ѬÎ0˜bµRø-ñIEND®B`‚qsstv_8.2.12/qsstv/icons/image.png000664 001750 001750 00000002164 12440612574 017061 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l; pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFêIDATxÚbüÿÿ?ÃŒ3þ3Pddd0 Œcí—ÁðëÃן Ÿ¾10üBaF†-g¿0Ü{ùá÷Ÿ ?ÿeøTô Hÿø bÿcøñÂ~ÿõƒƒ¾(C ïf°yx·aM{ÿ“*(yh Ð¯eÙaØ-ž7\ØëhI=“1kˆ‡.ŽÁ§+›:,6‘êvZq¶_ÿn°™*ЕÀù÷Ÿ…$ÀF nzì ÿ|@úPÑ ¥ÿÿýª²øä2ðñp0Ì› 1 €à3C ƒ˜Š ˜™ŠØÁ ˜‘dÿ£Ñ@pƒA¶^ºt‰áéÓ§ ::: òòò`1øû÷/ÃãÇ~þü v!C̹äú¿ \Ü< **ªpƒnð£G^¿~Íðãdž‡‚  2äû÷ï ,,, <<ÿd0áý‡ð ÜàOŸ>½  A4ÈpAAA U~øÀðáÓ°ë@Éd9(laÅÅ0 '  N:Åðh˜²²2XTÄAéþÆpu 9dÜ`xp€‚äz âƒ"òýû÷`0>(ˆ@©‹_8 €àóññ Œ†E(,ˆ`b ƒA‘,w1 ÎÌÌÔ‰Ü`’ ó .€-åJ$Cí€Ì« >@1QRS€ Fv)y&@,” JfË–-ªä^G– Š ^·nÈPyPáˆ.@,Øb”X4TH=Ã&`}g-åÚûF‹IEND®B`‚qsstv_8.2.12/qsstv/icons/line.png000664 001750 001750 00000001160 12440612574 016721 0ustar00jomajoma000000 000000 ‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ­#½utIMEÔ%®È(‰ýIDATxœm“½oAÅ3·¶ÇF PDƒpJAEIEAø(ø  %…‘è( £M•ІH|†Ï„âœÏÈvng(îœ8OZíjµïíÛ™·"­GhH¨4ë4Uê5EB‚†„ÞCä[¢ ‰–³ š8ª€öó«LW¡Àp¸voÌp@Šmu'"Pôr¸| ýœ x´1r¡/(RQ 3µ„­mèdðy0IÞãÀÇœˆõ‡„à‘A«ýo/Ä òÈ‘æI…×Ûld°Ñƒ_¬ua½;îÀÝc3îß½ ˜áf Å ÆÍ+m–À»?ð»kiÁ|Yw7snܾ(ßÓ¢&#‘$Ÿ:O¥X™]`e>t òÇ—ËŽ¶o]’téNŸmñöÕ{D ©Ï.2:”¼yMvjÍ>ü|òÔ)ߌ ùyÒ;CçZlZ%¸íj4_´ÝU`jî¸4Ïœã[ú¿$*x ÄÝ!i<{쮊 LÏŸ€¯›  h© nÁ-î’¢U£§´ÜóâÕÔ"sÊXNôy„£3“ÙtÝ–ýEõl‡d„Ã{´Yß臩U½ÈºâDÙUÐÇŽ” ‡|‰CÇx·Gû(Rа×ÁÒ‡“o(ñUø ¥ƒ°NIEND®B`‚qsstv_8.2.12/qsstv/icons/mgc.raw000664 001750 001750 00000000250 12440612574 016544 0ustar00jomajoma000000 000000 "`×ÿz±òÿWˆãÿ×òÿÿÿÿÿ]Öÿ:wßÿ°ÈöÿÿÿÿÿÿÿÿSÒÿXÒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ9Çÿj“æÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;Èÿ'`Ôÿ7k×ÿ6iÖÿ4gÖÿ4eÕÿ2cÓÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿqsstv_8.2.12/qsstv/icons/mgc2.raw000664 001750 001750 00000000202 12440612574 016623 0ustar00jomajoma000000 000000 s`dF512[8#0:E/?”r/#0bAFKC/?83†pVI&,/M6‹_/?4‹_12*1‹_T7[8#0–e qsstv_8.2.12/qsstv/icons/qsstv.png000664 001750 001750 00000002103 12440612574 017150 0ustar00jomajoma000000 000000 ‰PNG  IHDR,+j¹bKGDÿÿÿ ½§“ pHYs  šœtIMEÝ 3u™S.ÐIDATXÃÕÙOHÛP𯵂lj3QTæÆ˜Ãn½+cxɱ·$ÂŽ‚ ‚‡"2d2ð ÃÁ@C·ÓMn=ö°"£»9èmÄýqBÇÃ(´;´/}/y/y±­Þ¥&íï½¼6±b±XÅ …B ¾öØr¹ 50Œ~õtV=®¿îRïíxÎÝ"õW…}æÁ àè°c€½uŽã@UUŒe²ØgÊO÷8Á;áŒ:Âny/ðÖÔèMÖZ—ìêF2"Ö;aP), UX,’Ñ –ŸIB£bï ÞnÖ—p¤T¯+ìðnHªñŽsTú:¹ØJìÞºY;X]õƒ›Á*Àä)08\Ã’IÖ¬gÄ£$ @ K&Y³XÛ¶aÛ6„wœ×úêí¬¤íIÖ¶m躎»qÂ",jüϹ;Á&O[=,6ÙÕÝ2,ïZfÒ=­£ƒ°•‡ÌäjG DX¼’, ¢°ØÞdÊÇ×p˜ÛÆÑæt[±¾Jð°Þ ÐØ£Íi€ªª—‚eÀ¢dIx+ÁÐÜv-]àR°¾„y5 X^_IÂN§¡ªªpýa-Ë Ä~€ƒj4ÒõN.˲à8Ž›´ šNÖ0 !vïGH¼ÐXr»¥W‚•/U÷ eвÉ@|<¬Éò°ô—É e“åU öN0Y¬ :Êa°h5ņ¡Ißð¾ÞÞý+N¸U›/ZÓ4¨ªZƒ½uÈ™B,-]Íl¼É ²¿¿MÓBWfgÆÁ2àžnñÒu‘‚eY0 ÃMš y«¯g…X<4ri‚ÉbézðÐ4ÖüUa°_SO‚wkíÂŽe²îg’Nç©õ€{ UU@ Àˆ?áV×À{-/i2 Ã`ª@°ñìLpÂÍ`ÉÍ€‡¥ÑÞ¤½½õb×°‚3¼÷'Ül²º®béaÛ6“t%c†&ËM¸Õ5ORýï^BÓ4¼ñ`?¯]ÔßÉG]cekÀÃN6~¬:Žƒ\.‡……äóy¶—hg xØJ¦QC·æ[ù |;j@ï¼XÛ¶ÝÐ^›¿ßpÔ0aq’ÕuÝíìÒÆ:¥d«HoÄéx'˜ :Ñ.¬oO[_gi,or-m`mî:½hæéÿåÀ4é l¼©ýÁãÒ§úíèëçÿú*[Æ¢Ù@///cvv+‹Õ›òPÆ}ŠDžÐ\嘟p‹Ÿ‹â;]¡P¸R3È«VËM*•ºvK¥R¬é;ÝUŽÿ³ÝtwÐIEND®B`‚qsstv_8.2.12/qsstv/icons/qsstvsplash.png000664 001750 001750 00000312773 12440612574 020404 0ustar00jomajoma000000 000000 ‰PNG  IHDRàJ\±êbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ #þåtEXtCommentCreated with GIMPW IDATxÚì½y°eÉY'öË<Ë]ßRïÕÒµõ¦­Õ¨[X$ŒÄ¢ˆalö‚ñ1áqØ0fˆÀŽÀžab&ÇØá™°Á`BÒ€BF¢…¢[Kï]ÝÕ]ÕÕ¯êÕÛï»ËY2ýGæ9w©s2¿<÷¾Z¤“UuÏ–ç;¹ü¾_~ùûØ›ž“’1@J€1Ô¥.u©K]êR—ºÔ¥.uY`‘R‚1Æ€¯JâØ Çþi»/³œc»3Œ&ÛºØÝÕ^’8¦QÿMunæ])—%€Äûš0ˆëµ®udr„Ú†m6»%|ž–9˜¼GF˜ÈÊœ›çM|ÊœÛàãXlàZZ¼:Fäœ@W–x‹6ïŸD¥Å#5ur›ãeª¼—íÛ2ÀñÚªßYlO­ˆ/º½So×kLïhêT OÄ Ž?¼h¶Ó@Û] ¬ÁømÌÕ¡Œ¥°ŒÁ™ D©Ùæ<Ølãr¼ìÝLu”¨ H§ZvO¦g„I„ °]ÇNÛäÐâÅ]ô¢´É¿ÞÁ¸$‚9Êwp™Ë«q—ç¸(¨ØÔQfíÁÇMu`„c®*).à}Q²éÒ¦?N¹¯­­µÎ¸Í9¹ãð£`)³+§L¶ þyY³EÊ®ÍÐ]¿‹t$ˆn %‹HxC8lŽå‹~/A“Ë4•IpÙ YE‚Ð59Õ"4È]@ºËJ*ì¹ \¶+Hvy7j[´9¦5_ì_SÜu ¶‘E,¯RîQdÙ¤è¬.:˦+`qaAçÉG bçIxCm.LIUOyÆ¢®×¦pl“‹Öpü]®.Au–ç])+;NÙ^ˆ›lã €^D’ ˆ/ˆSÀã"³lRÈ;Jöb”¼ûQfÙtâ‹È²yÔJ8TITåzJF囨~gp˜)ë`ŒàõÚ[XwšLsx·*u+š,øïÏæ¼s~7Êõ¦ºVi§”ö^vÿI?[(—ç3“†:¢Âqª”¡MO|lStÇ)ehßAp&í^3ãô¹V—}$”ûÝKæ[Û3ŠÚÞl~[ÈFø§–㢤Ëì1^Ò%Ñþ¦ßËÞ­Ìv¦û‘¦{3¸éšK˜¥M+eû±`À{_wÜæi3V„Ž_69¸Äc2‹njØŒÀº•1`œà4P7½Ùtg5Ôm,,”®§j—ƒ¸Lug%`0ë‡3 ˆ·yõŒø^ 4 n›¶ù<¶ÃœßÍ4Á0‚ãkú.¶ÉÕµ½Ãâ03â³mÇ!eh“¤0ãÔP7V%œpÞñ½l¬wµ{]h,²kܾË}la¦gPØw›Sf{vU©ÂÙk¥…Y/:&Xî"[Úll{7a`åm6bû—…—ÕCœ{“c"ˆ û×U xÕbR†®±Ç²¤aÛêSuÂ¥N¦®*)€ÛÒ­ëæ*WyCÊNlŠ”ß<:ã®ê)”gP€òQË'µíæýnT¥— Ã&f‹ ÁÔ)ñÖ”\6©B›Ô!ˆÃ°m6³”Ä+UÇw[Û¢²¹u9º´÷”oíªgïªÒB ?1=ÛUPÁv¼jÚû*Ǩ!*”ð Emòªé„Ï{=%ÇD À ¬ø"TLƒµKlºí<Û„xTÉAªHR³—Rœ›\ÛQ^ïzí"@léÅy®­’ȇ9¼×¼Ê"¾;¥ßº´Óª½*@¤:Ë”~oK×m“Ô¢n<7õƒ£]ÔøN%Q@¸O Ä£žRŹs}>%Vš ðM Ò´J¢c0¯”!å˜-#p‘m(‡&gÇÒãªnª`Ûò»PÇö€Š¥¾ÙY6m“ˆS%ËŽ:ËfY˜‡Q¬¢.á2pî*6€ÂÞšŒ¢ ßVæXWyïДa\å «ê„Û€¸«Öx‡t*)‹Î² Âñ*Y6)c‚ äÏËl×Y6oÂËE ÜæØS“Ý Y6M –êüUɤiÃ. Ýå÷EtÓdë«G•ÈÇÒk¾Àö¨—WmY6ÜR\Áö­È² »e 7#³ãU’øTÕ܇eR¦q è]ÄJšm¢†q¸HRý"ú¶ë×G£)nrºPÂ.—A0Œ³6MnfqXmÏvQ8²… Q5Åm× Ãx@‘R¦ž_åwWpÆ4—ëo NÑä¼S W­Ø2-l »c‹QrM-íÂbÏ£Î`K¦`Z)01\€Y÷—ƒÿ]TN`jËZŠV6U`Td7ƒmcÎMN'´—¢÷—ŽïUô‹¾¥‹Î8U¿º¨íqb_’ lï6–Û– „Âpϳa{ö™óä2°Ù®Œ‘„eõÄÉ¿ <3Çñ†öPf÷ºØíEiŠƒxŸ20K á²eќ甑€®qÛ& ò2­sÊ&ϲUQâ@—ÙÍvýmÀW•ëºÝ‹iéÓeã!`¿¤hÓò à÷i›|¡’BÙ„Q5†°KÚÁÒi¨!:‹ÔÊ69U$]Ï»4Ð1GýÊêLÙ çNE}÷EµwÛØT ª+.‹!\I‚*{m@ÔUÇwTtêBëó¶¾[ˆÏûüª±â°Ì‹’2´%dsIÒC=FUC1)Tpª|¡É¶Uä Mu¸-ø";ÒíʈW`«l<¢N¾pï"¿è’êg=.`€.K€¤ À?JqÛ | ÞU܆nV"›Óiùnl° ïêSð®?ÞÛÛß?؆û@:‹G@<€ €×„lt »§ º§ º'!Ö_‹ôä!—NÝhoÒÁ5¾»J_£€ÎÙc"…·ó<øõgàí¿¾w l°>Ø¢ ‰´|Ào@zMÀoBú Èp²s¢sdç$DûDçÄê=€ß¤ýå2\ˆOþ;Máí=¾ó,¼½‹àûÊl°÷ÉHÙÀk@úMÕVüD°tNBtî‚hTvèܱ¤màʬ׌xu S5IPÕ,›Ô9R†6ÇØ¶‰’K^5¹Õ© ’6€8¶ÝÛ¦õmÛó³€0vò¯ä\·¹¶“ŒÑ¯5VÜ–ò”z=5Ë&…©¥ÜÓÆŒ™€í˜´€¨²JÉÂ'-÷¡v¨y;dÑo’]Ÿ]õÒÂbãÏ«ò›th/¶û%C—¿ˆðâgá¿ò¼Þµü$)Ô¢ ¤€H!¥f†@Æy~.H™*œÚZGzö›ÜÿHîy;ÐX¡õj{Ÿ·O9ô_6ÜGpé3_~ÞÆ—À’þLý$À8dCŠtfÖ`ú/p ì†9@J@,Eºz?Ä±× ]} Òµ×CtOÓœYq†þÿT&ÛÓÌÿãƒëèÿìÓ…UZþ³ïÕf'îÅ›±Á¤]ÔóE…擌ÆKŸK£ü&‚1È4É÷ìdVÔp¤æŒ1 ÀâƒmxAxáSŒ#9ÿ-ˆþ$w¿]p„c›š7ËfIÿõv/¢ùÔG^ü˜P RŠBŠüß³öÉ@èw²lݾ3p.á\†×{¸ü™¼ikÉÉ· =ùf$'Þ ±rïøz×,›&Vʼý‹h>÷4.? ¤#ýÍc5 ŠbÊ1“%vÈA÷Ÿü ŒÞÁ%x½ËÀ•Ïä•­HŽ?Œäø›‘œ|3Äò½Å$V•"Dpóï–; 9Еrìh2¨6.%$+éTK)ntBSí`Ê9Ëœ6ë¯è¿Ç}m t ¡>y#P‡ªçhÿZi;žûN´·žÒßeÚ ·³iD9ãB_ýàm?·ø,›”9F—ðåOqoj¼’ÚQ‚ú›1u\NØ@Ô»Žøál޳ñÝæ9æše“Ê¢Ûæw.šG¼ì¾s–Åpê2>\Ý©Œ8%Ëf™ÍŽby•²CÚE;¸ìÚExWo¹€{€o¦Î¸k"T|†í:Êy·H?=|éóh?þ{¶_Ô!…È&V=)1³¦b³…ÈAÈäy“à‚9pÏãAþo)R/áå¿X:á[ñþ—°«ª)@÷bÃ=t¾òÛh^| bÂ1Q€ à~8]ÝYö;g|Kf?)ÆÎÈ Ã)Á^EØÛ.~R†8Áàg>WÍÉì!i“áHÑ:Oý6š/+H‘ª:êoϸÆù {œ– êÜÙæÜF˜Ÿ´Aï ‚Ã „/ÿ`ÅüÔç3q&n@»cà)eþ­¥HÇÀ\ HH0=Iä€1ͨó|%èà=ôù ‰qïFà.'ŽeN€$çê[Hh¶Ü Œ/À¸T ON°–™3ÇT»Rm2”ñÖó ۰ɹÉTCö[+`Œ!wf)sç@J&娛hïža› 7É@9ã%+³mzúùÈBļt¢J$ƒ}ˆ$‚×hO÷ÂyL6×Üõ6ŸWÎãðÂ6¸"‡i<á+ ˆxÀýŒûðšK`O~h ÀMãV™öY6›—ÿBµ7„‹x0áØ)r j€I‰4êCÜý@ûÄx<39“ÇMª&6éA8£Ìƒezòw rÆÔ²{»€ö[Æ€»jz–I¾Ø49ï n™ ­;»¦1P¬ólŠ¡¦Ö‰¸|qKç-§h›ÛÞò{UpS8 , ºdé¢Q^ÖoÊRÛêgz7»Õƒò^Tq!ÐùòFç˃"V“*÷Bð ‘3EŠ=’`’MÄIê óÈ1Ê™¼r9gƒ´ ½|ïÚûDox/†ßñ @бëÖÏÓÞ‹l;Ó×:Ï}Ý'?&Ò4† ¸€ñVÎ~O1¡c8 9+z%ÀCÖÀ9óÆÌgs àÚùÉÁ•D ÓDŸ‡€–Ë L´h™–ì\ü8–žý@¤I¤ØQ/ÏÀŒnŒs@fÌ®9“6ÈXÜ \fÀœ1® ë<Î30s<¤Dg6ðÀ ~‘óñ Æ›Ñ=ïAxõoÇíRïUð‚ÒÉð& Gêþ@®í@÷¹?ÂòÓCšŒÀ¸/l)ëhV±mj³¥ˆGjÓe ½“Åù*Û±|EAN„!dL0÷‚„1È\¥ÃMˆ4BÐYdÆ4ÆyI+fìÚ}ñ°ü†¦‘b^Sƒ<‘&j„1È4V,i•Ú`’U1º*hƒe퉱|ïS6Èl—ô ’‚î¢KŸ¥ IDAT:Th‡ ¯‚Zñ·—_”F}ÕO2¦töÖS¡5ýB ûó¦öLÇ}O9u¥¦+KÅul½ HÆê½º"cc|úía¾ˆÀ¸!¢rÊ'pñQo ”h„-†’"}ñÈ×~¯»¦¸M]Ê€•ÂëÃ#¤:|†yAÞÆ²±P«7‡ÏBÄ4VNÃktŽúHxxÝ÷»IÚ°%)á¢d)I½ªj„Sbõ©:á·U Ű ¾ˆëï Ç¶Š”¡-Éͼr‡rŽÈ´„\U⚆Ú¤M‰WÊìm“É£|SVDL Ôg,J¢–|‘ò‰3çú»¯àØŸýkøÃ=H) ’Üo¨eZÍ IH0ÏW˳Q") ŒzHG‡j2N¢™Í†úÁšÁ˘t/lÃktËËùð˜çƒ{Þ˜ÝBÅ™ Æ[häg1xï¿Ez÷·š¿‹­]»¶w­W>•ç> ÉD+[ù¡–B(¦W ¤Ñ¡jzY;æËò"Ç*(™c2'¯™Op®læê9a~s ÌfÀš‡ÑÞ«*~¾»®ÚdL®´, ;ñÖµÏcåâG!¥œ²Aò$WK÷£ÒQ?gº• ôŸÌ‚Ò)p_9ƒ“6Ða>ãÕŽÑîH‘"ìW›3¦Ùeƒ¾€+ÇʃîM­ðŒ™|6­@"¥fË%Q e’õžŒ‰gS yæ¼95LÒë`fÔ'WÜBÄç¾ÞKÿØDƒD*§ãùýÖ xÐT!úû5DO}xÍ÷š¥MÓ۴Ѻ =·®üµ{‚ͼ݈¨?õîIÔ×!d¡rdÁôw~ðöÕò2 . ÇAXy¯"e8ïæL—Ôò®÷?¢øïÅp×ÌQT _5KÖíÄaaù]€85Ë&, èvɲiƒ.ÉK¨1ä¶Îé’ˆ‡~³yªVxQlš)lË6Q˜V¤å}çÑ7ô‰kƒëÏcýÏÿXt˜ƒg/lëp“ñd/£’áAÎr¥£>âÃmÄýÅjÚ=©@¢#H¡@<ìƒMíð 50²ûq?„‰Šó帀5ºÀè­?úy ¿çW¼áûÜtëçhïÞ`Çžü€Ú˜•Dð‚&xÐP#M ™D:<Ì™Q)’Á’Á¾ã@³7È1¤i Ï„íp/hÁo-#è šˆû»*dÙäMN|É9ÞpÇžýçH£^Ø÷È6IJ‘"LØ %Û`ŠerÚÉhº!OÙ` ¾’Z[_Ê /l©0%!I¢±S ìRÕ›Mˆd„d¸¼ùýöq£l¯…‰q=îÄ)ž¢Qî®ÏЉŽðÍàÔå–*@úkˆÛ:¤‹MnE–M€¦°r3²lR:PU€îÂVÎÃBÛ®wuŠbÝ%è [Ù€MÉàVE¢Ñ–û{W°þéÿ\3×*Œ¢="’ÉPmÔÊt†£ƒkˆö7‘F‡$7à7:ð‚–b—<Z>m g©Ms")=õ¶´Wá5:9ðÏÙ?)U¼©ï©PŽ4÷Cø­%°‘ù‰ÿ²±‚ô¾·»·½ í}õ©ßƒ'S¤Iî‡cÇA¤Ñ@9$"8‡ˆ†ˆ®!ìë ß÷•¸NlÔ3ªE’{Ð,³HFñi4€ˆ‡H†ûH{l½¬Øç LÍHÔY‰G’`õ¹ßƒ‡©Þ`ç5:9ˆN£ć;:ÜG:ê;Ù`*Üf¶Ý$qÞn&m÷w1ܾ¤Î 0é@؈Æ=È4 J â¡þ>ê< &$Wª ZZñ†¶Èrð Æ!“Âð’I¦›yˆ·‘ôw5KhGFNƒï2à…¤d¶•vÆ6cÜJB&koDÚ9 6¸ªÂÓ$×þ IÉV´c»Ç•ã5:Ì7lúžñìG!ßôÕ E‡ýæµ/Âãi¬lÆ<_íYÀXIF&‘r™rŠ2@.WîÎË|l1foÀì¢ä )x¢ÖBeÑo@¿é ¸­ÒÔÔ¬T)ïUFD`Byï£È²ic¦€òÍ™Uä ™eÓE†ÐvyCÈ¢ÔËEg*ˆ‡8w©[¨àý]¬?úïá%#¤©b¼F;‚R¤H£>’áãà^‘Œ0Ú½‚ÑþU@¤ð›KðÛ«* “õš5öL¢Î m:V8©0µù0ášýÓ’sˆ$‚HcxA^³«pËÇ~ƒùMˆSºI :fÙ ÷_BgçYuŠÀk´Á˜§cáS¦'t1!:ØD2Øc~w]±j~8Ö¶ bÙFTÆ8xÐØòØ–B¨Ä ý]Ľ-¤Ñ@]å…c˹½OR6&NÜ#¸ß@¸t^££e߆ °Úì5ºð4…H"¤ÃžZ&¨iûœEØÀËü,«»ŒÁs¬•Zƒàl³h®ÿ=åˆfÉ„4øó=Hîû ­œ#&2±Ü±êWAg aw=ƒB¶r’9—ƒ¢^SÉwÆY4‘­DÊðì»Ð¹ð¡)ùËL±&g–uŸ ºëˆö6 ÒH… 5—Á_ýˆÞн«2³M‰<ÚC«wq¹oæN‰H#%-©7{'ƒýqø‰ª10ÿ¤ƒQ›òõ¸)†Ü¤¶B‰£§eÓ|cZ‰® Ðo Ü¥Q}0re¼.I¼þNâ&ý[*03)§P€8ÄV‰M_T–MSçå%ƒƒÉ®Ôì…œÀΛ:î<×Ï£3N½–“³'«ÕmåÉO¢¹s BÇkª mV5©@r=ñw^A´ ÌóÑX9ÆòI‘`¸u ƒÍˆzí;Þ Üó6àäë€öà·€¨ÙßFºù<Ò—¾€Ñ³À¿òe4VN)`4/–ژ§—Ó½ ‰l<%‡(5k®&ÔüÖ ›H?ù«ˆ¿ÿßëÖÛú¹ ³t„ÎöÓ0…*fW‡ć;ÊVÊ~½m$Ãð°…°»¯ÑEÜßAã9¶³rxð{Þ¬Þ »h­Aà q²wéÁҀͧ0¸úØ¥Çá3 ¿µ‚p唎öÁÌà‹åüTˆq¬+’ªœ b„ÎÞShÚ Œùˆú»ú÷"tœr÷I%ý8v¤HÁ<a÷¸vH{ |sŽ µŒôÉ߇üæÿž¶ŠM%ÆfƼîÖãð$ƒ=ö4UøPÒÏUÆ$ÒQiÔóø­Í~o÷~'°zwñ8Q„©¨„©í‘eÓ6ç•a“x™rœ+Ë-0Lµl…ÿ–ð²d%EzŠ&Ï °ëVÚâKMY$ï$fܤ)µlBWLzš”:rHÌÚÖ&]äý_gp càª>ûé[„θ@5 p›çorâÊvöSÏ+¨[¸{+OÿY¶p ¿¹¤&þœùÞËCÀdc¸} ÑÞ÷ÑX¹ áÊ)$ý=ì¿ü˜ yÇÏßóϵ{‹‡æÐZÖïønà=¿„äúEˆ¿øß‘>ù14–Ž#ì×ñÁ\OZÝ`"# bۂΚÊL7êçj-áÒ ¤Ï~éï…xí»èαI#|¢=5w_T±«qîj#—Žd@Óþ.DÔh¬Ü/lc°õ2_} 8ûVà{~xý÷M³Ó7h»·FèN} ¿{.Ä×¾Šä…OcôÂ#à¯<Ž ÑFcå” ëñTHL’oh ¦qÁ”O@óàEøœC$jeÄ Û2Õ1ýq®#{Ì„Ê6×_R68ýVà]¿¼¶À“m líãÀ‰oðÝcB;Õ6xéÓ]|üÒ´ óTB( È8V:.;?òHyHÜç¿@çÃß™·üoîOoÚä^¾ÉSb&FüJ*C ÌI8Ͼ ̓çuýü±Ó e®#¥PcL£›oÊå^€pù$FO¨€SÀ©ió¿þ»»û¥ùíùãqNx:TÊ×òßÉp2UŠýæ’êg‡ÛÀw½ßÎ6Ûò´˜Î¡ŒéÔãe}Û¤ñ/@Kd›çMºì^& òۆϊ²IOVX*ùz—2tѯâ" ÉV'ÛR•á6m„°«¢n‹sè:á&yÃ*2~eÌ´Du p–€ÂœÏón8ö•?g I«ŽærOwò _ÍLý DûWó½záòID›Ø»ð9àôƒÀ?úpæ¡b'¨ì½àø½?ôë}ë ù‡ÿìpáò©\QC¤1òÍj^/éR…`¬H w.#újgØF¸tÑ#ÿÑýÿ…^ÒòM¨«P hõ.)¦/MÀÍ:C"ìƒù!˜Þô–ź†K'”äÚÁ¦žoýàÿ£J@Rz)}Íó»Þy×[ ßñó£}¤Ï|ñ3 ÿÕ¿EØ^ß^÷­L· Û² êã­ÞËšALá…jó)G<8÷|FäñèÊÇÆ6xËÏï°AÕ½6žœÖ6ømƒ GüÜÿú·htT|ö” {æ0O,(ŸFcå´V¼ay¸—ZâS**“ ;‹¹¿ÕexâmÀ…ߘTΗN:å…­\[›é¡•Sè_{"Âo-Ão­ÀÛ| âúÓ@¦çO±¡3Œ6ÑNw!¤÷B•hùËDÕYJ ‘ô÷hk­€y>¢Þuµz÷ÀÑ¥|)ómý»ŒÄá96hRI1áÌEIºh/ ð…‚DY2é–1i¦elVrO[¸ |ÁË·œg[Í{}Ñ`Î`N+_vˆ÷’†:] ñ¢$ ÛmÊÖÈPžz˜Y&diXõa°Çk»\oü®×2ÇgÀñÝfÞ«}õY´·_Rñš^ –ƒu¼uBŠTkN‡à^€øp£½W04Ccõ4âÞ–ßoønà?«À·‹ífê'Ï|Fÿø#zPéí2¯ÙUYó‚¦Êªè ”x~þwÐ9† »®tÌoÐ]Gc¸þ¥–§¦´›‚oÚ\WvñCønžÌCÄü~ܔ҇¯5„GïŠf¾3ð- m›Ú&ß+\†|øÇ‘üèocôEÿ¡÷c¨ {<Ë6È,$ 3¬ÚLüFcxNž 2‡SßIe t×À¼‡¯>­˜ïð? seãTÑ7j.C>øãHþË߯è'Åá?…~$ô÷rmòRàÁ ì ˆSdèÊnçªÏåmHÿ›Ûz–Ê}|³ëvß„"ý&†'þ ¥~ý'hN½÷»Çá…-$Ã}:æ‡h,Ÿ{â÷Šç(ê·(Â<ú>Ë{OÀk.©ú…-0_Õ Bèä^ªÍ¦Ñ ? »ëF{W7þ ÐèаSÁ\_ë;ÞÙˆ)×J 9 ï âïÒpþmÀ©ÆÔ¤%Ü¡*g–0ïúÖ-]*qÓõ&vÚtË&²Ð—²I„ÉÇôÎÌÀŽÕÝä4Ì Ð© %ßÁ’mm™*ÑÒ{SA¼Í °þÂ_+Íê,ô¤ÑžH®3Ð ÀÏAÔh÷Uˆx„péÇÎ@Ä#ì^øðšwÿÍGfÇý½ŠÎ Ûüðÿ†øärÕ%IØÔL«§&òÉIÞW!ÜsöŠû!+§áÿåÿ1NBS¥Ý´ù0:Ð’y¾¶‘Ÿ×K% t¢–³mÜ ôw€oÿg xVéS ;Äré$’où§üäŸàðÿòÜ7›lÓ±‚ãä`üî2€˜Ù!ci•:Ž’Î÷ý3€´ñEÇ©‚±SvO"yë?ÅàGÿ½·ÿ*ä™o>M»-÷Ê¥3;ú¡åc𪜞låDŽCÄnƒÒ?õv½™Z+õð‰ýÙ;y>x¨öjdñòÌ Tÿ}î!«&BPH¬ôŸ×« ¡rèýÌ ÆmwÕgãÞdš¨sm•§`¸<ü~w¬DÁ_U€6JŽ3Ëq°-¯³Ý¯Èá—ì² Ü¸ÕåÃ0–ZÒ=I#>Ïõ·3#N™œæ¹¾ŒA·996æJ&ÊäãÂšÙØiiâT€NÈ6yCÛ;ÁÂÀ®“BÉ"ÔM`»Íý+hì^ÖÓBø­ešüé°7fàôÄ\WjškçÀ¸ý‹_–Oÿä#@Ø ÛÛù!zßÿ¿@4W«4à5ÚÌvó‰œy~žšÞo.¡±ri¤7PqÍŒGûàÏÿ¹ÌÂÒ&³…¦C¥Ê‘1g~C1k~˜OæÜ 53ž) šîÿvZ{/sœbÉýß…áÀ¼rEãú¾^šIŽÁaHl(ÉÕ7â~#ä¸ûÛéä†+H.:Ÿ{Hîù. àÿ¡mj« +*Ò&Ïî©ÿxZ]ýN8}~„ÖÅçþm1MŽV^´uBõ… Ƽ|Àd¿PÎñ]cùxã·–áG{`W>;ߊ|½Û£ ´|@¤±–ËTÊ9¹òŒë¤LÇÒŽ5pîc´·¡6 ßóÕ±’ 3γi”´'Óõ ‚íªÇ¤…á. …)û¾ dÁ Àr©SåM†‰ÇÔhl¬ø<évâ.`ÚÄ]–WMÀa¡)˜ƒ³øyXt€.Q¾A•Ât3‡ëM)ˆaaÀ™åZJ½m«%ýqõåÇÔ&=!° ÔæE™ÄyRŒƒˆz×!¥P›èš]Œv_Etp øÉÿSm¤8MÛO¼¿l­¢÷ÿ].ñÆý†fÓT=ú‰åùcgà…-Ųj¼¹vìo~Óî@Qìªÿö˜’jãY"Æ!D2*Àt#¥ÈŽÁgç$­½KB?¼›ÆÛj—ÁV>C. ™±°Jé"ÈÃQÔo¬¬‘Ù {Ò<6™Æ *H¦Žµ Ð7܇b÷<달 ÔŠç‡c\;¢·ÇüÈqxümy›ÈV¬f߇{¡RÃitŽzù†ëÖÚy°§~±ø+ƒ àZU&“îd^‘Œô8¢ê–ô÷ŽÁƒ¦R—aÃW€‡~RïYV*{'ii£&MpY2S·1Ü6ŽŽïMà¦øʇqY¡€{J°ü×"h¡.Œºãòª1^Ñb)lšmò±M”U´aÉßÞaº¿ äÙ"$A²«®9õÚ* ~â8 º×žË7Å~{à^¨&C×›M”Éðé°/l£±rãŠý~ð=À›Þë\]“Ñù·">ÿMñP%Û [ù’6uL¸,Üá-„˧T2 .¿øW€Mqún%í&O®7Ã1½qul·`:euâ îz ¾èÝy ã%çš– ‹zè¬bGÀ§ôpZ8õZn¨· Äëk;;—ø¡NälP6¡'|ÅVŇ;iŒ ³¯ÑVY£Cà~Åý½˜ãû8xÓ•«W° ¡Czåc¦• ´Öï+謑a£ öÜ#æïFýî@М–öÓlûdìnD³xõ Î™7Ïý©ùÞ¦ö>Û§Š&7S_ã ‡ŸØVʼæ„í•:c–V‡¡ä¡8Ú.Ý3þÔH0Õß6NÙÆZŸw|‡Ûóó—¤f6›j[!(Š5n›Hš'-Ý«ÂÛræ[eÖÍÞ'sRU8›‡¸¿ 4´WØ‹Ÿ,ÇÌ‚Uf¾ÅR¼F³ ™ÆÊ±É’WiÇ9³§HFˆ·Á¹¯²Š2†áö%àì·ë¯/n'´ýt“ç›BSlqâ6œ6 bʳ¤ÛŽ ”‡ÏØîké6"yö=o >k4Êñ"Cˆ‚{}ÄÉó¤Dˆ™b-Úœ%J–gîT0>©Ì Þ];jšH¤©)ØERYÜà‘²‰zKâñ¢c(9ÆJƒ2ÀÉ œ’²ßgßMÜŸÜÛä¤Ì¾SÕë™ÁÙA‰í˜¥ÞEÈäs ®]Úº¨T+håûøs˜oð’R9ÜS¡3/þuµï^Ðn’æŠÚüæi’«>ð ¶ÜCsí¼F"‰À4ã·Ô]ÁÊ'~ ÁîËôö. œ›9URœös‹«cö0³AØšúÌ ÐÊB fÞ+i® n¯£™ òÐîð[Kˆzq~/&ÕEÁÒ 0/T)¦=œ1øÍ.’Wƒ\>]þ\âw;ìžÆñí§ðñˆho6Ì/cŒs`é8øà@+„0¥ârì,D!¼þU,í=´×1X¹ƒ¥ótOcØXWÙ;Aì§¶•ú”$ö©™c‡­ÓX?x*·A:êƒs®E)ótä^è!\>‰dx™Ä H-4×ÎA$‚í¯`©÷<ÐZÃ`é> :ç0hžQ6€W¾!UZú¸=³³mc¶iåòƒ:V`^V"µ<ôþês­ŽcKé‘3¦6VzÀ}Œv¯¨q€)†;¯@ÄCÝ5„Ý5$ƒDûWïý)ûæqÛœb›Ï\±5Ë&`ϲ9Û¾M™2)8YŽQíBɲyK8¨˜ SõÃPÀ±‰%´¥LeæŽdühwZa åZl`Ñuâ±G=g@âðUý Mé”ß(u 8^T _bõÿ[ƒ=ð  ‘D:{¡€A$£©¥bé!ú$üæ2ã*&ò5ßæf³”Ñ~ÃÕshï¾<‘†›åié¥T²€`¤V#ñ[Kˆö7smj¿µ¼úðà{«7}¬·t‰àÉ(OÇ.µ³’ÙP¥bgŠ¥÷“.¥VOáðüPK›I :@wûi¬¼¤äüGÔ¹ Ãæq [Ç1h®cƒäþbÛ»k?œ¸w¯}©‰ræ …rD&˜YRêD,’Á$$¸–-ôüyRõøˇ/`¥¯mލ}†á:†Í6–½EŒseçRâw«x`"¶[ËnjMõi›jÕ“Éßäí·,|ؾ o£¾ A1àiGXïÏ`̃ä)škçÐ{å ¤£‚Î:ÇÎ xñ‘¼,­ôü°ì" %¼FRJH™èÐ4ÉD<Ò~ÆÊi0îcpýE%úš÷T')׸b%*À7W×ð*×ã¶hÓ¸ez·[Àe\Å0®©”ó\½B[½™a`¼Ó •¥^§°3 "af¦d1kf mà *h˜°Ø_* MuHÊ|ÓÊL†Ñ0_Þö¶„ÙDîÁ­fÂE<ÔÀ  ©ôµÏ=d¶„Rß+j¯û¯L̸¯%ðÿ]tÖío" è¬)¾ý²P*y7É}ì®Þ‡•ÇóqqW1lYªkÆæåöó‡HFðÃŽVœIrçIPŸ§2ª6ÑŽ÷À/ê÷†ÁúÍ´Nà°} Q°\Ý!¥Ž%íVz>v»÷aåz¹ 2–ÌgA{"©MqD2šëŒy¹ %š£M´“]0ͤJ0 ½.ú„'pj¸’eKü¶P³*«—6?q,íÎÙðÚ‡ê¯ã‹¤·c\&ãØë¼k{7ÎØ©7N:g ­õ{пv£ýk{h­ÝèéC¼íç*=~M\…60ÚÛ˜°«@:8˜jsÑþ5$‡;àAÍcgÆp¸ñ,ðÐϨpWBPZVF•lßŰ‘œ&Ç€¶qì–2à6YVxAêq:{bcêÐz½Ɉ»²3瀺ü[6ùPê, “&•EŸ ÛÓr¥$ÖÁÜ›–ê ú^#òMHjã–Ôñ~>±³‰´Öc®˜¹tØN½žæH¢]ˆßl¤YøÒnK1f’'À‰ßZ”QoKðö °{¹¸­ÚêWðnÛ'ß‚¥W¾ˆdÔÓ Ľmˆ4‚ßÐJ l.oªcžVÉÀ–”BQ9(Ó)Æ 4G;hF»Àþs€”ñ&zÝ38Xº½Îø)í2—Àûö±·`éê‘ àéøÞYȉíOÌ áéäE^ØØòÄgLÇ€œyŠ%×1æã™ ™î •ìCö´ X½Ö´ïC¯užûJ” $.Ž‹ù‘Éã:EÇÔõMÕn$ݸe¯ûÖ¾¬7!ûñ¾RÑV·v°ºõR`åuØY{#F“ÕÛ;°r jÃÎú7bù•GÁøñ\>/³A¸| ­õ»ó8ÜìR ¤ñ€fƒ$ÊÛè¤ 8$‚x«ÑV÷´ º¯ÃÎò1jœ4;Ò“ßÔ5~›:Ö2ÂJÚ”¸?͆O${ºq•'ë"‡}åô&–QxoÍèºZÒ•cžDªŸfïÔZ»ÑÞUD½m´ÖïF¸|áèQ$›_…<ñ&§ç¶d]!î)òñK$‘ ÑãFÒßÃpû2÷Ðù žú}g¾ž¾ Hö¯åYC!%âþΔÃ>Øz q^££VkDªÂOÞõ¯ÜÂ\‹6ÊJ’ ¿ØD.$h±ß ´=x”g iTv|Öõ€aP§dg/ÒàvMJÑ7e_2#J<¨²¬p®©g©’=_ R†T©+Wy-ýrS‚¢¶Vö(©íËŽqÃ1X›]&{®I/ºLÒ% æ¸Þ4¢$ÿXA&1¤RXÆFÓUö'º“KßíÕòç–ÙÌåÝJ®Kƒ0×PõQu–R½‹ú{\ÿ,Ä&¹4wÒOgåßMz®~ãO£Ÿ Œv®¨øæ …æÚy´Žß0Žý—ÇÖ“`ÿ¥¿CÜÛÒ6„"÷w0ÚÛÀhoC%B¦ÉXéŽþdȆHã¡Î:ØÌ7Ö¶v/àìÿ §Ÿú üÑ.­½ÛRÑ£¸¯Iàêƒ?ƒ~"´š„Ú˜Ú\;7mƒ'þllQ`ƒÃíB Û`›ñÞYêp‹ š{Ïãìóÿ §_ü üh×mü¢Ä„Ï#[* ³~7åXNöM1ãpÊqŸæ“¼=¢²×}=À¸Ú  äßÊÓŽSö‡{‚Î:’QB‡§tîz=ü \T^¤Äš¸ ™Æ$<­À"ÓÑÁfþ<‘Æè_»™Æ—O‚{†Û—Ô˜÷ ﻫ¸$…¡d ·‘N¶|*.²Í®XNÎ)Ó0w=^Æ”—aÄ[΀Û> K, õX™·EYn·-}Ø–k¹qÓ&{w§q€¾‘òÞ6Ów4ÝÓ¶ªQE™pÛÐIy¥®ž˜ôQ©Š6‹ºÞ&e¨ÿæ"йL`tìñì$6˶å“|¦ÔÀ*Ô¯ŠÌb~©f̤úŸÒÖæ„ˉh”™Š HFøD‡v¥J<øÄoik×ßù‹Xù䯢½õ’J$â©d@A{£ý«n_ÆáƳ8Üx^£‹pùZkç,˜Hª¢ì.Ó$W‰È¿çyˆËde˜i™Æ*<*~Úkt!â!Z›_Å™Í'pýõ?„þ]o¡¯ :þž6Vqý›+Ÿùh/*ø!+§à·Wí_ÃpûR± t⣠´˜iÀOý\b¿¹„4 µõUœÙz×ïû!ô×ßB¿ªÌ.2°¥÷ÿ(¥P›RKúfÖå”C· yb%õÚè5Ï£Ó» öŸ0–ëpOn€æÚ9 w.c´wí“]ø­„ž@|ù/!ï~éyKb – êí+¹CæA¦±^=æçÅ›ˆ4CÞX= )\ú2pÿ{€î)3¦¡bQŒ›-ehÂr nrŒ0GRHP“šß-à.‰ n0¶—wчtÙÐä*eè Äa±éž² nÛÉ*N<.7%ÜãPÅH«™é8èR º¼!åzŠÎxš@ržÇ~ÈøÔ²ö섞‡A˜M{m±”Ð(‚|"T茔êß"Ua lÌÒ«¯B2ÖK¤±fÇ% ÍËÀǨ໥Ýuì¼÷_côé_GçåÇÑ\;‡°«’õ4WÏ \:d âM£ƒë8|u‡¯>£tv×®œBØ=®Ü©˜q¤)Ò4Fæï«6Óú98eÌCò%~æùºkÀáÖÿ ð×|?z¯ý¾rû»:¤3¶KÛëØyׯaôÙ_GçÒãh;‹ »ÎÀÉm°u Qï:¯l‘m¨ož¤ûúßLë®mÀo°÷°ö ÐßÃú¿~Ï÷£wï÷÷S,pœ3‘F2@æ+SS+P7ôM9Ó7åÑÌ *ûK¢Ó{^…1‘DÊ™dL9ºAw^£ƒè`­÷qÝ3bðÔ‡‘ø±ø2Xà)©A/T«cB îmM¬èqô7_D2ØGÐ]CÐZA 0Ü~xç¿™@S¾Ź«BZº¨´Ì+eh;ÇU…rì–pW¹) Ð]´a\>^Y9´×R†ó °69²²Ge`„Â(™€4u`¢È2¸Ë®-  Sìm”«&ã±ô!R0=gl¡Ð™1g_zr\$#D×Õá$‚ÐMœÆŠ2p®1)´TÙUćÛjƒ¢H Àƒüæ‚ΚڼÕ]×±íãw•i xݹœå!¶qø÷£ ¢ñ©‹¿€Öñ{´)òö*–ÚÇ ÒÉ`£Ý+ˆ·÷¶TÆÎ«ÏiÐÂo¯ \:ÆòIøícÉWTÈ… Ó¸Žd°‡tÔŸÈlÚT‰~Â6Â¥*®¶Ù¤Àò“B*%¯ïÑ´÷ÌïüeŒ.>ŠÆ_ý[´¼´ V­Å¾tþ˜Ú 7ÜÇh÷ÕmÀ=p¿1aƒS:Ç&)G0*;ìo"î묭êX–…3謡±zAg €Äò³B*$÷½×mS¹«BS·9ë Jq>«šÜ›¡ÿ/…RÏí_sŸ'` >\zíû1èíÁ?ÜAsíœrúõ7JF‡ã¸ÆÑX>‰ÁÖËH‡=ø­e´Žß ïóAš ¿i~MO¯¨P¦,©[ñA{áòIøÍ% ·^†”åSR¢íy ¹ ¼îhøËžó‚ç °+šóKR5º(¬0ö¸mpU_(/(+s~æ½Î²9ÿ{3²lVaÑîä,›.€…ÊÞ;„@Xã‰ßçà:¶˜ñD3§,×–“L·”HF=Ľ-ì>ÿÙ ª3Rã±~F@ž ±ûÂß “cS™}0Î!Ó$r‡Ï(×Z†ˆ‡à^)R%{æ7èu«¢½.ä5ïDrßÛ1züÃèýÍÿp¸öÉ× qìL.?tŽ!ì®CBB&1’á>¢ƒMć;Ñ@©Alæ ±ßZƒˆ‡ã$&“Š  ‹xÔµзÖΣ¹váò tþî7¯Þ‡ä䫯ôÚprï;‘œ;FO|û†[hŸ| Z'î›°ÁšÆj&·AbÔG´wñÁuô7žóøí4VîÊcy£ƒÍ;Œ?”Lc$ñP¯6<£5žÏÂo-£óåß@¼|’õ7VϲYˆ—GYø”ÓÌ6Æá%³}3"ìaçù¿¦HùXqÉ}\O—ѸðQxÍ%4×Ρ}â~µB#¤dz,ÇÎb¸}£½Wá·–á7»hvV?ÿ1È~Øøœàê0ÜxJ‡šÈ<g:ì!ì!>ØÄáÆ3H£¢½ ð `é8¤HÐ{å à?:#lºêŠü¼„ i“"Ãü¡)U²laƒ2 MI¹`ð½XNÙ%ê'nÓ6¯ s~j½÷ÌQ®+ _ @œÂRU–M׌§G!eè\´œ »èMWùކÁ]@+ˆd‰`ÀƧðhÿÛ—0ÜzñÁuˆ4ÖËûš…ìÍ.y±sRE‡¹Šc<×LI„l3&¤txÍ`ë%Ä=•Šz¸}Yݤ±Dc¤¨«~eŽ• ù¦÷!ùÆÇðÙGÐûâïÂûÛ?@£ÙEëĽh®‡ß\Ö’<£™4¤H"$ý] ·/a¸ó 7žÍC.xØBÐZ™Ð‰öòL 2 aHpÍ÷^}ýÍá·–á…-Ÿüe$ïû b”*«,ø’‡ß‡ä¡ÇèÂ#8|ì·Á?÷A„:§^‡Öñ{µc¡2ƒícºëªi©Æøpq£ÝWqøê3Ø¿øEÍô·à·–Õ†Ô\žp¬“-D&”¬B"õ0Øzi¾ó§ÿð¾?Fžêž²ZWˆ›Æ›‚±%ï“zCJ•îè`sÜ7wTŒ³~wã¼jÂÄ$Aó–èÞïEóâÇ!ÓƒÍÑ¿ú<‚Î14×Ρ±¢ö HÆà…ð°¥ÞO¨KçBïéYxkã¯à7—H‘ëîKH$ý=µW@oþMHûà¢þƳàa[%{èýÕæÙyðâ²lR6U–ͲÐAŠ&¸éo«M˜³Òd&íHêï]¦Ê¤_É Íäñ*1J¶Ä-&mI{œ÷×¢¦¸‰Õ¢ °.:·U²lÎÊíIK;,{®M'½ìZª¾ºM‡Ü&Ûè¢^voªþw™FúDôwÀÒTÅ_&\‡pd±ÉjS’HFÔø äeŠšu–½MàØ™âúØÞ„óJlÆ£ƒœ fÌËÓŸK‘äà;‹m—"…Ô’cR ®_DÜß–NÒëF}/Ø=¿–ox7ÄÞ "~îS8|ê“`Ïü%¼½+šÕ=Öñ{T˜…”H£>âÕ”$Mà7—à5»*ž]+H¤QÌá5Ûù¦Ä €+›¤"ˆGH‡`ÜCõ‘ô÷ ®}õ#ÿcí½ð{ràµï†|Ý»‘Ž1¸ð) žûØ“Âë]ß\FóØY´N܇pù¤ÊÀšDÚÛˆöUr– pË$‚*8÷Cp¿­%yn®ÛƒÐç&ý]­ ÓPñÇ[Ï€=ùÈ7ý˜È¦Ž‰eã°%g@2ìÁ [j¡)*Çáºr$G{S}3ˊɃfC}CÿqÝ$èJn8”ôøC«÷ƒ¾Æ=ˆx„dx€Þ+Obÿ¥ÇT¸ÐÊ)øíUíU w® ì+¼½ þøÇ ú›@ûDñ«Ä=tÿöÞ<È’ä¼ûeVÕ»»{º{zîÙ™=±Ø€I ”@ñ°x¤¨ „ÄC‚AÊ&e:dmmJÁ:¬*dË4)*DË¡ iI$ES$°E@¸ˆ@,{ÌÎsoÏLOŸ¯ßUGú¬WýúMe~_VUÏôìö‹h`§ª²*ïü}¿üò÷½®ëO%ð›³:Rn!õ3ã6õzÚ%ª1ƒxÔGïÖÀ£À©o*·û\?pÞÃ1P!V*eÓúA`PF½§Ø-Ln’“Q–ž£iê,‰e‚I,CÝ7•šðÁ覈6«ÒT÷£¦¸Í‹£[FS„A§À×Î5å–2Ù4¹)}pjçG‚ÖÚV6SžòÞm*»$ÒOµÃêÍW±uñÏÓk;Al´¶´0c–Yz¹ÐÚÒ¯AMÄë×3ﶃiÓ5"¶º÷û[™/ï8š'€¥© ¡>x9ÒlW¦œákµ—Ù£æ:åh¯£DÚzxêCPO}H«mmÞDxñsè_zë—¿<ÿGÑ^­ ¿9¿5¯ÖÒÀ1õ—GÉKáùðê­TIEÜQ€@<ì"‰Fú]~ ~sáçñ{~È^&ah3ª¿Ûæ—zxâCÀ;uDÝ›ˆ.ƒ«ÏaýjN4g!kÍì°åX+\×A¨`ÏO¥'Bœg»<1„ç#léàGõ6¤/´!üâ¯#~ú‡xB‚Øv‰w`‰çpãË¿»3´Sõ·Ò±©%!½4R¨D)xAsg, ×7­Ý@ešâ£³ß‰Î…•Ò>ªw¯¢þÂí5ýï8ÔlÿÊEH)xïOç¾»½ú<3‹ˆ[:‹Ú Mw¼z'Q*Ž´ûIkJÅšýþúŸ©v­-ŠLï1µ‹`~¿Vâ`Mî·³L6’öžpÓ àú¹ºÎ业Æ–¥Í àn©•2äòDÁº¸_T€r7mÛ^6vÅUÊP1¶z«”2änÑRã‹ãϧ l3Ú&^[ÿU€š?yõ…t[;ݲþZEBH/;Äæ7:ˆ R}åüæ,â¯òóhë7¦8Cºzõ¹cˆG½4‚bMG•õ3)¶ €§ÁZhÐæ×õ!Ì¥‡ËÉ'¢Â´³G€w}ŸþS’É›/"¹òÂK_^ý¼å : ©ËÊL Sõ“qdÒÔGLR׃ ˆG=­o¬xA¾o¾€øöE`ñ,o¬ªþ>}}æðÄ÷é¿qÜzÉÕç^ùpñ“ðn¼ ¿=¯Õdf—´‹‚_Ó.Ð2“¯eu „ÜÕ¼z[×ÁíË:,y­©ÝX®¿ˆxí"0–>GâÊŒS,²áÙIIJlI¦ {<6%„h#d¼;UoïÖé/3¿ƒh/ŠÄ#~ƒ“ÄÜÕ?ÔÒë~=“ÒOÑêè§Júú~¥nV>ê‡N`ôâ¿6ðÙîyÔfuôS¯ÞÑ‘oU‚xÔ×;g*A’ž5€RÚ ðêímþ§~doÖÙ*m‚ÀkÜõ£,V⺾<_pa!c³¶ßS®@û»Nœ€ý°‘*ѱ\:·a¸ ÆÂéåê­Ä«˜`¹>„E¥ •e0rRl‹'ܶ‹7·<¦þÇQ¥€eü3´Ê“…“™ïô˜Ò×`<ýoé~ªqÒ[ö^¯ÖB}ö(†×_¢d»Qjg,ýÿÆpµ™Ãuoïw2ÿXá:ɤ>ò ›úÇúZó~M:ö˜y~ㄎæ”ËUrœÆó€“Oë¿g>¢ƒ­]AüÒÇ0<÷{ð_ÿÚK¡sâq]~éiÀ õŽÅ8’æD=È$FK>ˆÑæMă®VdI#oF¯~jñ£Å”Šôw0v9=8ú´þ{ïG4ƒ¹~ñ+Ãè¥ßƒñËh>‹ÖÑGá7fRÿ÷$ÛÁ×Áth~£õeÄÃ.j3‡uÔZˆ^ÿÔ×}Ô¾Î(#ŽóÜTÝÈ ¹ ŒkC+ÉBÒK¯–MáùI ¯ÖÚ[]ö€ÿÄ/i.!>ò_ ¶ú"¤_C40ŽFˆS‘1Ú š™àÕ[ðê-ô_ý¢µ×€ù‡wƒ«p3rñ¶‰ =¯A}¬wŠdP×î]áºÞQðÔçŽÁ«·°½|8ó-ÀÜ{OxU!eèJ(ºàW"”ƒõª’2Ü7 8ˆS î*eH…2¥ØrS¥VÝx6ãÂEžÄË ¤ýȈ™`]})]9°Ï.@›ÔEîaü,5É*€Q‡†ôÉч´,] PÆÛöBÈta²í~é×Që,j¿áôPScñ46ßø" &‹H(¤Bg{-NMÍúAË#Ž ŠqØn¡F£’8„fd5Ð IDAT ÚóÚ4§ž¦ù¼¼ØÜ¶³ÕÝüià›> õþ"\¿ŽÍÏþSįþ Ú‹§Ñ:òD­ ×3ÿç±\ݸ”Œ!Û Z‡0ê®do‚ΆW¿¼ï£fcÏE#Žóå&9™îÐià? õ E¸y›ÏýSDŸEçðY­ªâH&"cj¥±«DK»ôŒ¶V!³ÐãÃë_¾þ£v9€)–A‘@(÷‚Ö\Z„D³üžŸÊÓcSÝh§Ü €_ @W¤)Þ;ò~4·/éC’A#uÒåM¢QVúõô€5RcËGcá4º_û—À_ø{»Þ9·ý jí Ö¯¥`]Ïñøàv:.F›7‘„øÔfhyÕÍÀ_üßîÞZ[tGžÚa¤Æf îb4pnÚóöÀõ¤Z®P|{bb8 õ][ÃR,;¥dBùà¹tʪ5Å‹n/íw ¾WQ6Áü– £TDßv¯¢lRÆmŒ" N=yAsnâžÔ zР²~¬®´ ý«‹TŸ= ïåO"Þ^RKr‡ÊU='m0ØB3-¼ðj™ozv¢(*¥å“áö*T"h‚ ê»iú3ï¥%jž´ rZ0] +`î’ïþEtW~ò¿ë–õž•~]»ãÄaVcWŒ ³ˆáæMÄ£j3KÚ—þæËv LWEŸ2A«¸}~î’oûEl¯þ8¼Oÿ¼­[h-=¤ûƒ”;uD»úƒJbÔf–0Úº…dÔCÐYDmf Xy¹ÜNZ)Ö°´æ3IPéÕ²ƒƒÚ-,ÈŒe­ž£]ޤ_Û‘/ä0—ø ¯ÛóOcñÚ‰6uYô·wÜPí>¢}÷;A“O¢ûâïÜÀ /Á«7µüh=u9Kb$á0›’0Û*AmF‡žï¯\‚ðø_»7ë¬ëØ©‚YßÏQ6…#Áìð“•€ïi+}òߊ˜$(¶ 9ïQÄûòÞ(ÃD¦@+^(Ë$( éóvS¾»6¥b°06cã~âÂRWÔÄ@¥Ïû–€ùÐ-õ\Þä‘ׄ¥¯Øò`ûnÞ=X¾e3q]1'õ©¶ˆgæ¹£µf&KçÕÛÚóÚ¯:¨ëç~Mk/7ç4K‡~^­…ÆìˆsÏo¶Îu‘¿XÌ®]ÍTBüz[ ê:"âØÖÓ[óJ%n,C©Aç0„ð0ܼœ~·>hú¦ ëÏjLi…¥üTZäçO->„­ý2bYGt øÍY}`Í»(™¯t}î(„”·× „Ô>±ëWÜÊmjgáÀhÙŒj¼M¼K->„­ïøe$^]ï‚äÔÁ®zêp·W!¤>¸‰+ùýÖt¶D‹m­bÌ_~sAë‚ô®ßšƒ_ïdgvÚµžÉBú;F¨íÛÜù»n\'”WGoþ]©ñPÏæ¯ÑWo§ÿßßœE#Õ·ðêm4@-Z®ýYö¾Fx A4Ø‚”~ª–“ºÙ©ù!l"ìm@ Ô„@ÿÖÀ;þPëÜ›uÖ«pÞEáµ2i(¬&ÌcÄã™}À¹ Z8têÝPmÔ.÷\F1:ˆ:(Ä9@¸ÿÀxY KzÀ*ÇE~‹£Âw¶Å'/"¾°äÉ Ãá= ìäµÁñGÒE»žù|{©ÒD¾ýZ"¼`³ÏfN¿ âK¿o‰,0Ç¢éoqãM­táéÖ ÙÁJ™æul4„Û«ˆzëÚ…fö„çc¸~xê»ì̳ ×rU•6g®IÚ‹è?ýW! 2€á×Ûð³™ë‚ðw@è8àM<êeþϪ·f.³é`ÕǪìï„14Ñüû3ÿ÷é:˜®]ñ°§•SjÍ:P% ma!•LãÂ0Wˆtì ¿¯ÖÌÔ~Æí¨•ˆêÙÁL- êO¸ßXò¦ó;ÀƒùË÷» _¯ÞÒnoµ¦Vuñô|“•3dê5:: –_‡¬5Ñ9ù$ðµßÊÞ5?xAgñ¨§ ót.Óîi;ï¬]×î'­9­9$Ñáömà]?¶?ÖZW]!(,XIXŒGW nÃr¶oWäE +yKb`§õ$T'9 ’®O¾Ûôži°5ý.¾ÍI'ˆ| FÙò&¿„Ô¶:ç $õz?rh•Ç–~œV2ž°áõCÇ!½ õÕl¢yøAÔ/=¬]ÛÉrò;¿½+?2§ÎrÒ¶ûk˜…¸#ý¼ÆŒ)ÒË´É3×)Ñ_¹ˆxÔ×LbëPª½¼û{òÛ0/oyÏÙÊ…œrU•Ö`(ö? ³¨j‚fº+ÐÈlÆHv\ŒtûÌaÔµ÷UAôS‘Óö‚è¿yî:¦ë"§¿O½«øiÔ:‡5hK˯ƒóø;õ:­¯­ë@z@Ô3Ï/ÔQ6ªü9s“nËq;ÖvÉɱ™aDæªbÏLs-,»:Ò°fq×MË÷û­³ˆjó@’dê5ºZ™Á$RÔ u(5þ5A0wæë€ó¿ ¤nFóñT!ƇߜÉ΄ģ~ê'ï# ‡n¼©óù“„=?s 8ó—ö×ZkÃLü ,ﱑY0¤)‹•8e2áΤ:œ$+k¤<) ™Í³@ÅÄ;À¼ž0™ñi‹Æö e±¬âŠ`K“’–YžVbšŠ1 ¨<Ýo¿É…D:naN·…´°Ýy¸$XxexçdÝK‚á––Ý á°mnÊwÞõicQê@õh´é³½“dn«ii³ô`š>.†2ݺoÌŸ‚ ˆú©[Ê,fN¼þÇÍ¾Û -y·6Sù>yë"üÆŒfÁj­Ìå"NƒkŒe…ôõ60¸}E/´ § ¤§·™< <üŒÝ`’0"‰¼Ràƒó áž6lÌÁoÌd²„àNA‡ÿ¿_Ó~áIœ¼MÁš Ììw^>%Ütˆmý=olJÃx”ffÂÞ>I­íc냕~°Î;Ûê2¶I¤>•õCÇ‘„C¨$†ôk˜9ùÚ¯|âækæúÍâRÌÍ|w‹iXr!}Ô:‹àŒ[)èÒ[×¾†Qw%õ= ¥½Ð¾ÿÇìçE(@óÌã+çѬóÞE}CH+dªq^ËêD¤m—%Þ•hW!´ºDqÑøme1&Ó?Þ;ÆpÝlH(º?:õ÷;Þ¥ýÙ³:ðw÷áÉzHÂ6@Ò EIAÓý¼‡ÍжeÐï×LþË ÍÊåï|85 sçI8Ô½r蟜ù˜ë7çžÜèkl€híg®8~cF»L¥aé¥àÐÃïÃ\÷e,yëÚ‹ˆGýl÷cìf4žÆFx Q›Y‚ Ùa\vèùýÄ9n"\@o;SX¿p±×¾¢_µ ¸ Ûhš¶‘D €n;œibœb7Amì)À;ˆg3.Êœ¨Ê×k?q× Þuq0€²±3Ô¢Î1¨Å§x>¯¶zµmñÁ|6}oDvdº y ¼1Á.7€ðõA&áù: ˜=ùÚ¿÷€82¥˜^ËsAááõeÈ Žh°¥h¥~àñ°‡$‰´vú7Ú¸Þò@ké!¯†ÞÍרøàOØclL®!¿‹ˆðøëŸÂék_FöÜ6÷p§%m- 6³´³ 0¢$§Ù_aoM¡©·!¤‡h°´ííÆú´ FxÇ›ŠÓ·¿Œ ê™Ç ˆ~ÍíïSﯩ‚ÎâØNë»êÁƒLϨ$Òl«”ˆ‡Ý;뀳ÛØÏ‚pïãÎzÑà;Øq!JÝNv4úk»”б+(kîDþ· ù‹»²”ßÕæ1lžL#ºîzG£¾c\uøÍ¹éaî¡oÀR+ÁÖ âQæ~¢}áµÁ>ž¢þ†›7 ¤‡ÆüI!ѽöpâ`ñ±ûw÷ÙFxº0ë.8¤ç`%Îy½}Á€+Ë5ûm{¶(@§aR09`ÛhS *6ב¢®)(Øi8a^ïÇ_™ƒ›ÔALÁÀ¶mҢ̃¹*|®Œ“±v@Õ;váì¢ö ‡…N¦ñÁ.9±_k/¢¹pQo# zâ£}ì1Ì%@çã¿jglm Û„JðøÊ4<£-­_]›YJý;FÝÛBj7 !‘ŒúØxã9 7o è,¢yø,…­Ë_>ðc:â¢éÛÔÁUÃsñ¨ϯcikï|åYœºúeÔÆ~ÕEÔSÁùB¨#ƒŽ%ܲƒ‡™KÎn,#‰CøYQX8K·qp9‰†ðkM, –ñΫÏâÔÊ—Q ·ÍÊ ÷÷…dC'±BȘ-–Þ®:ÂÓaÏåïZ¹î”Q;@9$Õäabéï€Ò t§»"fŠ©º€dªlUÎï9¿õÎ;§‚{©’ª1¥Ag~ª‘.ƒj3GPoÍ!\¿‚ÁÚuøÍ™4ܼһ=€îBb¸v Q3ÓþV*Æö ûãðeYF¼ŠC›EE×}® †€›‹ï=aÀáÀtÛ¶*8ª*”zŠÍz¡Øò¢î'\  &ƒI¹¦p-7[§á2âÜ-¡·2§Xî¢Û«” ‹…™b-ÈœÝn’ps lTùX}ü›2¿`¯Öše®²CM“Ûøõù“𛳷×R]ð&:'ŸÀ¡+/aîS¿ áE¯%4d’àÉ•k8¤(‰´õQ!vo#õvm»o^úst¯¿é×Ñ>ú(¤_ÇÖ•sˆ¢!ð½ÿ‹]5HÔ»>àXG4°´q¿üqœ¹ø9´·oÒÆ§N ÏÕ’ˆavK^«íUP!‘DC 7–¥P›]‚£­[Àá‡h#@Y€ÙtÔ8¼}_ùÎÜøÚƒ›¬Ý’…7ô÷š ñ@mtgŒË?Qɨ¿« „®ƒ…‡ŠQÀ® W¶ôÿw³öµlcW žtlîÔ‰Ì'.ÀÌof[;;L ¾ÙyðjHâP“Ú~cF«¼¤F¤ Yô[!=xu-](Rÿm4u_ˆ‡ÛYÛ«8BïÖëH¡VD’žÖþ–>ðÎÂ}ÿ«ZÊЕP,ê#nsq.²³ÂøUŠžŠxÇ9-ë’ÞfM¹ñ¹[Q6Á¼ïe“ üÆ,ÚÇßﯠ1ìcå›?Œ¸Ù¡çÀlxÇê2:B"ìo!l¡6³”E¶‹z¬]Û•¬wã6^ÿâQícï@sñ Fݬ¿ö9à{þ'`þ¤} Þ¤p$èyE/Õöáy>¤a~ëMÚ¸Š^­ƒµÅ±>Qд—ß!O-‰ðähu?ÀöW4 ièà#Q4ÜTH V¯"ì®f»ø<óŒ}ìqÚMíÜБ3Pq„ùÁ2m_EÏï`möA¬wÎ ò›îýÔÐßkˆð¤àÕ€‰:¨ï®ƒÓÏг¸ó•KÐ/Ã}ù2ðÄŽ ØlOøzïŸcä.ìë$Èu®å®kDPžDÖÑmE§û*üz[ŸS"ð!£=Ù !T"ŽCÄÃmí~’þF[·0\ÒóQ?tJ%ؼôàÑÍy¼¥~TP8×wÀalÚ.Rîuœ5?Ù v5O†òµ¥7 æöÑäÄ :Êf»Î‰²©,¬%'XDÂd]¢l–âu¥Q6m`œâE\0Ǖ鞄=lw‘è…BàÖ{¾'?ñ›HFýÔÇ:F2êëCk“aÞÓEßoÎaì ¶à7%‚Ö¼æ³~í?þ5l<ùA¬Ÿ}âñ!?ªo  Žprc'†}H/Àhó&âAµ™Ã)øˆzëèß¾œ†ßY`WÏÿg 7–Q›;ŠÎ‰wB%n¿ô'À©§€ýÏü¹Î’¿ü•Õ‹RqJFzð›³H¢Z£ZožÃñk_Aoæ(6gckæ¹ aY0§æ3¡®áL´…F`¸v *ŽP›YÒ*1qˆ¨·±»ù“[WÏ!vÑX8 /hb”ê¤ã¡÷»GWÍõ5Ý]¹"e0³:X=‡ã+_A¯u›­ãØjà6§A£i®4ôwG“5œ‘[hÔ V¯BE¡½Tb®ƒ3 U²\ iŠa&vï4ØÖ‘ ³ÝŒ‰Pó“»>J%;0'’‘Û\$,$“ÉŸ¼D”Íõö;0Û¿¥TÕS»Õ¡â(Mžö­4*õõxüÎPqæ~2þõWÞ@4ØDÐ^@МC4ØÂpýð?Š·ì/o.I ¤µ^»€ä"؇ëî´opxP{grhÿnSR><&——¼wÛ&3À®G*-Û¦>ÔÖ¨bt. s¦,ì'¥Ä àÞy¿qØÁËz–“Úõá0[ÔîeàÙú‘ÍÈ”–¾B©½(F½Ngý¥3Øxì0÷Ês:*]ÐÔlÒ°‡xØCÐY€ìé1À€¨¿©eJ /h¢¹xѰ‹Ãç?#Ï¡wô!l/žDv£z± ‘d’ÀC4†tú]Ìõ·1G)€ŠÐOeƒÎâóÝßDå¢V.˜ß+/<‹íåóð›3˜9ù¼Z k>ƒQo ø>Ôë»ç6i™˜Ðäîn(ê@óðƒHÂ>¶—/d~Ø^­©Ùñ8Bg{Þ*°üb¿†~k½Ö"†µFµ6F~± ”ˆáÅ1êÑÍh€¹Q ÉF ½å ™ªƒßœ…JbÄýMí×¼‹ù½¢U` ÐX| ÛËçcOKÒýÔFXˆÝ“i^øõ¶¥‡è VЮk/ ’ô‹úŒ‚6F²Xè>¢”€T1<£ÐL˜KºXi¨‰:˜=b¯ƒÛ—óëàÈÀÒ#fGay}Ä: ˜ŠOŒ¯1¸Þ9\kð^U©†›R;;‚YÎÜisRŒ]HÛü4ñ­úID~ bÔ‡×è@%#Z<li#$­“±Q™äìrLîÆ@4ÜFïæëPIŒúÜ1((t¯¿´–€‡¿oéŸÍ¥V:gvLì†@a¥}Á€' EXÀšiÂàL²*'½"X3nz·mH,LTóaW7•",¶"ê€ãç2ÞÊÌ8µÃIoÖ‚˜<”Ü›ú©É0Íë‹‚qoZY('õš^_yÏ·¢qýUˆ­[ÚÝ£ÖB<ê#ê­#êo¢‘ú~¹1B"ûˆG}€4´æ!¤D1{ûæ»ë©bƒ—Jà펇Ø~ qj½n¥µ{ƒö|*)¦2ð·3pÒ»ñ*Ö.|ÛËç!ƒÚÇ߉ú¡ãØ^~›—¾üÈ?N>aî;2g“„‘5•v¬) ¤îÁ!¨8D’V®c• o"PŠ‚ˆCÌtWphØMY`¹óžqp!áé(^-õwm" U&§ ßöÖSץߩâ°Õ ŸÆhë&j3GИ?…$`ûúKÀ·þìå•C›S/ã3¦:—iº‚$F0XÁ¡øÎ:€ãK©¦WoA6&ê B°ê`íÕÏæ×Á7ÿ,=Ö&ûJÞw нþðÔkð·ÛoZ£ÛegžÉ—IŠÐ2­ëùWßâ öÓô6ú^YÀ¢b¦§'˜ÿ ‹A@ù„ÛÙ…åƒéæøñ ¢(V»Œ‹Ëý`±»ø –a¸9îO½uË}ƵLŠ[@y?r¨ ÀòÇþý¯[7SP3GmÞÀÖÕsh>«1! îitô!)¨TE%N×F2¨ë '颩AE¢³•èÿ ãu„½5 R…¤Ôš¿©T”Ò êöeÄ)ó‡}l]ù*6^ÃeøÍY´½­£ wãU¬œû#à}? |ÇOßɸ ðBSþàØJã26n è, ‰C·dì6ú檱?kêR ’I<Ò/b\¤ÀBɈGˆUáöj¸Æõ¾c awƒÛ—5(ÈÛæÅ/£{õkÒCûØc^€­«çÅ!ðŸ,VS}žªƒ±A1]ãçÕÚá@)DÃ:˜].u°uå«Yé¡{íDQ<ó“Åü¾¹óuNÄø½„2U#‰£) ˜›¸y°ÍS”œ$µ{™3×ÛàpïÅ4Úm€$«郖Ón%,h¤lßxÑ` …Sðj- 7oh·£§ßÂî'®ëlüP„ä¸ó‚ØÙ½gÜæŽáÎ9iÁHÏÙêWŒë® ðG†“ê7MBT§´•™ò×z+qÀ¼ F™\€¸ èç³Q‘2eBµŽoØ[ÇpíZh°v Ýk/`{ù¼^XO£}ô1Ôf—°½ü n=ÿÿßðÀßþvðÌõÏs®â(ŸÑ`Skk'1’$†D#e¿S< v”)V$±¯©a¢·×b F•Ìžk!u¡…ð€´~£Þ:ú+—vÏ8ìcãõçpûÅO ì­£}ì1´–D4ØÄÆÅ/á§€™Ãö”±;®ƒ$Ö*ÙUqÁC3ÅÛ†:HÁ»¹’Ô0ó*«ƒxØÕuðM?´—S`÷ŠXsÒŽýºÇõbàQát"œ ËÁsnþóY >õÞA°€A0Úà„œÝ[Â#Ö ‘k¨„Û«èÝ|M»Ÿ:ž…À‘§£ïÁÁÕí¨sIJ›Kp™ïßU^V…úR‹'½éßE:ÅþQl¹k§«â>7\àíÄ)–ºJF¼È!OÓÅâ‚È£3kæ ï;‹•oÿ›Xü£_G#i&¼uÍ4Dô`õ ú·/¡yø,Z‡„×èìKA³WkíH¦ír=IΌ婫ÜaH•‚@‚pÐÕJ+½u(• ìÞÆö èÝza÷6„ôÑ9ñZG†ôkغú5Í|¿÷ûŸú-ÍÊs}mgb( ªTò®¯!lapû2šKg3U-™¦£Uî`øÄó?vÏ)œ±åiýŒ•0T’Pá(UxX†R1”J0¸}«>­+_M݇Naæô» ”ÂÚ…Ï nÎßõ l€m­HUÀp}yWd®)¦:iäÎqˆ‰ˆŽ¹uॆ\N$Qz–QyàÛ~¯Âu÷ªâÞ$eeÁUê?g®,Û†¸Ä‡ª`îœzïZëÜÈ ö$BM#È6í(• wó5Œ6n@Öš¨Í,!‰C}àƒ¿t¼)\ãº#ÏÅ!ÔœLø{Àa°j)€í Ž9Ï×®ÓH.r….÷¸‰….à¸èÉãª-Úý>9¸,lE·W9@—c¸0ñÖ̈»H¦×>…›ßÿw±ðïþ!ZáõCÇÓ–À«µ0X½Šíë/aûÍ—QŸ;ŽÖÑGPëNÝ*b}h*J'…„ðý05.$ Q™~oØÛÈZ*•`´y[×¾†ÁêU@)4N£1Aë’pˆ[çþÝ«ç€ü à¿ú À÷y.:pç†6Q*ÑLR·o£{íE¬žÿ$¼zõ¹ch{ ÍÃg3–\HOZ©µtБ ã#ßy£4Û ¥¶n¯eúèˆEè¯^Áæå¯ {ý%Œ¶nBHãcæô»à7g±þêçÑ[¹ü·Ï6O…‰!O¨Tœ•¯ta[*ó¹Wq„$å×ÁÚÕTž¨ƒ> ¤‡{󀫻*º'¤v½ƒj Ã’8œ0t|ýê¼V×êß”»&àOý÷Fã!õžC ýâQO«¡ø5Ò EMì¨8ÂÖåç ·ÑY8!}ôo_ÒŠ*OþõÀM­·EwäËâVÚ7 ¸ë¿«bº9ò„eXn®þ¸M* Œïâ×.{]Dž‡ÊŠX´÷«¥^•¦xÛ«6p«,,@¼(£Æõ[%ê2<ñ0VþúßÇÌoÿ:×ÖÐ<|^½…ÚÌaøÍYŒf ¿r½›¯a{ùxõ6ê³ Îa® IDATGÐ<òêsÇ }¤Jk)®rA¦T‚ÑÖ-l/ŸÇhó‚ö<š‹g´ç¡’ÃõëXþâ¿ÕšÏýgÀÿ–Àæ4±{•±¿~c…Ó˜9ýn V¯dcö·6»„æâ} µuhW$Cû”¿#¿6 2âQaw½›¯¡wó5 ×ßDØ[ƒµ™%tN¼ÍÅ3€õW?ŸLýçÀ#ß\q²«Þb¨$ßœ£ë`á4N¥¡Å}vßPcw” °U¨~ðŸ~3Û -º›ä$Gx‡BHŒ$ S a›*i`:±Ó 8;ä6 ^tÍ1¹­r>€Èob»~­ÍW´AG™êdûÛÀ7 •z·^ ÐX|P ¶ß<<ô—ÎÑ·ÆZx·ÖY0Û“Cžq‰µ=âÕ0à0 äË#™– iZ$=Äm’{&éCW?ñ*Ør®* ‡Yã€DJÓ“ ¶ G\‹ö~â&ý[‚ÅËM_t{• î9àG9L†X¤€NõÝxþÖòÿÀðc¿ö—>†Öá3¨ÏŸ€ôÔ玢ÖYÌHÖ®¡{ý%tß|9•ßk!hÏg‡9ýæ¬V±ðëY”¿1°˜U“ÿn¯¢wãF[+øö›³ˆú›XyáYl]þsàÔ“ÀßùWùj'\€MíÒIóxŽú[ˆ‡]ˆL7æO¢>wL3´]ÿþíˈ›èÝØ@ïÆ«:¹çëµ´!hÍÃoJë¨<ÂC‡HÂ>’p€hÐEÔß@Ø]ÅpóÂîmÄÃ.âQ?õ­×FZK¢±pÒ«!lbíÂg4ù›¿ ¼÷Ãær¹Ö]ÚW¢þ¢þ¦®¥öwüðoïù0ÍpKð5ÀÁXcv­´KŠ#t¯¿ˆí7_Æ/ÿ~æÂ5VHQqˆ¨¿±c¤¥êAÖ³ .®)®Æ~ÞÜKïœz\o?‚v/UúÃe V¯`ýÕÏ!õ³È r㠥ĺÞÂÞ¢Þ:j³GQëF0X½¼ÿé±ð+ 9k6åŠI1é÷€ç-èyÀ̤õMé|Oƒ`E8J'œ:9nÒ7iW*pÏÏ&娷¢-W7“Ž6}jÊ:­Rt¿Ny‡jðôÙóÒ'Œ @8´…íl†M'×tŸ“Ö¤lÓ0Ÿ”c“>úßý_côÔ_Dï÷ÿw´Îÿg´>ªÃ™K~kæSèœ|áöªf<×®#ìiuÍBià ü`'JïŽ@úuÄ&YIN :N™¹šâ°Ì¼ŽoÖÀq¯ Öô¹• ö T’b“‰²úRÉŽO|#h/¢uä@H V/"‘5à±¹Åy8ø™·²à5á¸fS;Q1àâÈgT©×Ü|9¤°Ìt€ˆsˆrUàC—oSßçJ)rÝå`¦³¥µ•bX(ß< \RÆ\Ñô÷ÃO1*macKÃ@æ7p°ŠË{òÈÓ–K5Š¿§…æšørk&F‰Úšà,d6P ¸i„S®#.*)eƒ÷pÒrÜf\1TöÞUöo¿O” Ú¢*)C[ÿ¥TP¨Ý€ïßNµïÔõè]ß‚è]ß‚Ñ_EïOÞŸÿ>jAÍ¥³™‹ˆH§9¿9¿=Ÿ±ÞYp9>”©3· ºPI ¿1;Ö4ÀH¢ZGÂæûøÞŸ£1u¼Ù@Ô–Vzˆ~ÑCÏH /=­—þ¼W> qý%6êsÇÑX8•9jf ¨¥Œ“Ï$û« €dZ¶Oë¤÷W.¡wóU–½1|à#À_úiàЩ;Ë% Ö‰uNóyÑÙg•@^}[þ¼×> yë<üZ³|ŒAÕ®:Ð"ì­é:¸qƒµkPõà?¼?­¶ª Ü6=ð û<1fq'ÿÆåF²6§hjí}¸»¶QìeQ)ÂsçZëaÌÏ#»¥*u‡È´çwÆÇnð |CT ·×€÷|„7ÏsªƒŸfªBÊp_0à/M1à‚ ’9l5ÅSi~(cÀÍÏÖ…á6½°ûqNä‘}¶¥åNZ®,5ÅÔS[¯÷+§˜©²Œ¸ ȹ°Ý6€Îa®8¬õmÌÞhùòg!žÿÄ Ÿ‚¸u~­ =¿5‡Z{A{~¯·¡}{¥§uœ…ÐáÃÓ—^½¯Ö¤Äö›/c{ù4N£>a÷6Ö/}Ýÿ¯ˆ{†f*]˜^“Ïl™´ @òç ÞøðÆsWÎA·àÕÛ𛳙¼ßœÝ‰ :öqMëF%’Qñ¨‡°·¨·Žp{áöšöm‹g'¾x÷÷;0–ûs)— hQÏH;Ø„¼ôÄ•/—Ÿƒ¸vrT &Tr¢ÔÅ)ì®îÔÁÂYà±ožø^àÑo‚š3Íe¸Ë0ߌ±öÐç~+/<«Û<Û9JYogá"•eÔé5°fÔÇð¿¿Âû¦û(0ß¡$s>U÷G¿ð÷Ð}þß"n# šíŽB½Æ`;ß“™Ô©Ž¶@H‰¨uøÛ犑6¬x9r¸hå’ xyþbxÂ9X $‹=J ¸†ã‚vWàÏ}Ëv  SQÁвœü•Ùz+q8‚Ú2@~?»¦p@Äó€hâÒW‹ç€›•ËP·.ËÀpõQžßÄü;þfxêsÇ‘$‘–”žv1¨µõ7°uõkðÔÈ”O¶n_ÂÖGþ1⣻Eíð*“ÖÐóÒnÞ„xó<Ä­×€Û—¡V/C¬½ Õ]Ú¾ º@8¢¡fö¼šÔõ0³¤ÿNGÓ~#0{ŒÎÇ^—Ë%m÷&Äó+¯k—¡Ö.Cl¼ µÖÁ° DSuà¥uÐYÚKÀüi`é1ý÷@Z”qDnwÜÜ1Åï¶yƒ›–sŸk<¸º¦¸Î½.@x/4gàà·7øa²î÷3à.[Š\€]$-ŶS@Þ\âUî"Œ8¥,ÀQ©ážÂ§&:F4²·sqrœAô% ‹Ì” såÊÒ¹2~ʾ0ú_üCùô¿AséA­CPq”éþj&¼…á†VºðêmÈ ®£a®^Aw°…­ŸøU$³‡ù€ª Àt±ÔseÒ͇¹¾åB²QÏrÛb¿‹¾ƒ‚EXô*îQ¤AQ@” '\üÄ‹jUr~/JØüÊïÈ €3å¸Ü³‚ÿ­à¦O<Î5øÎ´ZJ^~ò¾#,צŸ–ò©ï˜Î[žêË´:Êôõ2÷Pâ~€VDYóòd›Øò )î·îW6\À¬šÃMØ£šæ}Ϥ.€œwÚ"i Ø},Mzö€Y¡ÁvÏô>“l&î|OôÞïA÷}ßÁêUí‚’ú‡ÇÃmDýMÄ£‚μFGÐêà<õ¹ãh tþåÏCŒúær FÞ`©sS;À²øšú绂 Ply(›7ÁÌ›‹687­rÈ3§Ý\Ú³Ûjë×ýݪÊÅkU܃åží>,÷mƇé;‚1O¹Î.s4w~¯âûo÷Ÿ°à"ÎY å¸ èNk~' :mUp¿A¥5d“ÕŸ0Œe{‰ÁZN€?,×ÃB‘À6uÏ´mÀJå”MX€xBñ¢2.îG .ˆEƒš`¹“³²€“ñÌ ý2ï9Ê0IÍI¢¯IÃ= ³œ¡Ä2dL¼ù¾ïEÿÏ`°zI4‚ êAñ°‡°·‡¨Í†4n¯"õ!Ð8tíaßþE`¬,bZ¼¥ TÄŒ-\$mÞsÒÐW¸e‘¶hÞòú Òrë®l»™ÒK‹0=F¥Á@(Úß©÷‹œ¼sÆ!爻ÞWÄûa(—íÀêdYls§íÛªà]ˆ›æîƒ]‡6L³oød¦ð*óÜäâœätj×´0¤U9@\1ÓçÒdjp(K^ªóÞcºžƒÄ²{À¾=˜XŒay‡0䣺’êæHêUÞ~Þï`Ü´h€˜äó| û–üd»É‰YÂÕ¤5â0=Þòò„©û¦my9±8Šœ{`€IìÎÃê·ýúGÎ`¸~Ijî׺»« uÂ¥‡Ñæ-$á@3ᇎ£}ë2Úøš‘“¿¼¶wæëŽ2H˜³HÓ}Àm×òúS؆o¢@¹\ó† ëNÊÆm·évW9׬óÊ. ý]ðûû俨Ò2M¿¥eÇ@Âîö(aîÌI/A«6IÃÚKݘv ¨oW1¿ÛÖ e©›@Ná"obo˜ñjp3ÍqOÉq6V[YØoA|“ú®*™^LpX¬bÈÍ¡Âr]XlW.Ë ‡g„ÁÀÄØma0 îÁÓžYëy ‡;Áæ¥/ÊîÀ l ©‰¡“9“¢"îÁRÂ` Ù®V?ôS6;7oA%1d­ !}DÃ.†7 ƒ:êsÇ ’Ãe$ÑBzhÌŸÄÌ…çÐúÌoßYÒÐŽÏýCÚ f–›V2V Nþøî)Û$‹–ß%­moÞ’Êíï&Û4¦lc´*÷TtßT~e0$lùçνÔ.&—/:¿¸¨TÊUö§À*,ª‰á4¹~M X4‚Hoלƒ3T¾LÏÛ\JLÛ*Ô=Áèt‚aýs@³ÉÿÛÔGŠº™¼µÝTŠN°®é…eŽ ™ÉÇ]X¬w_q&`IšÜþ«ÿ*B¸½ (¥üˆG= ×—á·æÐ˜?‰xÔOAøµÙ%Ì~þ÷Ñxá“ù ÊvÍB9éaYø]Ò Çoæóœo˜ž³é}SõGå͵\®ß­:½Íÿ› ÞV  bLÁqšò% s²ï,ãßF$¸Î_\ƒ„±Íq‘áºr˜qªÞ~æ:TL³/8ňƒÊ¦û¶-r›_7Å4SÀÖÆtÛÀ"ç©b€aÀšè\ÿraéTœN§ õF(pmRL±.í[åàfQD0faé«F fŠãœ{_R`‰Áê_ùi„Ã.¢þ&„ôà×;Pqˆh°‰ÁÚ5Ôf¢1QÃõ7¡¢Ò«!è,`îã¿ÚåíªI® ©ô&–L–¹*k¡TÙLé9,´K¹8@]™º€`Á˜ã¸l6ö Ãa¼©’ ]8îaoSûÙ”a\€¸ ‰!’3¿»²ÙÜú?šÈ«êÕ¥eÏE:ŠG®¯ˆÌ`ZáÔ7Š|à‡«¯RSœ’%t kÏ‘+,"UH…»7•­¬”áApŸròXEƒûØŒè¼~“2tÑ憵ȤÖùç°ð±ß@Ð^„¬5ŒúmÝÂöò+Ø~ó<âQI4Dcþÿ ‚¶Ž¢˜DCŒâ·?ü÷-œàËÔÙê–#O˜w½jq—k®Á‚PòWÞñnêŒm7ª/Àñ½@99D8¼('eX6pˆûUK‚1‡¹Î(0o¹¬.ß?øÝI@ž½×2„Ê’9›¿­b°àÛí*eX$-,¬m’Qà…õøR†ÊáÝ”/8Àóç¸qPL6× „Rbƒ=;Kî…k P~{•raÁÀQ¬%Gæ°„ìZï߀Íoú>„Û«HF/€WïÀoÎB Iƒ³Dý bZ)@È š`áw²·áÎV*ð$ñLl²b°Â‚HK1­œopóG±ØƒnË –¿ê´.õâÊžsIŽD¢Ëu»íâbÂÙíâîxQÊ0œgLíd“Ò­J–bÄ˺¦ø‰—[kï9þÕ©PôU°ÝTA9×\Ùoî7Ц¥Ò»÷)Ê £ ãÌMÇM[„¿Q69õz¿³âw3Ê&,†–+¼Ç•ç°ìéõ…gÿÚç¿¿9—ÝT©ä RI†Zÿ·˜Èd 1˜?†•ø¡Æ!Ù‹°¨òÃÆÖrÉ“{ȇ›·2×Ê”«H½ÉsÑv£¾Ïy/眱S$Ê&òƒ³ÛeÃ.÷˲æEXf—ÈÂpHWE”ÍF<ÿ—ìWl!õuXÓjÁ迪Àsyå/“%ÛÓîÔ|ÊQÞ€åÛÊaN¡æÅœS\ï)Ã\¤ˆ¹ŠQ ”a\Ê&˜$†­î«šß«~ÏÁ¯bNMäEA,§S—ñ¢À7úc°Q *ù¦&=0&b@æ€j0¾ë¢qJ;Î36Pd3]€¸ `ÜÏŒxU¬rXÜ(àfž¨6ÌûTÿàÔgÑå“22ª\£ Œ|¹¦Ýk¯ÀÛ1ã>Ø%©ÝÖ¢#]¦Ý¸FµÃÊÜþ®ˆ|»Î¥.Æ2EÖ¹/*š¿\æ^—¹SìÁü.J´ÉÁo8,W‘çl“‰bvtŽ"icpróØ•Nƒõáh,S 25 ¸6èrv.¨û6·F°k½»N4Ü2½€¸Ëëšž‘5j¢väqRq)Ãì,e‡Q. èlÛîˆåª%Qˆo(‡:à¤åº3*FÛQíæêÎIkÊáû{ й ´ˆ±\¨swÒTEó—ËsEæjn D ìtÆ÷€»–Ê›ÈDpîâ³e›<•C, â9ùs­ö}/:ˆ ™ãªaÒxŒô.ÌŠ+(ã,®.®-ûˆ`«Þ^尳شuªLÜCe™½¢ÝäqU„ŠQ.˜,â2XìròWU¹(C†š¯]ëpÒ.bpèUwnŸs5–©¹ÉäÒ&àæÒÆõ‹çqŠÄà–;¿»°Ù|’âà·œãMQÁì ®@™k©º‚x€ì²mÄÒ. º/ Ð]*Å(Ƚ\–ºŒŸ÷[ˆ—`÷j{•c¸ø»,>Eî•=ãà XŠÄ2†qY$mð@<—a/ÊÄ»lU2mÑv£ê•ë–ä:çSiY«Û"už…ëfV¤\.$ˆb– Œ¶à®YÔÚpÀˆïŸþ%àEL°[·T9t.•ó.*:åtÞL–m^ÞLåãyùSDÚ"e³=Ë]l€11L< ì‡Z„#H7 jJîшÛòÎio7 n›`%v4î«â6ÃS†›é¹ég&5‡Me2õá<½bÛ½¼ë`›ÓõjÛa2å)olååÅ–?J~ÕÔ.TZ›NüdÙ³4©é‰¥l¦´Ò¡®’ŠÊeJ[46,+è7‰¡ŸNŒæöwAÌ#yï§Æš­?rHB®‘MÝçÌy@ÕTwÔTÙ¸9”Y¥æ"Ũ³OssˆËYÉ|Φ‚Re¹8» @Çm7—üí7E\-(W[/:¦8ã Žã¤rÈì¥ ,õÞ)Ã}€s,#Ž\YoZP¹ )@ÆHàð “jÇðpÑç.õ <Q+)#eÈe2¸R†œh_\V—÷9/£ â¬Þa#jNᜭhí`—òV!»æ2†¸:á ŒIyCJ}¥ˆu•7tñ÷R"\Óîe»q™NjM¨ª¿sÖœ²s’«BJ‘û®R†>ªZönI¾Mxµ2„.ZÙ”£>W…‚¢6=Wê=E´ÂQ¡À©¸æÊrµÀ¹:à¶$áz“–ã/î꿽WR†o5MqîÂæzøÊˆS‹zÞyÛ7ïÛæ¢Î9 ÍyŸ«^õݱ®o8@’šã‹È'VQþ*Ó–m7Nzn ìqÜ…òÆ·Ë=Nð0ç'Ž:€í2÷re`EEóûßœR(qÑÊæ²Þmä¥@¼«|b•åâj”W‘žÜ¡J8‚`À=Ê&7*'ßÓ ­Š(›o¥SãEµž‹LÐUFÙ„C‡Ãý*£lRL#ÇÀq}‡‹^4Õ(ÐÁ£ª‚oÀœsž³õƒªå]ÇTÑvÛ+yÃ*¥ ˨¤ìu”Mî}C}¯£lªŠû⯘ç€I0@,Àó½sõw»{!ŸÈõ)ää":ã¸ÜØ÷"A|ŠDÙä€tn:ÓâÉY”]Xîƒ(›nŒUQ)Ã½Ž²É þᄊ/)Xʺ½H_DʰŒ„¢`Î.R{%ŸXfGm¯Ú Ìr»Jkî•Ö8È£ïêšFÍ_exQ×”²ó;µ–rêým Àm*Et¼9Q™ƒ1EÀ¹+ˆwÉe4Ðá0pDoS†JÕØ›(›UI* 8ˆ²¹w콊²Ilr‰¤iúV~«œùŽ»Ø— TˆrÀdËe‹‚øª5Ð]˵:ãÜC—›q±×Ýuax¹Æ4ä]¢l)³mî<ˆ²¹Ï8, •‹2H•iÇÏIËs¶…UM¥-¢3¾èyåÏËŸKÙ(yÂ<Ýo™s«¸ù‚#ç]&Á<@d«[=™ÒÛò' "ˆzqaÅmõ}¿ñé¶§´ƒ)f‰Ò4¦´¾¹ Gß¶L$ÍÉü%p“ç²”7³ö0GúÐöÓ÷vˤÅtÊmß)£QnÊÔo’çé IDAT|R¶lEó6¶ qn?1É9*Ð:á€Y²U8ôS—–|”ÑÜx:ä6,¡ˆº£ÆÓô}jþ¢Œû¤"ƒ3×Rç¿\´À]ôÏßÖ ¸ Ðqu¼÷*­`0ö ŠésSÏ©åR–Á)¿KÙLbþ¦IÇdh˜Ø›ë€MƒD9Á¨jKkcÇó–„É6p‚D‚¥Rp?´´ŸÁ¸Mÿ–£FÃÑ™ãyÓá^›ÈÑ·¸È»—§¿k‰”þ±­^MÍR¹e§4¶)r`®ŒFy^þLieN™%³nd‰¼ÙÊ%ö ­K»Ûê…ÃÎÚô°‹¼Œþnz¿­¼ykv‘XÜ1ëJdIð\&¸šâ6ÝrW708|ÿmÁ€—• ÜË´¶Ã0püf‘çîf´¼#çÅþÙÊhÛª4 ÀqÕ§XEÈâJ Ð[pTþ¤ yÌ85–]ÊÍew\Ãfƒ0‚аßwCÊ–opænýsÜU€âî yß)s0± …ê9 œ|b‘:q©cnÙ\ÔOÊèÖ‹ý½¨æ¾)ïEÇ!æL½k,jnâÞ+#{  ²ÇÓðõ®¹`²ˆ5uê2 žcÉUU.—ºÊëŒsŒŽž2Xß-• ˆS¾à\€íòœ+(£@+WÂó~ãUIrƒÆØ|þ9‹}Ym`î½*d׊t××6n«“.… ¼ƒßE}®Mý®L¹¸€«äÒn(¤7¹In?å¬'E R—y‡+X•‚ 5W‰à²f¸ÊÀÚvtßæšâ{ˆ§H¦9›kÄØ"å²}ƒ{"¿ª´®`ÑV¯Ü‰“b$8ÌRU {Äâìe–1B^áÈ/ÞO?–š³øÛ²*¥ mÒ¥UFÙtaüLc¿(ð±¤Eå ]ôª©ùÁ•Åv¬\o3<8Ò§Uk sæ(åÐïÊ茻ôîx®Â ½×Q6à—‰eÀ1¶]ÁíA”Í{Ì€sYP.HÇ5XŽbvNŽÕïªmÎ}® ­pnZ”(g»ÑÆf»0Üw;Ê&hß(›.ŒÎ[Ñ5óÃeÄ÷b{•c‰²™Ç™ò_¥ìšKÞ”ÜKyCnPÛ¸uù†kÙàй ~¯ê®*YI—ô–Ûå%“hÓÿ¶aÛ ‚Ų-ü&ÆG0\ÞÁ-[@ ¾ä›8ƒcèSh\Óst¼ÁL †ñdʳ€Ý-b|9ò©œ´eÊUV{Á‚ä‚¡OÚtãá0¾$ÜÔ‚l†¾`Q.‘8%ƒÝ¶aÁ ÓÀØLö^0æNÀÍõÎÕ³Vp" î{ ·9J.n.Ïí¥7G¥lèäª5Ð9õð$ËÊrú‹y‰C®o˜Ç–Œ¼Åüq\g¨‰è­Ä~(zŠ1áôXU޼¨­çæœ2¹ÎtwEt¹lW¤ˆÞt—% ¸»ÀóA1–¹n3wSg¼hÚ"íæÒ&e}ªÖÜø~ä`x¾{ u¿ˆ”!…µ¸$ˆb–bµ‹(Ÿ(¢Þ÷ˆWˆ‡z€raÊ€dÀ•(,"ÈyÅU>‘s0Â5Çï“ ¢AÔY™ >eUR¸Úè¶´E58Á}\Õ+Þê@œ3Á ‡ô6ö§È!"[2‹**¸Çë9¹2ò†¶º-°÷ˆr}[M ’S“¢˜årÑ/“Ò¼ƒˆ®<]ßQ<—‘8ä|¿ŒNÝç¾Ã`SÆKÙ˜®LRtñ½“!, rQ!Hv÷E$(›‚2”‘O,*ïè:\ÒrR©ý†šPË0è\PÏé@µQ6]ŒŽƒ(›îì^EÙä,¾UDÙ,ÊŒ¡DþÀœC\º«”!èæI¡HZA¬U”ªt¼9uZ´N\óÇM[V_Þ…å®:Ê&À—8¬¤»€mÛ}*–§?¸Îs÷S”Í}À•pR`ˆ;Q»¦w¢(09Ïqógëä(ιÏÝ-ñ¢ÆM‘v/ й„KŸ*£lR ÎÝ’2<ˆ²éä)‰B×(›.R†®‹õ~‹²é )2 ˜¤€²KÚ"%¹ ž¸¦ŠrU­3Ž *è7.A¼î… JCÚæŸ]f'®ž»Ë¸2°®zñêð*¯  ÈãúhSÖGö®HEAp^ÆÈØ tNÝ•‘•,Úîeº­­]Á»+HçÜç,®œ‰ƒsø´H”MnúýΊ²ÉeªŒ² &3å2~/¢lÚ˜kªN9¨VÞk »ÜüU%½¸—è÷ºÝÊâJãºôww/Nžîu”MnÄoîÜT… ìÝâ÷œw ›ÀÍ·HzÛàá.VÊ’v¯‚å$ƒÝµ\eóÆ©c—vã0 eú Õ¦yª-EýÊ9 Ýt¯ª(›®,uUQ6ÅÞLL÷äWf¢æâ¹Q6m‡¶&e·òT lòžeA:X$s=á¨ÃPà8oÜJƒñËc6¶¯(8§TU¸ÛeÞº›|¸íT´ÝŠôª´À]ú;g.¾›Q69÷÷2ʦ´Ì./ø¾aÀmr76ï":á“ߣäŒ\Òsµ²aRiMÀˆÒÈV9ïh‰»»¥Ž Ú’£ÎPZàyù2i˜s5Èžî.eÈ Æ}ªln‡OLrœ.¡º§Çûùàf­Xk(-c3ψáÊšqÆ@ž$¨IçÛ6î`˜k@PWpÛ¸pÑÏ+»é¼…-nG¯Ú¤»nÓ(·¥5¸œüÙ4À«Ì[ tNZÛ:^¤Ý¸íN€6Müªú;/½+Æe ¢ÞËhŠSXD0æ!`c»©oW¥¾oaš:¤MÙÄRç-ðÓr°è©ôEµ²•C¾9»6mNÙ¸úë{¥Ž Ûóm€§ÀbX&=oÓu—Ù6Wê'-˜“ «ÊÑ)§@9ǵæ~îÃÝ-hߢì‡Í±i&籇.»#ëG-º‚‘GW99iaѸzÑ”ö¸)½‹Î8ˆop€ ‡§‚´qXhiØm)’7ÀM?Ë’ÛÚÍ¥Ýñ}³FxQM|Ž¹ÉŒqðc”Õ§ 0Ʋis•uqË*:¿ï Nk I:áÜôÔ!Ì"ZÙUèq»–ÍU‹û^k »|×Ö–Ôv«ò«ò ,ˆ¿ß¥ QðTžßJÁ}\}©¶°E“3õm(å€eÓî 2µîºm.æ(›ñꪔ“4QW9=®b 5ïÙžs‰ê'**Às9QåÊKCmw·ƒ½”޶‹ñ쾨± sa᪯(Æ3 ÊÌÿUÈÀræ÷ŠÙïêð*‚£pÀW¯ÚÔá‹{ÈÇE¢ÐfñÝ-杖—•,#oH[àräÀ¤¶¹Lé(€oSÁŒïp¢l‚ÙÿªòûˆsXꪣlº‚[hàä[1çh޼§‹rŒ¼kÌ‚"–›ØTÿá2tŠX38 ž£ÅÍe]@2çeuƹ ØEÞÐeÊfÀ·Õý¾tAÉ,Èaè8ZÙ)C€¯‡ÍÑ«vIoI”¦ö4‹eXÓ“Kž^¨-Ï&=íÉçlòW®úé¶vÍëUéŒÃbìØ|ÏLƒÑ¤…m«[8ö÷¼ëÔaeeXHmZä­r.ë äëùs QX@ õÆÄºßYq®~7Åô™|&9 ‰ ØæJWpÓ$9ýÙ´'̱bºNi/'àéOçѦÿÍ‘ åh€SÁHLÒ³eÊ·lUj ÛŒIªî\ÒÚ®•m7ê|Xš‚͹ôwÛX•àß2aÊ-Ѷ†»ÜçHR®>E4ŃfùË{Àøa½MM{ÙEN.oBKà®mK¯ˆ:¨R+[øFà¶oRy³í&Púé®u' –M8´;%ÝGm]šv|L“@bÙeHL1¥-M-”K ÷0WU̸ CüvcÆ9šâ”úˆÅ®ˆ‹ ‹ .ªÌÜÿÎ+¥]V¯š¿UêŒSúèk.åå…{©Ç"í¦c‡›ÞdHvyö¢¿cªÏ»¦É+\…ÛÙjg à»Öº¸ÁQ».2°û‚w‘äH¾q|÷\t¾þ!Á":ãÀ.«3N>À-ü¸í¹2¾Ú\y@Ü¥º£Ú›Þ¤¸¾©œþnÄ‚èëÔ=ê>'O`€oCâêfòvñwÑ'."¯Å=$j3¨ƒÎÜZHÐX¾€Î寠qãUÔW.#èÞ‚×[ƒ qˆDúˆý:Ôy „­CçŽ"œ9‚hæF §1<òÂùS€'‹iÛú™‹¼a’ qóÚW¾ŒÚÍ ¨ß¾oë&üÞ0@Ä#(/@Ô¡jM$^QkñìQD³GÍÅhþ4†Kc4w ²qN`#Ž;¡í¹2à®ò‰EÊO¥x‘–9ZÞ@9¥Û”ÛÖS.»\T&Ä)íBB¸žG¡°õí²ËÁ‘ϨR¯¹ù#ÀöP@²èuQÁ»¹×Ф§Œù6õ 0òRæò†i÷¢îªn÷ªû5ÅLS‹ç'-GGœ£§Ê‘æãi—Ã1÷ÓÏ6¡QP¡upÁøpd8 À­yã¿ô»˜ñ?¢Ö_‡”BãÕ'Ibĉ¥”Þl? €D%ú^ú{5DÇÅðè£è=ðnôO¿Ã¥G)Ýc>p¸‰kÍ[°ø•ßÅÌ  ¿·)Ò¼*éyFÐÿÜqªB@ýÏóvýB@ùu Ä`élŸxzÇßÁÒC; Ü0-ZáïýÕ÷!Š"}yj¹ßɃ¦`uv t¾”PPš¬ÿ$Iø Cë½ñŸ”ëkkxãç.ä–ëé?øqÔo¿‚8в<ŒË4Y¶ñoC\ü‰ÏB5æœÛ˜u-½î…[x÷¿ûnÄÞ5?ã_†ØhŸÁò‡ÿ_?›2‹^§˜{E÷Ü{p˜«(×”2ó—`´3ø+§—K-<Õ3à\ƪ )ž2l%÷Üô.òˆœoÕãæ°œ‰›”Ô;aaØ]ë„sJº¨,eYyÃ2}¯l¿_¢lÚ¤ ¹@ú Ê&?½Ëö*”ruÎs¨Æê%œùį`îÕÏf×#¥ÅñN–„€J %ÓÏ)Î3ž?`Æ}WΡvõk˜ýòïÁ÷=Äõ¬~7~âÿq25 4W/á?ý̾ñY¨$AEˆT‚0Šwò†)èvðµ€€€€.Z Ò  €QåѺù_üCm˜Ô;X™{×äÿæKùMýwEŸýRÈ]X@à •c.´)eÖy€sldŒ¿; DÇy˜ü~kCduuÕX®g¿'o¼€$Ùùæ8“ùÿ…ým/ü{ŒÞû£öº+"¡8Ñçç/ý d"Lv‰J麊¢h×µ l<õSùó˜kp*8€Õ½VI)eàÉr£lrv‹ÊÀî pjÃöß.`¢*99®lœ Àç2@WeZŽÔOÊÐUN²L¹8./e4Ê]ÛêOe4‹qùC[: —²iâœ1u eÈ[ØŠn¯rA¼K”Íô¿O>÷¯qòOþ d’ Q@ER@J ßóàf=•ÙI¢ T’²â *I2<ŽcDqŒ8Š D’ÀI†!Ð |ãà'‰Ý‚€åäŸÿÎ|ö×!â#¥M°°^à£&5«= ´&?,¥îüc0ž$ºÌBhà)@—?Ibr{£×þøQFû[æCHOÊìßÒÓùq%T ¡ ÀÙn”¤ÒLx’@)‘Oj‡?d s‡íÞ ¸ÇÚ2ÄxWD˵úðwâÔ žˆRcL¿Sr…8޳6€ <ÿÿbôõ?ÊØ\ ˉkG®<›õíif~|ÿ=…ŸþAÚ¸æE:…ݪ¥ÒQ žÃ| DÝãÌ÷€»ZYeƒšpÁ˜«^4äVÁ˜ºèxsÒrÁ#·Ó»”­J ô¢ÆMYñ²úðœz­*ˆå#ðUlj6VÆ5ʦ‹”!7lvÞýƒ(›æ…ùnFÙTŒÇ?þ±tîRv8Ш×Ô|Héip$P‰mIúï8Ž5¨V*ydIxR¢Öj“â$A8a4!Šcíú‘Ü(Šª²™ÄxâSÿÇ^ùBÃPß   Å’x7¬… HYŸâü­V À`4Âh8Ä`0Ðíã¨Õj¨]þþ•_çÀå/Ó B‚ ÄuÜŒ‡mYA ²ÍõZƒmj;5ê¬ìð˜1ضmÛ8Žƒëyd=×ó@@àxž‡¿½Màû8®w/£ªíænz× Mæ§^øß9tãÏi†aüÛÁÎf€ßòi¶šøÍµzZ­¯f“–ïÁ= )±¬t»®K&“!›Í’Íf;Ìi&“a«Ú¢é7ñ\) ×9è® "c~¯N%Ò²V«í‡/‘–@"  ÆÙeÂÛ´u´Ëè†a\uaì*»»a{'BÆ~ïDìòæ¢í‡R´¿±›µöÿ«Õ*Fƒ|¾ðf¼K¹–O~‚ÊÜ‹Ž'-‰%m²–$ð}¾ïS©TRÍdØ~åwh~ðï ^g8p÷Ïpl ¿%:mKMÙ¢ÕÚ¡Z­âyù|ž0 ÙÙÙ¡õ¶ÏèYn™0«4ñuQe{ÕÜOË^§%VLý³U÷D”M>ûCÀA¯ý›´ê´À¥ba%0 yÒéÛ$ËR’dÚtùíGÇ;éZ€Ù_F™`=šh£G† vè¦åLÛ­lôÐoÀLû>éôwÕXS雌QHÖ0W¥×å/©0˜ti“Ò¿IšŒP™*W“ýZØ|Kã¦2yñ8téK4‚ ”Y×qc·b·™ÙÖV×BËåÈò cÛ6RÞoå†m—”0hµZ4šM6WV¨íìø>^&ƒ˲ð2™û ¬š¿táí½ú'»þUša 6³Ù¶% Ã? Ÿ……yÖ×7Èd2är9Ür)Û`· 4eÇ!dÂüÞM†ÖDû^e\öª­¯#…T:ä*¬¢’¹ÕÅ*;¡:7í%ž&l¶ÉÖ¸‰FxÒ‚‘´«:šw'5~H:ÿq]äÍHQoiØ_Õ7DiÓ0Ó|ÃTÝ´\QŸiueß69…*ú{/R†º>oªCnPÅä>èmLtÝ<`Ê"‡˜É‹}¿0ã¦Û®:שÙI¡¡ëm¯rú›ÿ"öçB²Ù,Žç"…„(bem•+¯]Á÷}ÆÆÆöí=‡+ã÷…aHÛ›)d|è϶‘–Äu]ò¹< Ç~Ç­f‹Ú~«uamûw-‹ªïî+«W[ãÉs¿B„qyvóø>këk\½zß÷¦R®`Y2v;鈷Üc“ï;ð(¶eáyÅb±<›Í&ÛÛÛ4[­ŽŸû}*"&;‘ûTË’Xa솆qÝ7uíËW7@Þh6;Lý.£Emwkk«lll†!¶ãtÚaÿÄ$ð½kxpŸ2L÷òF®ÇÚ±sàg±¤v¬Ö¶]c†ŠEVWW©Õꔆ†ð2™»W©Í_&¬7ýô„¹½°u“Jý(DZ®ëÒjùH!ØØXÇ÷},Ë¢Üfã«Õ*­Çÿ*85–êFétëQÌ &:àЛO4š±Öï½½uÒË}óYšhÁ&;…ßsn*5ý):˜–é ƒ™« ЙJÚ½U:ã¦ßM£õP¶Ah ÷’VWwôÙn¦²Jitë{éïýø—›Þ3e tï0u¯¤?ͯ+S­Þïg ®sÝÑi„«XÀ}ýuú•/àøuêA€ãØx™L‡A½uëׯ_GJÉÄÄc €ÍÍM–——ØÜŒÝ‚à­´ße#›Í’Ïç;@PFÇs)¹Î¾Ã~ÂüPš¢þN_üC²Q‹mßo3Ò™Ž¿úÞò8p€áá dkk›ÕÕÕD7›o*”Çqð™0Ùàx¯~”àí%€X‰dá[gŸÅûÎ${÷ÅB\.×a™µ[ÇÐ0>wžLÔ¢éÇŒ¯ëy¾!wïÞ%Š"ÆÆÆ8pàõz×^{ ÿðãð?ü˜z²û‚mí)Ï¡G žºWžúâ ¶Î=ËÊ+Dîî«”K% ùÒ’÷¸‰ø@—v[[[caa : $Øã«½ßg{÷7>>Îää$•JÇqÈær@ÄFÛç}×ÍÄó<†‡‡ £ˆ .ÜÇü¿©›µA}ÇÕŲ°ÚífII³­¢>Ë X<ñ1޾úXVl„á=}òr¹Ìüü<;;; g†ã‡Úmj7^ 8þ>ãºK$ Œ¬¿F)ܤñNë´rVW×hµZxžG©T`}}Þ÷wî7LpR¯,t¿á&]5?$í¦¥UA1QHIz¯ê~Òz’VÊð¡cÀM6Ó{ßK‰Ã~¯˜¾—ïíG§|P2ˆiB˧¡½Ê ~/ÊÕ‹Îxš™AëÖ§ywZÖÛ4ˆ‰›‡Îxîë1›(¨D˜«µ|?‚ñ^¥ ü¾w¯UîœÇ¶m|ßïø[RR¯×h6›8®ËÈèRJnÞ¼IkäüOÏA¶øæÑ€½ §ù#Ÿ£ùÉϱ½>ÏÖ ¿Cé¿A¡¾Ëî¥ÕEÞWO—/c[6-Ñ “É ضÅÖv\×uÁ²,îܹƒ?2ÿãs)öôíðÀq?ü9û[óTÏþ.åoÿ&¥` iI5Ò0‹¯ü×ßQ Wø:Ï'þÏu€­-elKX²£ÁÝŽ™ÿ;е¸ù—~"ŒØw~Mu€^a@/ÿÇ/ÿVÛ…Å&Šü¶ñ%(•J¬¬¬°³³ÃÈȶmS.—Ù<÷ïN¼OOôýÜxtùy<×¥Q¯ãy.¶e!ììÔØÜÜ Š" ÅŽã°³³ïŽüÀϤg„Mw=tì·i@×á´ $`æ*éÃÝëÖi“ˆ¹=þäÀx7…Õ=axO¥ú)¬Õu ž4Ïë”>"ƒï%Õ!åÓѨKýöšVµÛÑ­ “Êfúœ(›äMU.R>§k·¤vW]Ó.ª6IÓßA¯)Æ[Òu]:U¾“îë$óTeM:j2aŠ”ßú~ûío7 Ë”dìt©«òÚÍûœq½Ž2I£ÑÀ±mr¹6&T߈º|³‹DXgû#¿ÄÌßÿ·?ýOðéÊ„¢“°»fòܾ>1::Òf™%Ò²Ûÿ¶ÚÊV;²ç›ÝY’Ê—˜o“š=×kÅÃTG#Š",³ç–eáØŽãÏçñ}ŸV«…2vï¹øïÁoªëDwh\€ˆ|Ž­½ÔÖŸ—ä²9¤X–Íúú=÷“áJ!kkkDGß c'ûk7]¾u"|¸Z¥’¤,¢êï&s‡Hø~¤¸ž6]Ò™–¤2GÏ è7Þ l‡Š  l¨¸a‚ejt’1Ð °„]ÀQ˜PuÓõ ]¤º¡!HNÒ 7MK—k&@¶Û7BC‚ópy#EÞ’ê$ñ¦^¢„¾·5ÆP€&LÔ¦ãP—MZ“²a8æÑ&‡juÆÅ÷#šÅEeœ¢Y¬Ûé [Kb*--å›5ÛFˆvP˜·}$Ù8¨õ}“UÛfû̱üßüûd£P’ vBDqg5–lƒº]fU‰±ö´ã8ˆ]÷§>’ XöÖc7íå¤ ,M½ô’7]ZÕs½äOu ¦—ôª-Æ4ý½Û˜J‡i\Åt÷0¼‹­›'P05ªÝ&SfþÓpQA±+aȌۡODì'‰øb„{ ,3“™LVg̶²¥†¥êÌö©øNBZWÄjŽãtŒ‡0 ±m;–ÌÛshÐ󇆆:,))—Êd¯ý¢^MŽš(yàuNÕ¯´w,òÙV»>–—–©ÕjضGâ‚ååexòÇ _Nþ†i»E]v<öG¡NÚ±BÓoHñÕNZÒ<’ôþH1†å¾’Æ…%é>¨]yß2®ÛöMëó é}ÅAíóJJžäº¢{¿ šÊ¿™*¡¿&@´×´I¬“ÊGÍöÍ |ÉuyK[.R¦ ÓFšò'¥Wâ6íクj©ÎSèÆ¨P¤Óù]'¥P»$¨Ú«7“~]\vfÜć²KÚÐÍ"d종qÄCˆ°l«ãÂัoîôô4îó¿kæZ¢ iTÝB¾{ßÍc·ðX‹;v¯pœ¸ »n¶msôèî·G׈ô]åó›tÝÄ¥C÷Þ}}bx»ŽƒëÝâ¶mã8v|°²-¿'dÂQ€”?‘Ð~íÿÏýHg§Âv쎱ç8###!ØÜØÄ²c7”RÖžð‡‰;1oí¶:µý*國ïû¸®‹—ñpÚ———iµZäóyòùß›\tR|ª4"i37ù¬vŸó<¯ÍÎ;<êõ:Žã0<–3ò޳´´ÄÆÆccc8ŽÃØÈ0ë¯ü>|6•øÓõ×*æYX\ŒƒûxZRR«7:ÁŽFFFÈçslnVÙÜÜ„wÿL:q“5L¤HKÊvR~?M?í·¿?è(›ª:Ï€ÛŸ¬u bÚûi"iª¾ ˜×ýûAô4@\MA)È3»ýQ“‰XÑä·WßoÞÒ°øº>ß ¸6 d ÐÓ·ýËŽaU ž¿ˆ²9x ž÷ùƒóäÕ/!„ ãØÔju +î:.®[¡^¯áû>¾ï“Ëæð2™{‘k«ŒÎ<Ï»—ÎPu†˜šd~èsCS, MÒ²2fáµM@‡fÌÞ.Mó®Ù¯O¶šÍޤ¢mY W†©nUi6[!𼘎ˆý¡sÕy©™'ï~ ‰ Qaqè‹Å£,”ޱ8täÍå$`37ƒ|×}(\×ë" á½Mô]÷-À4“: ¸çÙÕ¡ãT‹S mÝÝbñnŒ„Åb‘Z­»©¸.GŽLqçÜïÞà&ýBÀ»Ä븮‡mÙäŠ9lÇÁ²-ffgY[[ò,ÆÇDZ,;f¿'‡©3úò§ç‘Y»×½IðÃ~ »¨G€Ž†ˆÔEÙóHš:#ð¹&}·0å{ jñP³˜ªÆ4‹¦Éd&,ü¦×uleÒóQŠo&éU']SÝýßêÆJ‹}o§Iiv;’êM½ E½Dмéê/)¦ßèµÝLú“®ß¨&ó½§Ð£Æn¬uk÷nãm>»Å@1V“@¿ì›ÎG&ì±n~ù~úu1læ€èºq$C""^ÆCZ’­­­ÎaÄ(Œâ -BƯ±,$!™íN4«<ºñbF ÉrþwËÓÜ,æöÐ BËî™O77šñ$—qÏóöp· ÀãCQu@·mÛ÷âÙýIÃoKîWž)) ·½ŸwÞø};>$»k0…QÄÁƒ¹qý[[[µÿ^7ð½7IçP‡…4¬“ ÙOÅ}÷MӪŽÐÍrŠÖ_d/•m·< 8Oª(ŒðéÆ"v«÷P’# p6a/# nR6]½è€sR¿ Œ„´u§Ê_Ôg»©úM·÷šôwa0ÖTßE³;¤‹*f]Wgµ› ¨·iUóQš´`:úû¶ÃÅÓ?Ì;ÎýÛ8f&K„¬¯¯SÛÙaìÀÆÆÆð<0 Éçód2™Nˆsß÷ |¿üf·.""d>·æߞ登ߠ&]®xŠW¿‡ùÒ±äK“ó<]€J`9|gòyïÕ/àz.¹\Žf³Éòò2Õj•‘‘*• år™VË'“ñ°‰ ŒÂ¸ÆksL¶–xßò‹Ô,—+¥Çùîg˜-L©£ÂêÒ~&ëMR$À=Ào—ßUýˆ¢Ûv2$jûí=Ù8&ßýs–L˜jgàÚwóž™ÿˆ”àX¾ïÇ`ܶ94qˆ™™VWW™œœDJÉÔÔ‹/ÿÁÇÿ:²nû÷nû:Ål‘õõur¹</CËj±¹¹Éììa266F&“aaaZ ÞýSjàkâ¶gš6"YS;)°U¤éc*Ì–ÎÑ€v¡`§uîÉ*â'ÉÝT*vŽ¥fÝšû7a™uÌS¿÷ÁÌu¤Û½P±bæóª“ìÖ“Þoâ.¢Zp’ŽJ[%ƒ¥Úv‰R¤Õ±¿¦'öMó—T6‹:Ô0M¤(«IÝ™äoPí¦Ú2 Q»kèú©ÎÕ#Í8½‹I Å¨§Í_šù ÌýÅUm÷}Æ_;ùƒœ|ý+ˆíe†ŠC †!ÍF“×_……ŽLM1~ð`ìÊaÛ±šˆeÅúÑ"¯Dà>Zƒ ôl+>T!aÔkœ¾õ<Ü~Åá|kúãÜyD'A(˜ñ.óÓùÃïå±Û_ƒíŠCÅø i³ÉÎÎ×®]#ŸÏsøÐ!†ÛRwÎî!Ô½!Ûà Õò‚޶ø®>º@ üO-¿ÌÛÖ¾Ëì!¾~è#Ü*Ÿ23ÎT¬¿$ÙMçGܾ·Ql€F!ax/ÏÞ™]çS?Ý$öW³#¸íVX~ŒC¯µ†84¼”1•r…Íêa’Éd8qâ—¿õ‡Ôø¿!´n.pïÄ7m›R¹„%m,ÛââÅ‹¬­­áº.“““XÒâÎ;ðȇ¡rXÏjëdÓ´hæµ”ížø¬‰¯tRŸ•ŠyÏäF)¿kâG.5銕ÿù_ýÕ~^°ýz–P/ÂÝ€tR ’}vtÛRÂàÛ½ÜKú¨Ãf ôõb˜…Á;¢ƒ(MÞL&ý´i{Í£.­iÙ„¡ÒKÞĪ»4yFÁ4‰ýÆÄ°Óå¨ñ›¤b‘”…¡«QRP²@ººUµ-†}˜óÈCú ¥ÍüG™¼úçØ„är9 ù<ÅbÛ¶Y[[ãîÝ»ÌÍÍÝsEqcÅ ÏóÚQcÆÒqlCX™TÖÍI¹Êß(ߦZ­â·ZŒŽbíó¯þùŸsëÖ-Êå2<ò~àsöìY‚ÿ L>m®ž´ÃßkZÓvOÓo’\+uó©î{*ð¤¾a*q¨{—î;ªþYØêk‚î€_ A 3‹*í€JóU§Qø4Þ”}W]4@O¤M ‹¨Ïk<¤i霧ñ:CêAÕ )Ú½cÏdÒíÕ „!† Çy‚„É^¥±¬‹vù¯ž-±VždèÕ¯` Èf³x™ •J…ÑÑQÇa³ºÉââ"7oÞäëopçÎÖ×× £°˜lÛ‰åv¸siÅÌ£e[DaDàˆ6ùëú[¹ÍÑ[ßbæÀc4²CúÝ!”¡€zfˆåÂ!†.þ¶ˆÈf=\×£\.S©ÄÒ‹Õj•ååefff¸uë T«Uh‡G}Ä]<×ËÐí¾+_†!R \Ç%“Í`YùµÛ½ýw*PÏ ™I»¥, ×þJp)ã]Šl&Î[µº…lûí_xõApúôi"àüùó÷ð´rzÐsÚuw”ØøvîñWwpÝØÀ™ŸŸ§Õjqtj Ïs Ã[wçh=ö1%ðúk¹kœY^^&›ÍQ*"¥dum•/ù+lmmqòÔIÆÆÆ¸sç7fágÿ°ÜÞAr?» J‘Þ ß DrÍÜ¥üî Azþ­ேñöªÒ0Wi¬?Sf,ê3_ƒé¦>£½€kÆS±…g䯂!Å ~L·Sûùî Ánšr¥­û^ “¶Lk”™¶{¯á+ ú·l›Ì &ßÝ›WS–:-ƒNŠ2é€üCòÛ*béðSgÿ«¾E.—Ãó\²Ù,cccL™bll”0ŒØÙÙaccƒÅÅE®_¿Î믿έ[·X]YÁ÷}„„a³Ê¶Ü 7n |¿bÜ’8NÌn­S|õËÌœü ¾›ÕÏ÷‘žõªM0?þ8þÙ?Fìl’Ëe; ndx˜‰C‡¨T*aH½V£Z­²²²Â;w¸yó&333l¬¯ãû>VÛõd—õ¿glXAH«åÇ®žûÈ×¶(^úSnýKøv64ÒtÕZ·¯~B\î¸Ìd²Y,)Ùªn!¬6¿p?ðyô‘ÇÎ;ýóé¡ ª}„Â‿ÆXcŽL6Ó1è×A ÉæÆ›››>Ÿ§P,rå_dû/ýH«k~$!ÿÕÈe²2¢ºUetd·½+óâ‹/ñòË/cÛ6oÛÛÈd2¼ôÒKTù$<ófk‡A¹Œê$íz*ú¼–VS<2Ä`&ÁÀ„á{zaÑMøCÀ-¡gL/Óg 3–Ʊ_¤¸gÊ(  ë@R/9-ÐMîûç ħÍ[d¸@D=Ô}?u§†&õbÒÇzíOi€~¿Ær/ÿýJS`Ñ‹ûš©Qòñza”Å·ÿ«s3l¼üUB¿E¡PÄó<\×¥T*155ÅéÓ§9vìår !$­V‹íí퀽qã‹‹‹ø¾З=QwvvˆÂÇuÉd³ÈÆþ…¯³øÔÒl±Ö,ÄõÂ(óO|‚Õù¸—Çn»: MLpüøq&¦84„ß÷©Õj¬¯¯3;;Ë­Û·YZZê(ŠìúOïù¶·· Ã0Ö™Îf¡¾MóüsÌ?öQî“ô=Žxêòìß°®tò™Íf‘R²¹UÅ’1?wîaòøcE/¿üò=ž–íV/k@;mËÎp¦~©m”Ù€h«¶Ä»óóód2ÆÇÇÉçrÜ~ã +Åã„c'»¾ûLf…ÏÞbyy?? àÙgŸåöíÛLLLðØc±½½ÍóÏ??þÏ`ìxr¹Doìb€ IDATŠrõZw)ÚØh7ÐôÛi˜ò4ùJÓßÓ°Û¦­xðkmSÿI†ÖdÁ5½¯ó!7¹× H†@cÝ”õí—ýŽR Ê^¶)[û ö^¯}¯¶0ì#½´[¯~æ¦ï0íïýŽCRº…@g|«XêAñHc<¤ <´ª§ßÇÒÓŸ`~æ.·ŸÿK³w±m‡|!ãÄ 3ŸÏ366Ɖ'xüñÇ9}ú4cmw• ØÙÙaii‰•••xÍËç;ê)a²¶¶Dd³²™,­ù¬Xv=Ò½=t;W]Ö¢ÐrØ<õ^–žü8ó³w¹óŸ²<7ƒmYd³ÙØïØ²ÉærŒŒ sôè1N:Åôô4£££—ˆZ­Æòò ++ËH))ò÷±ñ}ŸååeÂ0lûçh̾Á²È±}ðt:Ư×ë{êå3öUà·¤¤Z­"÷pß÷yü‰'8{ö,üøçÍÆ§ q—ÄnXeži¼J6j’Éd Ã׋wH\Ïe~nžF£Áôôtgââ…óøoÿt×±ös•Û¼cÌfaa‘b1>ŒkYñAË/þñ©Õj<ýôÓT*.]¾ÌjŸùõ7{˜û:àlÊ@ÓCZAífzf/ iÑËuSƒÔô^RäÏ>xÿ*(»¿ºÓ§!É^öþ[ç ßMXwŸ„ûª´&Zä:p]@ ^µÆMÞo’OS-m˜~ïs½he«t˜¡3.R–-ÎxRÞQw¦iÑºõ=Ù¥Ójî÷:Um®btLõ»Mò7è(›ªz}È~Íò8K?þ+¬|ê—¹ûÝ?åâÙgÉ}ýw)Ú011Á‰éi&¦P( ¥$›ÉrôØ1Ž?Ž‚f³ÉÂÂóóó,-/uB}{^Çqh5›ll¬³µU%›Íáz.‡føÏþËoÿQRDî~÷ß{äÊš¥q–þ꯰ò#¿ÌÌ+_âòÙgɼðG¬ƒrôØ1MLËÇ>ßÙl–r¹ÌÉ“'c]ê0dqq‰ÅÅp=ñƒñ2®ŒG–——Y[[køq™ššbäkÿ‚Å'?—G§ÇÜ­¯í×/Öi/·ïÇ.3BÄ;DQçi†÷X|ǹ?iô¢ÓèUk”A")¸X|šm}Çq:Ò–e†!ãããÌÎÎQ¯×Éçó<ú裔¿ôPony…û¾™?X^§Zˆ¢€áJËŠݹïžcccƒb±ÈÑ£G‘RrõÊx÷Ïßß&à»Ïé4Г~Ti¡3>ð$µªýyOó^ÕܨêïIò‚IyOúö~ƒÕW© ¨ô²A-ήÓÑMZ<ÓjŽ ƒ²¨^Ðëw“|KZÄû¹ž'N¸ ´ô“¾­lS ð¤þižC“_•8$ëx§­“Ywƒh·$-lSýñ(å˜Ò鲚Ì/::m,ƒ(aÛ3¦x„y¨qú¢)›þV3ân–w}Šw}е …sã<·®~›/?÷åߢHƒ‰ñ N:ÅÉ“')—JXm{âÄ Ž?Îææ&ËËËÔjõöáF‡ÑÑQ*‹Ã\¼x‘|¾Àää$ÃÃ#«/‘»yŽgÔ™J9‰ÚåyæÓì<óiZØ7_áîë/òÝמÇýÆRŒŸgvv–ååexßÏ$»ZDý•+±LêÓô½´›®Ý»~¡ÈS¯á&ý=B¯{.ôã`|0¼vÇÄç(2ºšöþ î™ÖIéÂÀ«ô™ûÕ W=«°ºíÍAëŒ'Yé½<÷ u¼MA÷ êŽín²e8Ýú4Úú&cÍdêÆoðJóÝ4ó¡ÉÙÙË^˜õ·òg9´Nž¡uò |ò³l3W™}í[|÷µpÿßßf8Üá±Çãï|'qôÁR ×uÙØØ`{{›¡¡!<×åäÉS\¾|™›7ordrÛ¶åÚ•`úLwãÝTi&IS|ïó¶ƒ?ý þô3ðñϲ-`sö*s¯½À…+ßÂýß»Wž3g˜ïDS´m›ÍMÖ××)—˸®Ë±cÇxå•W¸víã)ƹú?£çIsŒn%_oáí¿E;âdWnêš×mWÒ»öíI»` 3çbÒ_$—sRb;6¶e366F©Tbee%–‚´-ÞûÞ÷rö+¿ð=ßúp~Û²i4 ¢(>ôúë¯333ƒã8œ8~!—.^‚cÏÀÄ£Ék·è¯\=…œïåìOÚv3¹¦òg×&3Ñ7éïªg„bÌ” yK8)¨$öËTf&Rô´A:tL[¿@\• ¯›€è4€ÊäÝ*‰=]ZÀ6ù¶‰E°«šÀº•­€õ0‘ôZwº´QŸí¦³&tLú¤É˜ê¤ƒyP°óÃKi€¸‰ñ zœ{rõ”àði‚çi}äg©[sט}ñYÎþɳ¼cØå™gžajê(Ùl–(Š‚ „R24T R©pëÖ-Ö76bÙñ1¬+ß‚Oü’X ¥ 2—ð\0qšàÐiZþ9êlÍ_cö¥g9ûÅgyÇH\ž#““är¹N4ÐÝèÙl–R©ÄíÛ·YY]¡R©022‚uõ[ð±_ê/h€Æ¾÷„aH†DDm¿û¨ãŸÇ‰q@%“ù.- #Å®Rû÷RæQŽÕW:2–‚(êdÛŒsûöm666azzšÊoþ& ›óD¥qJ¢É{ ›,-·ðý…b‘ ü€—^z‰ÍÍM†††Ÿ§ÑhðÚ•×àSÿ¤{ŸÒ­Éi¸ëÜ)M¾AÊüE†Ä€.`]bÁäŒQZ€Þï:3à@ÿe¾ñÁ_æ›Wnsí7‚€L&C>_`ll ×óˆ¢è¾òA@¡P \¸¡>/5¨à%{ê¬ÀÃØç;ÜÆw€x ËïæIâÝŒ]P«6é䈻S/Ù' …E£Ñ@ A³Ù""Âó<>Œ”’ÙÙY"âhŸœ:Eôíßî¼þýÞ…\–;wmëëë\¹r…0 ;aíoݺÅv½ïþŒ^É,­ô¢N½Fõ ÿ¯K«ÓùÖµ›Iz•RJšgMò–Ôß»]7=(ü–p•£`G) €2›l?ˆ{ªúŠz,&@F÷Ý$€®Í&NœM¨ ÃiòhÊz“`ìé¾)R[RæÍ¤îú©SÿH³“{ýta`l›q@FüU¾jž3Öºï¦Ý‘ŒR¦ˆ~;O„?ókÌ7 W((—ËDQÄù¹¹N¸ñpc9x…Ñb Ä#ÃÅ{_ßyú#¼øã¿Æ|S²±‡G¢l.K©4D…ŒŽ¾¹<›+Ýß­únÒÚ˜†ö]óÝ÷7»<¼º÷rå»U×0; o[dxUNÒh4ˆ¢)c¸#¥$ߎкººJàûDQÄ{ßû^ìïð¹3 ÙlÆu†~À¥K—X\\Äó<ŽL!ð}.\¸O} #j`¨*›©‘‘$/ÓFJp¢¯ªú’©ö}?i’Äá[ ÀM€eVÆd‘ÂÔªŸ4‹[?¬)@:†Œ•**€®cUå×1РöW3e°{¢½€X“wªêßPøHÑ?D¹t†QÚv ÞKŠ~ªëï¦=24Ô{1¤M€¸)‘ ú¾Ð:FÛ”ù>øÕrüvæ';@/Œ"lÇÁÙñ°ÙlÆQ5Û‡ƒýEý‚™« è¦`Îkùa^{ûOܶA€--lË" B,Û¦Ùl²¶¶†ß‰Áær2+ªÛy1eöö]‚à¾?Q×}ÔÎ÷.øÞû·Ñ»{aLM˜Ý=×¾íœF´Ë ¤¤ÕòÛ~ì’tê7 B¦Žadëîê &ì:Of·¸}çFƒ|>OÔj5^>wŽ­­-Êå2åR™­ím®_¿ïûéÔùK%3˜F&ïQZ“Sð¤]ÞuR†ºþnrxßäÐ[Æ€?ˆíU€œ–¹Š4–xd¸ðEš…-J‘¯Aô´½W¦Z'I§&þ®ih? 6añ A|?åJÓviËú·QÊoëv]LúSšþ.,°jlëvÒTãÔ„}VåAwý?S×”k哔˥6û3±AElooÓl6i4A@£ÑÀ#u ×j™?Õ:dœ×*§)•J1¸ C‚6¸õíí-šÍ&Ífß÷ã¿wË£3ú­wÌÞ^ýó0$|ßï€ð0 ¢ðž{ÊŸ|#–&HŒ.½L^p޲¹Ôjµ›9rëæ ‚<ùÄœXø-.‘ËÆî'!-‹V«ÅòÒ27oÜàСC„aÈë¯_%È ÁÛ~ôÍå65teÓi ›€ä^€½©a4àv3޾™VÈ ¿ë Òĺíá7¸C˜Ý2bÑ- „ Åb¯sÎ×};LhÕ}UÙ’ÀE  vR%£gRgIeëöm^âN篮ø(¶wMÒ ƒk|82‰êå»ì«»¤º×)õ$íö˜–+é9‰Ú=$ì!­I»éü¾…b<í¯W‘²ï™ô÷¤9%RŒ5‚æìߪËSÒ<ÑÏÜi’6©þ2W•ª¦©V«ð'D̈/--Ñl6) A@us“p7}š:Q±`ªCçB±» U¹%³ÌÏÍqóÖ-Ö××°¤EË÷ÙÞÚb}}½sÐoue…f«Eäæî×$Þ?–¥büºË¨j@Ì—¿ü*•2ãããäry,KÆŒ²H!Úþá÷|ÃßMt¾Md„Uìe7½fßq¦yïN,é(eT¶uËs¹\l¸µbCçðä$òî7¨õ*ÿ|á*³3sd<—‘±QJC%–—WXXXÀó<&&&‚€W_½ïúIp\½j—ªÌ*™W]½è˜[P+ÿt©»û¾jX`i˜?Ãv{“Ž·IzR¾×DæVu}¿Áp]í(eÇQÉiéÔ0`’Tß 6ÊDa%Òä1D:2TB‘Ǥë¡"Ï’^[Úô‘LBoúÙ&iMuÆ“Xã°‡¼é‚ô«žT~Ó´‚ôºåhúÂþïG)û^d8w„ ^Ê0IŸVµu)4õ“D$è\"ÒÌiÊ„&}û÷?‹³üËÚ!.e=P^Žâà)ëëë„A€XmxûömZ­V€¯®®–ÇÍ‚¡íû}ð~•WŸø«SïT“B*CK§l#ÀÙ\ữ¼ÂÖÖQ,ÆQ…¬­¯Ójµð}¿ýÌ6~通8J •dì’ðÜž/--077ÇÅ‹) LOO“Ëå(•KD"ŽH´Aø®.x$ Œ†K’^5¶”7—ñEïQÞ·sžf³‰%%fÇv–Åðð0ׯ_ç«_ý*ëkë¶{{ãn;i/“¡Ùh2;;Ë… X]]¥X,27;‹—ɰ¸¸¿ø³o&htå3-[¤y—IÚnßDQwû SÝv©ØýLÙn÷}Û$}’vxRŸW©ª¤y÷[ÀMäLunÓêÚFŠm௢ƒÐV± ¦å4•]”ör99¹)`GÇ“"½Iû˜¤5ùnZùESq“ç!ŸhZ.ÓºKÛn½êÖ?ˆþÞë8Tx]Z],4óšˆë€ö€¥ ßfmrèŸÿwžâöÛ?ÅÂ#"²œðÒåç¸cß¡V«“ËÅr„‚ŽZÈèè(¾ï3¿0O4~ܼoî¹w|ë•?ùǬ çú“ŸdîäˆlÇl­Dán;¾ûÊå2­V )%¹|)µZíím …"–e±½½Etü)ý|¡#utëé¾g2ÙŽ!Ðò}.¿öÕÍMJCCLMÅ÷ýŽ›J„êõPµ³-4¸ƒõ¦K¿½åŽ3/JŒn­‘ÏgñÛ®$·nÝâê•+øaˆcÙd²2ž‡°$RÄÑS=×Ãu\‚0 ^¯³³³ƒ‚\.ÇìÜsss0~N¾[¯ø•D:‚™| ésiµÂM¥!UåÂØëpBZYJ0—GTåÌ5¼+Ø?W)iƒN„Ÿˆƒ^CÍv£©•žæ¾é=pÐ h0ÑOóÙA0]0½ê~Ó§ÕOš,MËì £Qâu»@&@¿×ºëµÝÐŒ‰~u롹¯›‹ÒÄP¦°é˜O Êz™“öý666ù©¿ù7ùÿ~ó7yâ‹ÿŒSÏý_Ì?ñQæÿËlÈbUØZâéóÀ7v6X\\`òÈN­­1~à —/_faaÛ¶fss3–ûø_Q÷¡7›É}2;óŒ¿ð³ýÒopsúÜ}䇨S»Iê˜åv)l/ó¾[_&W(°½½M±P¤P,p÷îvvv°,‹áá ®ëR¯×‰NIp%Jq/¡¯‹&­V«ν¾³ÃÖÖ/¾Êêê*Qqýúu ùBÌ€§‘½3Ñu6Õ‹NHÿ¼uœ§¯½ÌÖÖ³³³4[Mliá¸.®”HD,m™/`Ùqèz!/ƒ°;Û;lnnÒl6ÛÑJK¬¯¯Ã}Ní¶%ú±ý‚øÈpW/ iibd¦i7úlwÜgª_®Ã=ü Ž7ɽ0-2Ê&š-]”Í^¢pšÞ3©/Ó(g¦¬)€àcZ6SŠˆH (ÒLà&à\§£ñª÷ô(G÷NXw¤l÷4í¦ë7ý’º÷ô:Uc[e3JÁ>›>§ZLu‹Jй÷_ýëE£Ùb™·ls›ãç¾À‰s@sü$óÇßÅüÔÖœ$’é—ã øÀË¿íÀìÖŽëQ¯Õ¹pá<ßm¼ð­¨V«‹E.]¼„ïû¬¬¬ÀÓ2[¼÷Õm¹RÁ²-|? Õj‘m5ºöeíY-Œ3wì],ì–GØæãjOy>zõ÷(3,.¬S)—9<9‰ã8ø¾ÏììFƒ±±1†‡‡©ÕjìÔjðäêÅ L"ø™F÷‹ T*S«Õh6›ØŽCàûÔëuZ~‹°Íxû¾Ï­[·:2ÁuÔ#Ûjt÷´õ‹îiÂW^Á’–3ÜŽç’‘´£xf³Yòù<Žã`[÷®‡aH³Ñduu•0 ©T*äóyÖÖÖhµZðþŸNžãÓèq§M× “¬“:Ï€´ßèµl¦ínÚoHÑ÷LúCÀ{ ‡lâG& 4`ÊdkãAFÙLS_iCp÷LBÀ¦>½€÷”4€LUú±: ¬ûF¤™ÐÒ‚ó4 ^U 'ÌAÕ‰iݧÙÕyØ£l’h› :¿æïA”MÛ¶ Úª$R „qB)ÈWç¿òEœë_Adò¬8ÍÚðQÖJ‡ÙÌSÍ”¨Ù9ZÒ!7l‘ów©¯2¹y›GW_ã`c™ZVrg©F&›åÀЖ%iù7®_g}})%Ãä”T«›±¿ô£ïQ¯Y kF¥RŽe ƒßoÑjµh6›ÔuÜÆ*c¯ýÁÅÿ@=4Ž¿ƒµÊëå#låGÙÎÓpóø– Rbû 2ÍmÊ[ Œ¯]çÔò%¦:vÞaiiB¡ÈÔ‘#‡†Bpö;g™››Ã¶mŽ=J.›cvv–VayžA6ñOq¯\.ã8­f Ç „z½N«×Ën2»¨F_3Ù5†s½‰»§bo ³3u†ò\|3f·³xžKë:¸®K&“Á²¬vßYð0 iµZlll ¥d||œl6˵k×àÑÁÈTò·MC««È ]¤pÆÐNk˜¸ŸèÒêt¾Uín‚k0ü~?ý-à½0Û¤XÝqÀ6]Pu`ÊL™ý0âýú­¦aïL'FSPé›bpMâ DÓ¤Õ1!&®!i …^ó–¶\L’iÚÝÔ(3Y("QÚAÚË84íC:7"“€&äG?!ëíœËæ:N2™ QQbÛŽëà8.žçaY›sd7×qv.!¥ìÝ?»àÇq]Û¦‘˜Ýl²±±I¾gòÈ$R wîÌpþüyZ­år™‘‘8xÍêêüøßa°Rv)w&“!›m´â S¯Õ©nUÉd2©Ãf³…ˆùK^¾—_@¥RA´_´¾±Ž%ãò”ËåX‰#'ÙÞn²¹¹I6›åرc ±ëƵk×øÂþ€Z­Æ¡C‡8rä0;; ?ú÷@ µ,l·~Õ'Ïf³„aˆã8dsY?ÖÃÞ•FÜ Êãy¾ï#vë\ןÒt0| cxéÑ3¹ù®çẶí’Ëem¦Û¶íN_ÜíË»;:óóóloo“Ëå8pàÀ½–ýóuJDu®!&sœÐ¬ ¦gR7Z ñ½HkäÓú™›¼ã¡à¤`qà»u*•ü ®"ÓúI'u¢~ýÀÓ²W¦@<é$o’TT/ ¸p­t¦>l*é½&ûM›&¦õ2Èr©\ÁLÓšñn2¡iNý›0å&ý=­Aš4÷æ_¥NÔm§¬[ÙM±§™;M ,RûÅ¡"NÍ!(—ËŠEü6kìû>®ëâº.BÊXº.ññcÀÓöÁÝ›'?ô‰Â¨£?íû>ddd!âC—ßþö·ùÒ—¾£|ž©£Sär9n߾͎ƒûlÏë–ë:8Ž»”+d&2¬¯¯³¶¶ÎÖÖžçÑl6Û‡°­“ÌÏÍãe¼Î>ˆÔT·¶¨Õjضƒ022ÂáÇÉçó„aÈ׿ö5~ó·~‹ J¥O<ñ™L†óçϳÚð£Ÿ5 &ƽŽ)lßó2á¹Â EüÀðvtÌ\.GËÛ4Ø›'‰Úý*2X’Æt·w'¤Ÿ?ö~r¯ÿ6.™l†(ŒÈçó¸ŽCË÷;†ß.øí¿[Í&·nÝ¢Ñh055…í8ÌÏÏÓ6üÀ_°@Tb¦–ÔmìKÃù_0x¤=¦íV¶´»&³(›iÆÚCÀUK%Ø®’€IÒoLÚ¾é¦w½¿ÁuZà&ßÖiw#IFЉ®°.x lë¬EàfšÌ3qÓw$IÏ©ô¢“L¯:ÞЛFydÐÏuåбZß+ tÕ5UÝ©tÆ“´¼uíf¬Óô÷¤ùI×WéRn°ßmž®2RÒùJš;M檩R©°å8mÆÐ¢ÕlRÛÙ!“Í266F¹\îçûB—‡avØïÝk®åbÛvìÍà¹Â0³´¸ÈxöY^|ñEÂ0ddd„ééi†‡‡™ŸŸgffþÞ¿†|¹çuËu=lÛ& #6«›lV7Y]]Ų,FGGÈçó4›-Ö××h4w ß÷ãò :`β-Û!“ÉËå(‹ ,ÛÆ’‚¥å%¾ðû_àk_ûa2>>ÎÓO?ÍÄÄ7oÞäêÕ«ð¹ ¹r:}bmr•S;­çºØm×qA\ÏÅmÇéçÉç󃚭n;€:e žï¦7-ºŒÅ.ýÖ·³¬œx?'æ^ì0ùRJllj]¦l KJDÛ…j÷7s÷. H)9tè0¶eq÷î]8óiÈ»“)iòŽbnHj§n@P…T:Þ&y3Ñ1ïEg\—¿$老j ^UÃC'Cˆf«É„Í5™èuVôþ ·e#ôþO‘f’0˜ÈŒhéÅ(E¨t‘!½¢„Nƒ¼ÛûÑl%uêóƒˆ*€Òm‡D·cÑM+;F¹iäG]žÓ2çJ]W.]Ý™¦5m7n½ÊØN+e¨ë«¦1’@¸NëÛ$*¦i¾MçΔçyJ¥RçÑF£ÁÌÌ 7nÜ Ñh0==Íôô4™l– å3T¢T*‘Ífp)%QÆ>äDAØñ%Þ ¶³µUe~~K—.rîÜ9æææ(•JLMMqôè–e3;7ËÊ}òoÃ~¦¿…Ѷ:ðv%¯\¹B­Vãĉ;v ˲h4±&v©„Ý>¼'±.v¶ËÅ@϶‘Ò²-¶ªUVVW¹|ù2ßùÎw˜™™¡\.sêÔ)N:‰ëzܼy“³gÏÒüá_¼WUØ{“5-R¼„±éy¶- CÉ»w¸ví_ùÊWâa†± à8Nì:ä8ÔUÚé¦á*T&ÝÜíIwmâ½<µy!NÆfgg‡›7oòÊ+¯P«Õîs=Ù•VÜÜÜd{{»½3L½^gyy~êgÔßÖi]ëXè4úáhÈ:i¸#b¢¿nš·$6]eèÜ~ÊOËz IDATÖ­|QBÞÓêÖ¿¥Ü4èƒ ¨UUÞ ¤ u~qIïM+eØ 71NLïõ"¨ÛjïWƒ<­ª ¤×«îGÅ8=n5Q1=$òVk ›¤Õ1ì¦}2ŸÖðL#é©ÚMsO vAéGʰ—¹3ažB€XR’Ïç9~ü8ÇŽ' 6«[\ºt‰……Z­ãããLLL0<2L©8„—ÉÄn íPæ-¿E£Þ ÙlR­VYY^ffv¶ã‡›ÏçyÏ{ÞÃÄÄ–”´|Ÿ«W¯réÒ%ù/á­ï%­ÙŒÝgvÕ1N:ÅñãÇi6c5ŒË—.37?G³Ùdtt”±±1ŠÅbìÒàºãA‚°ƽV«±±±ÁÜÜ‹‹‹±ü`±È?øAŽNÅqš­&¯¾ú*çΣþC?¿ðkf¡…fþ2y¦Ëw\×ÕC¬Z­Æêêê}®'ccc÷ðT±;LTóWd¶ÞÜ*"(ŽaU—±,»Ó樂4Žÿú®áçû>ÃÃÃLOOwB×7²xâ/›ZNãÖa,Çä ©·ÉsidUò‰ô‘VôP¶^tÂ{Õ­KxZ?o]'4¦c–z¢¦@\×éM€øƒVPHï'ˆ°$2Ý»Ñl‘™¦}p¡^@,˜+‡è$ MÀyÚç´zšºÓí~™¤Õ힥QôIkê®§‡º{i€~æ¹”@ü¹<þ+_§˜ñ8xð ¥R)d®Ëèècc£ñÁDAÄÞ¼q“µµ5ÖÖÖØÜܤ^¯wü½#"2®G6—£P(P© sæÌ*•Xåd÷àÝ»w¹té³+kð‹¿Ÿø…pJÏ.„´^ú•Bމ‰ Êå2¶»\ŒŽŽR©Tx:xºªWWW™™™a}cÍM¶¶¶¨7mà½Ë$g³Y†††æ™gžalt»ík¾+åwîÜ9î.­À/ü¯ðñ_H užŽ€êbØyž»Ë„!“““8x|à·›V«Eøø~€eY¸®k¦®“æpf/½Ë؉\=Ã;š_Ų,ŠÅ">ú(<òHѳmA@Fßã»fggïÿi"Ëz0 V'W+zØ&¤S/ßxè¦8.­<¡N^7ç>”‘0M.0Þ«kŠI%÷²@é„éû²õp? »o žûeüúÑ ï%ðJš@@ƒH¯«»A)”¨ÆŒIþÒj€§Q"‰HƤÎxšv‡þuëûÕ””¡Éý½Ú )æ Í7ÿø=ŸÅzçߢ|í[ ]ú*¥o>O.l2<<ÌÁñƒŒŽ‘Íe‘Â"—Ë‘Ë嘜œ¼§˜Dmíº˜YŸ ýwËÚ /VŸ¸~ý:ׯ_gquð? ?÷`ô0ƒúýá;ë©¿Éð/2tñ«”_ü*yZT*<ÀpeÇq°¬¸<™L†ñññv9Þ\I{ËÙñuoÿYYYá7ÞàÚµk,¬¬¼ÿ'àÿ#>œ †Ò2˽º¦ìÉï^…iI¬À"!–¶Åfâõ™LFæ;í!Ì~úž÷œ/?Í6ÏRÛÙÁ²ìNŸëH(îi›À÷;J:¢¡tssùÁŸ½ÿ ©ŽDԱ؃J›£¤¤”|bZÖd€ýÊôÛº]öüçÞ¼•ê=&>ˆý¸¦D˜ùˆ›tB3Õ¯”á ÔUd”ÍXt Kg}§jƒØ —ÓëEg<-ˆ7e¤M"yš<' Ëßo»õâ֤ꓢÇrBâP7ÞúÝ)Sº½ŒyE? œ,+ÿ+ÿÙ¹×ÈÜ8‡wý;dÎ}ok™L&ÃÐPì^.—Éçód2™ØÍ¡Ížî²ÁµZjµÊÚÚ+++,//³¼¼ÌÆÆÉÇácŸ…ý-žàAü'ËÒ£béÑ!€ìl»Î}þOÑív1 ày¾¢Kè÷QqiÌ\dÜ=røÉ׫ë [çYƲbMž¡íºveÕ7•¦Ì*¡˜¥ü´°yõkr*"}ó?x€ÃÔ€‰eâÐXwºû˜”›æ·T½_ÓT»T½tÊñŒÉ5¦YèuýO±¨uãâNõ „ G]èM;Ø–ñ¹³h›îwYÛešNxšçš¼sêØ3ïÓÎ)U™,ó^GèÊzý\u›p6^€½ù2ì­—am\„µu¢Óúm ßì¶ ¹ a9vbn²vbåäÉ»!n; yï» «+¸Ñ»± g=hÏæK°7^Ûº´§³¯=Ò)Œ·çDJ{TnBú´îiãE÷;Ly=-™ ê—Fx©¾OkEшzhª E¹§ 94mY ez“ït‰ãªO¦}oºq3·>*?8"ës@\¸Âï)Œ•S1HiGt0¸žÕ5E(à€ò½êøQ'‘¦YªhyªŸ¸®<õTS”5“Ô:ë~§zfZÙ,mÍÚwÔúe÷YÇ  gï¦ójd«˜È¬De6qCœas³}’Þ½0èO ¨5âi€†’ÈDåʦËAa Äuirž Å:` ®Óîa `ue)˜…ZOiØn@ämÒ¶¬u3m—É»KÔ²”÷6%w|2‘ÃR-¶Ißé’îè7¡Ù`(ß“¿Õmhº>MH×8Oê[ ê£l(Ú©jWÒ÷“mÓé"[Ä…=M§;é}ètÂs½ê4¦R•(%IgœZV¥Ç­*›f½3bÛ(ýbR·Yi Ã ~–ÁXP)‡ÌJû>m.3âœa¾éúRð¤ú $«ò,P ]Îù+”'­ß–bn©úD¥i¬#}t:à”Ü “ºËin,ôÊ5Õ÷’ЯT#›rµ ‘¥ÁªD‚i‰…Ò4Ωe%‡1MY-nÎ84Ä“©~ºJœR6Ë{C ¸¿é8…£DµÂкÕùQä):Ü€¹”¡ÎgHצjœ ÐScëØ{*3 Ò— V)U¥„jy›ÈáMÖ/©n”òqjY0R•ÕéG§µ °Ð5ÐUuKc¸Jgœr4IÑœW±²í{I˜Ë:å!hÞk–€í´<:7ê:dµ¡®/À¤…¾®ûŸi@"4ïÕÔu л¨¤1ÒÔ®™Ìb¨Lƒ0uý§3øt>òª{X Ÿ’&Íe•Ž·êwrвºÄ2¦õKÓâ¦È ªH $œ£*›†ç²j”CAQuÂoz®Úl²,°&“\wÔ+5Ö•`Sštà“Ò&]r U(ýN1ލŠT™BÝñ;U’NwYÊÎBÇ[W–ÚF]°¦.µ=œ#ãïnqú„÷n gðLé¦L#2®sYe`M€ø4Rµ¯$ dWpЕ4ò…âgN FK;eJ*/ õgÄß錋,J1&zÓ@6ì4;«Ì ®îRƒ¹¨Ø 0¥\RÖNJßOSÖô½Ý”™0gÁˆg]`g‘e“RÆt31⺅aš6OÓïI_§¬@e¸M$)Šº{ÀP©€ÞA'ò¡êqO#ã'3‚sà`5ÐMËNûÞLÔxf•œŠ2V©*)TcYž’X Y­_YÖÚ,ëÙ«ˆSŒ^ÓòŒð~¨@WG’éê¬rC0%| %µí„†)7‘©3ÉTMßOû S¯sƒ‚!Ð¥j S}jYIh5æÀb½ÞR†³âªgO« <-P—ƒ7k–Í´çdè&zÑ ¦åRg\Ç–HB?Pú^u<{ò‰–€sšï(ïÃ,Ì g5–Ú)Éõ̲™%‰›‰á+ ˆƒø~)û£ôPrPƒŒY6É@„ñše/2ѧºgQq½iªÌ î´uV2~ÔöªžaÒ.Ýkú>¨§Lº¶½jø4z–÷9ÈãUi¸øªü¶Tþœºë×3Ëæ¬‹)sMè”MJ‚æÛLy~Ú6‹²”“*3šÄë@v¶ÛÄ81í»iÊ›èÖëÆÓÍeSbú\e“̈¿\S@ÇÔ>¡d»4кu%C–M圢¸ãP™ÿ¬d‘‰Ñ“HR ’YêŒS’åPÝÌO­²j€ÏZ²&RßÅ« €ß @üFfÙèþñ×3˦i_šø­$@§21&L-›qyÓD>ÔçP(ãÃÔ7œiX³i“MÛw¦ïmV^§ï Îê|K[(FÄgÙÔ‚­W³k e}˜•kЏëö@ á¡0â³`¸Mˆ¢,ìµ=.$KyJÛ¨eg âAñ2c»²€xÓvQêüªà7§‚¨$€-‡´—+0’Ä¡,×3ËfV¶\%M( ödÄ ˜öôRW:š¤Î¡ºoÚoÓê¥WU‘´ï±ÿ&Çœ=øŠÂdaŠºéÚeÚw”÷&æbÚX –Wõ­Éx§¡0¤M¯©®«üÑg‘e“Øgº^½’Á¸)Û›ȧ[ ú,›*¹RU³(´ ¡~j7,©øÖY•›5&&.ã—¥|’º‡¥1vÒÊêÜÒRV…‘¬‰¶e­e¯6m×dÝLûä;€«@—êX+Ë}@`¹“6'•OnÚD§l„*` èµ}UA“:ýWÕu•î0U9ù 0&i~¨*­è´û3Bý¥ÂÈš¼¯PÔÙ‚Zc[§÷$BQ*r‘2&Ó| ),Iý2kýtF&ïm²ucA7_²èÖƒ0—©šûL”A\§Teuê(iÀN×në%á%ï•´ÿ1¨õó©,¡.{$Ì"Á0SÍQFKªëiZýiÞI:ÞÐÌ´ï-"^H‹£H«š^µ®<ßAaHQ5Ê™!î‘ЦÅ=k t1¡ÒÿôåßQ\ÇàΊ§°¦á¦*-:÷¦y¶lÀðºÊ……i&t˯cÃ(Á™*FPh6йHéó4 o¤|—Eg\g¨Ê¦ÕÑ„7 ‚¢ÏMu¼MÛE­›î4AÖtmSiœ›êÖ«Æ“©æ¾„¹² sÑT݉¢lAÉã0›‰é)æ!3®–2¤è—«yMTPTÏ1¹–ÒYÆÿFÂ}&‰ªN8€R~V:ã¦Ì1Uƈ)Fá4úé,C»tc‡Ü @Sج u)C*ÀhÑ×R3IUŨ†Á´×f¥œ%© %sZyCÓD@ºèø¬eg)Q¨c )õ›EÝ(à¤n€¹F¹I²ŠQ¦K‹m Ðuk…)§ÈR@B3WÙnN“îfâ¦É}L<õY”Ì®ª¬°È`\PIÊ>cÊUóÑ4@“û»tÆUe)kIÛLå)íRá@ÊšûÀ): +~PY6)òaÐ N(X§´ßP6daƲ€xoªžUã;‹ÚJ–„0³Öñ†æý˜h”gIDiUÛÜÄøš&‘0[r£ D€Nï³Ì² Ђ˜“Ê©Æô¬³lfâÓ&{µqÊT–M™L `Ëše“2³tÓD@¦`r j*x=@¼©xVõ™,ú釜 U`’º éXJj–MÕ žu–MjÊyS©Âi™1j½Lûæ ¤ ³¨U€øÝ,@@»Èð @¯3®ãЯZ §Õ@§‚äY•…¡aEÞ0Kr*êX¥‚t @¦&àQ5³lΈCó.Ò(©’ŸY²l‚ð^u2ˆ¦ï—b\ÌJÊЄ2É:1ê•(›$ RIdÃAi Ã ì >¯^>Ëv–Y6gy¼:ë,›Y¥ uÆÉä5¦¹¦;y 2Ü Ðg¤g]ÞTŽï e)e)FƬ5ЩeA,«ëª¡9­ø´Y²lêÖÊiNÚLXêÃ,›æõ>È,›YÓÉS]ucŒU¹Y'ñ¡´ †k«)À7òT™AŠ`¢å…í>ùDJßú€g\Œ¦Y`_­Y6¯—”! êe²˜]OÀB¦™:³$nÑ=VZÙTyª›ÄC³I´aC©3ËX÷,Y6©9ÅÅÈ$©WÚõ,Y6)Áî™eóÕ )þjʲÉpc³lêŒ~“,›TKÕ«Î &³êŒSžKñ˜¢m0l—Iû1»ùÿÀU lšõAÜG¥0íñj–,›iÏRi˜KÂuUŸè®eé:ÄÌP5Èuß â½ÓÞIRš–·Rî©ë;­lFx%ËžJÆ2MºQÕWT t™ÒÏÓôªì4ï’e„ñˆ ã} =M[>éúõ̲I•­Õ>q3îiê ÓdÙd˜m–ÍIY¹¤÷š¤MNÑùN“­ƒÂ°ÔÀqMi݉®epÿ´{SK’ʳÕ7)ËR溉L¥NC} tJÝÒúä€OÁ ¤éŠš]&M\ 4Mq“ÃIµT°Rè¦i€ê#–áºJwX)oÒ.™Ò7­qII}¯Òùè:áYuÆ©:Þ@ è“ìè´Â'Ç“NOÛ4éQšÄ£Jg<­]Óôª, ÖPgå§Õ­Ïª¹ÍŠM]•«@w]¥­n’ÇAµžY0;½¤€øW(W‘2*uhN'Tšä”g¥íOH¹§ê> >ÇôSŒ•FxÒø×íÉñþÕé„'í¹ÐÔ-m ë±jΪ€mÚwIîªuH–(TIêê&5õôÊ<‡|†Ì¸Îò§ÜG€~:”!å˜ôFIš¦¶ÏÒ'@º2CÒ³èʪMDj@‡êÞŒÈ,«ê‘fôÌR+{ZáÐgjÐ µ_n„zÚs©ò„ºò³Ð­7•2ÔÍ5@À$_€Ž§*P˜¬‚0U÷£ø‘¾÷¿Y(¨PwÊ{Ô40¸NmEÅ%í$É2hŸ©Ô«J'œª“mR>‹Î8›AUŠXie-Ð]yf¡~¨‚rÀ QBÓM‹MQ.‹þ¹‰”¡Žu¢É mÓmƳRt0 ®1UJ1 &2Õ«Öݬ‹»êw&@™ê_ª ¦LÛŒaâMÛ5‹¾a¾èê(‰åM†©crZ)CÓkªödñ•Í×`Âh›Ø¿€8•TùGS4ôM@0žÅ‘ÜKÅêfðÔ SÓñGÉ<¬«ÔòYduë8UŸï¥[OäŒÚEŇ|Æ ‘ €Îº1Q¸ÊWœú“,›: Œ”úé®Sî¯ÚŒ3• ³— ›¸¦*V «x\D>:J÷;Š!H1Z²è§O âMêgòިㆠ §ïÓdÙD‚ñnJPÖ¹Ã,›³â Õ”v«²lªÆŸ ¸Õ¦I„¨ˆ aY’E™ê„'PÐÍD§-›en2ƒït$Ò,äøuâYØWC–Mª¦7(k6m–Í,Œ…QÌ ®o„¼¡É)CUÝæ’U¢Ò/¦ýGY¸1ƒúQrL3nfÐumËbHëNÊ$Ô~®ºE&,õ,³lšÚW#ÏZžÊt›JRT]›²Ì9ê>5k€®sŸËªÀ’U}Ťý*€}P…ieUPn¢…h ,eó™•!p#²l‚Àn™ª/˜õY(:L›Ä‡ ¨(Œ§nñÌä u€N·YÍ"á©¡B±”ßD2ž¬›úÞJsZ€n2Mr P‚ݬY6§Iw3ï&@J|"ËfÚÈ¢…~=¥ §Ñ7Ùçtïuò† N)kªTD©Ÿ ˆ§ŽƒC~£›!ËæA¯N›e“ºifeÆ"˦ Ð6Ù eaʳ2¦Yö,ù`в:ŸB*Xͪn²y›6T@žõÔ$ËxœÅxŸvêî™EÊð0ËföÏ͘eSz)î'º÷4Ë,›:`}P]åÓ<+€}P oLrT¨êL52¨iëø d¦ÑŠu–͸¾®îxU•$íe–òl3•dD€8“´…UmI«—J²Pw?S€n¢É¬šôɺÊTFe9f©3.5'­~H‡PüN·qÌJ=­]ió_LñÞLÇ å½ëôüM O“9¥óÍÕIdRä;§Y¿²TÃxõ»¦èØO“,›IàI%­99¯„‚ðHÒÊFÊuyÚµ4ÉB(¾§ÔIõ-Öx’ˆHøNjÈ3¤ìÝiŸIåM4ÊuÊ%ª¾3Ñ6§ôËŒ èC>k0®ÓŠ5Ñú¦ø¼%Y“B3UÝ*ÝlS— “Ä5i@†¢ Âæ¯k§]›]•¬ZãiR†ª{ëô¢MÊ'ÉÙ´Î8EȦžä»mR7#!K»Túé0l —¥dšçS× =uNéʤ•c¯zŸoIX;uëå˜;kuïCÊ¡+:`fhSö+– [57-ÅœgöS¸têÚ¦Ò Òu¸UïQ§±­ÓŸ¥xȪž4îtu›R å€4;@Õé¦0'&R†Ô¥,ì åhHšU˜¢œUÁÔçUul)0»`8ʽuŠ2EÕ÷©ô¦Bg\µÙRåEÊX›F0—Yœu»T@šz4O1’ÓÆCv5”iÕŠ(×(×M‚Î(î…Yݧ]ß_)€œêò“eÏQIª\4hq)ª¼×CÊœ™¤AN9-§Ê‚H²$Ö´¶4 p€æ>i⯞VÖT\µïð›ˆO³Àfɦ>ˆ”ÅÎdCÕ±B¦*' ¶Ílg¹6+‰Ãiƒ<©É}Lõª)}¬Zij茫] ˆ5QO1íƒYi ›Ê;N+OH-oªè“Å¿;«Z‘é5j,‹nóÍ’ÁtF†µðPÊPÏÔfõÓ–€™ ¨)ר§Ë ¬g*šv]0±Îwšz¢˜i€KbYÕ3L °§Î×À_éÞ׈›,RºEé ³lR˜^ÝäÖ±¼³Î²™¥ÝTÉeÐY@4…­¤êgÕ«ÔG¾×C+܈Jbûtº¯¦ ~VèCAW?SyƒЭ7½w)C ЦlS% MÖά¤Ëa–MZù›5Ë&eÉÀi’”ˆ —Yè„§õc­pã`Ve©ª(&è×€3˜G@§q€6‘24Yä§Í²9K)Ã̲™%“&…½;HÆo]U }Æó tÆ)$U›ª3®ñ³Oœ¥:ˆÔ{{¥fÙÌ¢œÐ\NÒÖ#žÒ¦W{–M*§&À¹QY6M5è§é³ÖŸ…NxZù,:ÞÀt:ã*,’V×´g¨úä†pÓuøÉÆ2ë4Êb7 7yމéõβIé÷Yø­šøgÑdÎêÊ2KyCJûL@ÞõÐãðï|õzRJá;sÎÇþ7! ¥Ä™3gð›ïü5s%¡]^û vwwSŸ-¥{öÙ³gñ›ïû5zßeu#I)ÿKù¯`±ñòXÃzOÖ@ô¿9çøòå&þý»^ý¾fáî•2v>m»»»B€1!8çQâmbŒAJÕww¿¿üA\¼ýÁô:™H¬Å~óAyÿuÿ›h4Q]Âa¤”QŒÕïìÙ³ø­ýu3ÂFñùóágP¯×Çž?ù¾ccíŒAH@0 ³áÂÂ6v]–G×)¡iÐpæ°ëÌa;¿€Íü"ºv1;7õ1W¬·ŸÆç°³³36ÓÞE8¶cþ-‹½0 W2¿ìšÈcϪ`۞ǵü®æWqµ° iYjbÁÄÈ øti|xƒärl͉ÿ Û*¥ôçÁüqñ–õÝ…þ`þ þû1ìí5£5D!ÆëŸá_xúé§ñÿ¼ïßÒÀù,’áfdÀ§±hA¸9Ë Úæ£]°Lx–ßψS2óÍ‚53q­¡NTÆÏ ‘Að¬îA5,¨zÓ³Ê 9¥P¯×ÑívÇ€dÈÂMØó¼è?öØcÀ;fþ™ìºÝn´ÁM>;þ\Ïóðè£ï…¹¯}y‰¾¿Eîá”·fPŸ¸±0Ùoa½Ãÿíº.šO} ¥;½#¯¥ Š»—ÊXŽ˜½½=ôû}€eYQÇëïûx¿×ëu”žümàY6'ÞÏÎöN4>& ߸2ù/ÞaÅ?9f¡À¨8…í±v·„çJ·âÉÅûq¡úZ€YêñM!XûÔÞÞz½c°mØ·æM®AÑ<ø»ß~êAz–Mø>ßg]€mÎE´þÆçƒëºckŒÂ_ßo°M´ÂM@ü gÀM&Âá‡ö’©G–ÐlLi’…* . Â4šâÕ…ÉçPÚ$ õ¡j뤠LAº‰x ò´ö˜$£PiCSë–UÇ;Iß]§@@)›²Yð Œo¶qð~çy^´Iïk4õK¨[»BÚÍ IDATö€û›Rôlª~ºIý4ÒŠïÃápˆƒ³x{âŒéêê*ªOüô>ôßÑÆ©‰[WÒ{¯ ÖÈXÙï8ÀJ2|â¹\Æjó ^ºrÝS§Õë¢kÊÝ|w²&š­vôÞã†AÜŒÁ8ðèõzúµÚàøqà›ñ¹g!ãkw¼|Rã§Iáß9·‹Ó½]Ü¿}ßÏÿ#ÎÕîÂã«o‹K÷ŒßS§‰­;…ÕHÏ…kÀäØ˜4ޱ²ImãVÀrÇA=ç9·×užÂ=[Ob3·ˆ/žün\X9M“ÌÑàK8æœGõ‹ÞaŒežñ1W.—±ÚæÁÉÓûOt‰øRæÇÝl¯µh6;‰dDœIš§œs„+…ŒSéŒëNÕÙDY zßÿÀu“C§éyøI?âÈ¢KÑÑMZ¸LS_ÀÒE†êc`¤°T™FjY Y×9 tê4¿M5©ߧ.:ýñ$À®Ó«N*¯Ó“ý= pÕsc¿ Á'Nœ€çyX__‡eYÈårØÜÜD§ÓÁÊÊÊ ¨¥6UÏŒý&Ü@àØ±cûž½¾¾ŽN§ƒÕÕUxž‡Á` ž;Ô¾ôúð±ï˜x‡÷"zb)%jµ …:ºÝ.À¶í±Í»Ûí¢^¯Ã², ¬¬¬`á›ŸÃÆwÿÀ²³éƒ«æ”P¬ccFÖêê*8çØÚÚc,I!+è8vvvÐl6Q©TÀÃñãÇQûò'ÑýÉMÏ09w&ÙïÁóÌSù|sss ØÛÛƒeYÑq{Ø·¹\—/_F§ÓÁòò2„¾AÄ2¬ï)Ÿø˜Â± ]Pb€{²Ý–eE}麮?ƒ²ŽãDßÏ7×ð¡‹[<€/=ðŸƒÛõž °$?µ çÁææfÔ¶°½aÝ[­Æø<øú'ÑýØ¿N'ª¤æ»8€ðayÐï÷Q(¢y®a;Ž!ÇÁ•+WÐjµ¢y0 ö뢫4Àu¸Ô"”Õ ?ÜPNeÆM<¹žE>(MqSׯ;Ëï@8¦NßvU%1Tf|–áYî£ ü̪W­9ú%•7}¶«K8BàŒp3ºxñ"êõ:G€Ggxû%þ½„g¿ôÒKØ žÍ9à­37¯çkX@íV'Úã,áØpŒ•«W¯n»í6 , ‹òùGнç½é*1&ãÝù Ù5Ïó"€1éoþ X[[Ãòò2jµqäë_ÆVs ^õHúºB¬ß¢ìâmîtÜ!8ç(‹û™ÉX߆cãòåËØÙÙAµZ…”2u³Ú'Æú‰sXŒù¬©e±> O@F>Ð2¼&`{{ý~óóóQ›âó6|W¶m£X,¢T*¡X,F'i¡QܪT*n¹ô(\¿ˆ¯~ïÿîÓ {Š”aÊø Û‚ÿð]LÆ=„s9i¬LÎ ½«` &YDï`kètüyP(öÍxÜFÚ<‡Ù‚5e†zS‚Qo:®k”Íóð££×ˆ›>?«¯8…ÅW°¤†èŒ¿i’ô˜^ËÄuЋ @Ï’xE7ÎLê6^5@Oª£¢®ëÂu]ÀúúzÄ…ÐÃ? !ÞúÖ·Žú4ŽZ·Û‚ðõu!°±±]øá‡Á9Ç[ÞüæÈ÷‘ °MúN ùöÁó@Þw?)‹xh6›cõ³ Ãáç΃ã88~ü8c8yò$.|ëÏÆ¸®3ÒÜ -)%677!„ÀÚÚÚ~CBJˆ àì…^@·ÛE©T‚ã8X]^ÄË_ù?ð³éò•D?ðïê< ‡;­V*:†Ã!®\¹2^,æÎñÈ#Àó<<ðÀ ›åúîºnÔëëRâÚµkcì.pöÌY¬¯¯G¿Ÿtɰ- …b•JÕjËËË8uêŽ;Çqàº.úý¾äƒç‡Ãˆ}-•J°, ·^þ–®žÅÃïüil¿OM̘nÆú$ÆBlmn Žk×®RF·{úé§qæÌpÎ#£8Þö°lÛF.—‹Ú~äÈ<ð†püØq4›M´Ûmض~¿Á`Çqà8ª U[w~öÅó?ü?Ñ Ý56nhÄç”22”“|ûëõ:^xáôz=”J%ض£Ë‹¸ôõO¡ñ៥]*ä ?à>‡\a»ÞŠ ÷n·;šu ÿ>òÈ#p]§OŸN> J3†ub–`Í›FÅT«ôÐ_|v@üf̲9­Ñ@ã”,›”ɨ ìRõÉõȲ©cѧ,&²q:@§Ëšþ ô¸“€$gc~Íá±gèo8x(x* ÌF›>bŒaÈ„RÈι®›]ÈT¶ ‡xƒû:®ßN.1È›››c>¥ñ¿Žã`uuW¯^Åîî.°´¸„ù¯|»ýd¡2;E¡¼8{›¦nð……,ÔjØÙÙA·ÛE¡PÀ±cÇP{ôÑø¾X9ý:–Ò6Gr¼¿÷<ðÇ^±XŒ766F€n€‡î(qÿô1>ƒ,›áý„AP\èÍÀ˜_—gŸ}Ï>û,8ç9é·.„SŒ‰^ZZÂÞðÜu×] èn)ƒÁœóȨZ­Í&Þ󗿈o½çã¸t÷w©ç—ÊmQa(ÇO .ü¶° ÿŸ ÚlÛ6NŸ>Ó§OïsC±c,{ä>Ôëõ°³³ƒo>ú*ss8qâæææ"67T) Èò¨Uk8qþ¬?ûE4îý€Ú¸Èe3>^Â:NúõÇÿ»V«aaa;;;8yò$ ùŽ=ŠÚ7ÿïùG€£ïÏß9àx?¿€~ß|ÌC‚#œÑüŒ©îÄçAhzž§6(ZáP¯!J¢ð¦aÀ))¨¡è ÿæÃÏÔGŽSƒäi³lêNG¤†Á¥dÙ¤0SÔë¯æ,›:p<+€~#uÆ'®…Á=þmýÆAeG ýŒäÇÀŠÅ „;"v'ýa0µ]³2ŒÞл€"“h4[‘( ]´Z­ÑÆÛЋÅ"r¹^óš×àÚµk¸zõ*æççá8–çJØxâ3è½ódz뛜&Åüí'%ÌÆïb.ðÓŽŸ8çž{›››8~ü8ŠÅ"Žä¶ÿ zoH?‡SŒÁ·w_@•y¾ô ÷XxR¯×ÇØ>_ò@’B?Øxøq­'¬ïãœ9H)FóAJœ;Ï?ÿ<c¸÷Þ{ñú׿~HšT O™ƒZ­¶··Ñétðõ¯?þ8n»ývÜùÚׂ1D†h·ÛE.—C.ï3ÉB¼é‹ÿÐmáÒpvDÛB q`ºµ¹9jóë^w8“ ÿÙ¶ &F~Ô•Jsssà§N¡^¯cwwý~åJÜóçÒÞÞ8ç8~ü8,Ëòã%þâ—ÐxÝhb×âþ÷á'îâ!!Ç‚3àÄÄ<(•J8âpl=ñôÞöPú­Ñù~kÿ<mF32HÂõ8”gMb¿%ö¢œs½; ê4}Ö:ã7€›Jšjz~f ©ï‚’$(k–M‚ïšàSYä,R†¦>âY¯™Ê®™dÙÔ-.Y|Çg™(«ÎxÖgOl¼qu )$$l¨q²8à4®ßDÝB`÷©ôû 7¥h“!¶+“q’Pö­Ýg ÏõP*—à}ÿØõõulooc8Âqœ1ÅŒjµý›ŸŸG½^Ü N:…û“Ϫ[â\Ž;cAq<ß<€óóó(—ËØÞÞÆòò2lÇÁÉ'ðòg<¨§€±º¼¯ù4„í›—Š¥L¯¯¯G `ĪF*þMÂ1W„0>ýT¬ïáIϤŠI8.···!¥ÄÝwÝ…;ïº Ãáp\°\X÷Í®T*XYYÁí·ßØk4pmm kW¯¢ÕlàäÉ“XXXŒb1z½zý>J/õââ"îýòo ï±yÿ‡è؃€CÂyÍckA€s!°¸¸ˆ»ï¾C×Ãïÿþ'Ñj·—Ù\.‡ååeÜ{クçž{°¸°Ë¶Q­V±··‡ápõI.8Qº|ù²o ./£\.£¼}…ËOcpËjÜc˜I3<½’2…œh§„÷‚¿ÀõçA Û;þm–Í ÌžQzz ò,àšr, a€Ù_ƾóµfù`R„¨cŸºGxDm\¿„¶yÜgÓÃà´Éä?áæ3ékš¹ý†}·È›¸Ã»ŠÎ0Nsr‘1ðâ‹/Fê óóóc²„¡šã88zô(Ο?ÝÝ],--¡V«aþɇÑܽ ¾x’~zCIN¥è#\ìcÀÃë­V+r û{eeh4XXX@­VÃòó¡ñÒSpo{ƒñIÙƒ5ÜÊëh¶{ð\¹ùú½>Ú6Î;ßJ¥‚b±¸o؆ctlLdÉ„œbÄp—C Ç_|Üyž‡jµŠÛï¸ÃáŸúÔ§Æ%à&€h¡P@­VÃêê*n¹åY=‚b¡Û¶QŸGõž{Ðn·±¹¹‰k×ÖáºjµZˆý>ý>æææP,°¼´„{>÷¿£»t í÷š‘€ 2fx 9VJ /0–Zí6ðoÿ˜t‡p» ¬_~ÛÏ~/?ñ7¸ÿhwÞy'òù<æççGô –ãÇãÅ_Ä¥K—¢àÎJ¥‚ÜÓƒÁkЃZƒk!+Ïœs4›M ƒ±àôååll¬Gó Z­bé¹ÇиôÜ×¼A˾¿c°†ÛdÍfÏwmsô}´Z-<÷Üs)R.—ǔέRŒ¯ËT€MÙÿ¨eoÐËQYm”С›Š97ØÐZÞqi» ¬·©Š8ŽK‹é¤¤ÒN‘9£H RúV'£˜æ×'c^¤|?ù^L$ ™âþIïV'G•¦Rri+Ês&~7Æ—”`A eèÓú¬Æ5SŸ‘Öo)móõw9ŸÇRu·|êŸãÜ'þ¼8GÇ!2e>H€{M9}‡è~wÓp ÀKó±5eÆ),Ýá‡Î fqSÐgî‚tª˜eÓ S© LólS)ÃY0ÜPÔ_Ŭ鎾Ef< (Š”> ûo'õ‘0`jÓÊSÜh4eÃãÿ8»²¥¡Ojø»Ð?2µ}PÔ/¡¾šˆŸñ-|ΤO5c ƒ˜‘ 4è(èiï4aΟn>‰¡5D¿?Àüüz½lËÂsÏ=‡v»ÕÕU,-.¢Óé ^¯cye µZäè89äó9ÌÏÏG™(óùh?zô(ÖÖÖÐé´Q.—±¼´ŒÚãvc ¢v„°]s[8ÝyÀè* èv»ØØôöÅÅň‰dŒEc3ÒÞ#âcã1ëÚ™ðñO&ã ©8){ÊUÿn…Àßô=à†B ýÄ_áÊßþ.î¸ôn»õ6=z4 ¸l4šh5[‡¨”+(—Êh6š‘ùüü<*• Ž5¯aû³ÿ[?ú/²ï1ò(zô(<ÏÃîî.„(•J˜o­Á¹øw³7ªïc:àñ´Ú®;„;Âu]Ôëu´;m‹EÌWç‰(1N±X„ã8˜«TÐív}…Ç—b+<üÉýsWQ‡w7žB>ç ÕjAJv»íí4{XYYã8(‹(•ËÈçóc>°“[ãò™‰ëu­š˜kþ}=ðp^xnÀˆgFt]Þ¤" eXpßòýØûïÿgÿáoá©>.\8f³ !%Êe_òѺèv}×–…Å…(1N§ãkÑ/,,àÈ£Šüú…ìû_ìÝ Ýzý^ ‡èFsÒÿ'¢ LÏã㱓YšŒ1açðòý?¨«¸®€Á¶5é·‡ó‘ÿ³eY»ëé{UÒs‘b˜Çî®w^\±&&9Øn·‘ÏçQ­V!„@>—ÃüÜŠ…bäÇÍÛÁêÒò_þ¤:ßÀ„1øöúãÈÛ¤”èv»h5[hµÛ‘1–Ë9(ŠÈåòàbt*!bëp8ÆPXÊ^O9åg)ýF-{Ã84ƒñ 4S<ÛÔñì@œMqŸ4ÅQ› `«2¦©²îI" ”¦U¦©#õÀD÷½)[_&€N¹ @"¥|Fã`´yàx´AųÂ1Ð*–ŸX?›a°©{œÃsƒzðÿß©§ 4Ÿ|"8ýîãèvºA?¹Ü * …†î.\€ûæÁÖßµ/´”GVŽDYECVñèÑ£Èã§7R3öb=ÏÃp8 þŒ­n· ‰ZµŠB>§ž~ —;£ðžçáèÑ£°,+JsìØ1T¾ú) TÅ‘ê¹ïpoÙ} ½ {(cþ½ºÝ†JÅ7d.6‡èv:«—Ïç‘Ë傱é˜?9¥æ4™¸vzÜÝñ±éq7ƒqîqOr¨ø o}îñÌ-ïò3|AåryLf.çøAÍF;;;p=¶mayq•OÿòôXE"0:ø Žøy2LÚÄGë@Úž“°~_[¹Û÷éî!¥€à®ça0F2£ívÛ®çw›É Šç&í±ëQâ©Øõ\ÃáívBÔj¾«ÏSO=…Km×s!¤?V4Ì…à8zô(*_ýwþ<`)äZì;Gzxpø<†ý><Ïó×á0zv¹\Æã?Žëtºh¼òyäóyŒ­…‚‹ýó€i_8×lv0ž³àºAq:eÐÍò˜àˆÞGf`ÄÓ˜k]šYÓ-5GÛiÌUʆžÈD¨®3Íu ®ÿ:Ã4ïeZ€žmÝ×ßÓlh@æÄwþ‘r¸ÙzÐäÁæË,ß\ 1~䮪cÚõ é¹\ot„çAð˜ê#­j§ÔMut-Kx¸»þ$úÁ&é8ŽŸBœsl».*• 8ç¸$³Á;ÿ6o?†®‹N×O(³··‡þ`jöz=t:pα²¼‚ÒSŸ¼aºAiòÞ5÷cwèFÿÍňÍe€Ï¶q‹/âÅ;¿'Ò¤3A‹Åˆ-‹X±†ÈÿݧIó÷ôîỶ>vvvŽºÝ.z½^ ìâÌ™3xþöïB¯×ƒ€°Ðó¸o(F>ÉGÕ:‘¶v¦¬‘êz# è pþ·7Ä3ï!€ÊqõÇ~/¾ùG±½½Á †\.1Äžç¡R© T.akk íVœ Tçç1ÿä_ÁÞ]›zïóÜѸð<žëEÏö<¾ÏÜôd¿YX„纺C ¾!è¹.¸çKRƒhî÷ú}§ öÑ£ v}0D’ÃÁ0x¦ºßäóypÎñ /àÂ]Ä`0ŒÚm1æ»NÅæÁ2øó OôÍ}{O£ìv±µ³~€N§ƒv»N·ƒJ¥‚ápˆ'Ÿ|ÏœzzÝ®?_=ÜñâÉË|uš ƒ( O¦íé ž"HøžŸ-žÅÍdZ}èš2{ .1×äižO=^¥º¦èØb¦ø Óln¦¬·Ìxz `¢›tp'°•d€oZ>À¹ž”î·{p9÷Ý@ l±@ 0?©X'Å•Ž<×õA¸ëy]/ÚPÆ$Ð’6}¤€}“$G)}r{ãÛ(z=4›QÂÏ |Dý,¡•r®ëâÌ™³Àkß,ߊAi ëów`8ðÁz¿ß÷U#¤À‘#Gü,ƒ[Û¾xÞAÕò;óùt°HQ›!v®ëbè}v7‘®œí^"2t`÷­…Ç쵂Œ•œ{‹âÄ þö·HÆò[7¿îyèõúÈ…Á—ͦ¯¥Î9Î;8yì¼ù! …˜û“ ]8çà‚›¯s*w¯¸¡c…A¸Í ×Ýï‚2ùƒ?ƒ­;ÞF£ .|ƒHÛ²£Û,//c0`{{®ç²,ÌWJÈõO¦Þö >1lÛŽúGJ‰ãÇ£ð…ßJg¾ckÿÛwƒëùîE¹Xðe³ÙçÏ?ÿ<àä±ý¦‡P(ý:†®Þhm ý¾ãy”™©ßò·Œîo”i€øA¸¦LëoþÄM´ ³®:÷Ž, ÁÌOœòlŠï-4€ Fˆ›l¾”zP:2ô¤c? ã ¨ÕV2–÷]?|Õ‡øæ+°B’euLsœ•õ¼€}rÇÙÅàoänÀSÜ T€©oxìs÷æ£àR`0ÂuÈ9Ç¥K—Ð ÝOŠ ‡.._¾ ¼ãcѽ^:övßw=8YäjµŠ|¾€Fc/Ê蹺ºŠü£Doмw…±nà>㰜‹ù7{cý,æV°þÚ÷ùÁ†BÀu‡¾ZEÅF õΗ6žƒýÒÓÊyxrïEœla·¾ëƒŸõû}”Jex®‹ÇxïÃ-/øê1C0¬›eä> &}‘a¸~%Ô7c܉¾k–€'ø¸ßp0?HÏ"í× Ï|ègÑ·rètº~€l˜|(Ð|.•J(K¾®|¯ïËã--Áyô?NÀù¸ÛIè.¸o˜ÉXÆDC\C(æÅ î/"{Î9z½>666À9ÇüüKæócñг`ÖÓÞ·Hy¾‰+KÒ‚%R·´ß0ØÉr=+د Âæ« èѹÿ¤!"@WÝÛÄO†,t¬|è[ËyUÍ YQÿo˜ E¹ñÊlßyÞ(ÈË 6î6‰Oÿ"c¿(Œ–¢ÛÆ-õo£×í‚’|®;÷<\¼xžë¡27çg Øp¼ýÇ¢g\>þ \?‘F·×‹´‡«Õy #_Óùùy”žÿX{wÿ{ê÷¦7J/^̵g4Ä>àŽ¨}éÞø· ú¿Ûí‚YVdTX–¯áœûë_^Gî( IDATWε7¯=)%ZÍ,‹¡Ûí`oo­V Œ›››¾"ÎG>á»d<2CßWejœ0Mˆ„ø6±vF¬/瞤Á¼ˆûïc)Ćb¯–pù­?¹;¡&ÿlÕjU Ôëu!PÈ‘¿tlocJŠNcÂw&Ñâb”·iØî$µ6+oPËÏðcÍì.’up“¬kâÉRÑÈÉrº †:CaÚû|§2âH£Ö/ÍbŸ¼Në”)6’4€+&€»L±fã÷MÓÒ•°žæ'DzМ&¨® ë% 9ÉmA¤5"¥Óú2þìxÿ‰ Ò¤±t´wšô]XˆÀnäÎÇ¡8Î9ÇÉ“'“ûRõHh‹jµ*†¡ßiès+8¸ç³›‘â##wƒ´÷Dé—´ºÅÞËÁ†ˆ@²¯È"ÐlµP¯×ýcÿ¹ <ÏÅùóç»Þ ,žŠê6(,`cñî(a‰;Dþ´+++€ípáë…׿+È}óÏ’Ç‚â½iÇÍÄx1Ž^@8b{c \Œ$æËw¢¾zO•OŒµÏÂú‰J$VVV0ÿÔgÁZÛ‰Ïë×qwýY4›M¸®h¤»è÷ûQ6¿§žz xÝ»€;Þ D c+E`¨ÉûÌEJL‚€ÚG>i®bdzk‚ßG~¢ªP™GÄ’Rq!èë{Úû™ø¼tÿ÷N.?>`•pl‚sÔj50ư»»ë2øªö¹oNµ½…íöÛéeŸ ÇDtâ,ë$´ëäîyä ù(®ÄÂh·;¸xñ"†Ã!ªÕ*ŠÅbä–7~w2VJa˜÷aš„S¡Ð×Ûu]¸Ü H€X[C•bP+þÖõ½Pôuü¨î¡ziߥ¬ !Óã¶™ÿ8÷ƒ~‚Ž4i[n¹wþÙ÷àèê06J“Ì|ÑpXÁ_¦Üì=,,-‚YöÈíDø@ƒspßR" 4Ú§sKÐ'i€O¼÷;6‰\5 ÅB˜eãòåËè÷û¨T*¾o¦ëamm øÉ¶ï½^>ñN,mžŒYº¾¬š^‹è´ÛpƒdGËËËXÿÆaøþëëG!JRtë㮌Y‘[Š ÀWèß« ¯œ~÷^=cÃá¶c£Ýj²}./bï ¿ ÷‡ÿ龺¾þå‡áXÀÖî.c~ÐY«…N§ƒ¹ùy´ÛmlllÿÙ/ÕUJá ÎfZñ± qícI˜kiëÜÄ:Å È0Cl0À bî'c’šö^“ÝtXªa÷ø}X¹ú4'‹10Ë‚à–mE‰[ÂdOÅbìÜ7·$;Î=BŒô±y,è5œã¡/¸ëLŒY›ñæµoD®OùB‚ ô}<óíoc{{…B«««BàÚµkÖŽoüPr2Íɱ¢N\p@HØžï_Ï…ê4¿êKü0^õlv]׃ãØhµÚÈåspl«‹5ìýíïÂû‘ºïýÞwù+ÈÙ ë[»ûÝA§ÝF§ÝAµZE»ÝÆúú:ð÷ÿÏQ]¹o¤9R:‘œk£ôuð' "ÕÉ;K ›%û¥•Ÿ1Q;[”¤c’4÷‘¤,Ui¿i›)ŽÂL€¸J[óð£à”(|Ý}¨J(iÏOs}0ý=åw€ÞÝ„ãC¿n€.sB9•!`*qÌ^NnZ¥@„êñ<}f/<ê\^^F±XŒØŸååeÌÍUÐëõÑïûÿƒ¯*0ú 1=q!dÄF,“”ØÙÞÁúµkð<år9–ö;x~ `%ºÚfÔ/ ¨µ×°Òz ®¯Tb[a°•‹+W®@ŽJ¥)¥Ÿ…1ßýdâ^;ñNé³majúp ÓŒ7›MH)Q.•PÙxÖúy²JKª§«Üg•½€õ±Ó.bZïÁ=6n{úåe F¶Ûé ïä`1+`ÆŽ;†â—o$IÔÓö\œÞx ÝnÃáù|îÐ×R}·žóç΋ÇwýhTW(î„cÒ—¾‹ù€#t…鯖É:ï§ Oi^‡Úô"H÷ÉrRöJ¢âö©Ó`Ì‚”¡žÿ#¿nÅb)ÊÚÈ÷åý®žŸŽçþÉ“c€Ç²F ¸Ò•ø!.»çð}Oý;,ºÍ ÐÒƒÍ,4[M|ûÛ߯úú:r¹Ž;†ùùy4[-ß°ý±ØVºG€ +)0 NyBáùîE“2“cɆ°yçƒT–¢1ßív|)–0êØ±c(=̃XY›»¸÷ê×Ð TMò9´Úm ‚€ÐçŸ~4‚²¡ä£ˆ´ØÅØÚè“ ƒ÷™òˆåÓ<n×¥‰WdU§èuOâ‡A›æï~– *YüÅ©>ˆ Ä%aC¤$Ú¡HšÊªü¾up¦p§=_‚&ÇM'\§Û®(?¹éÄÁx˜4faaýÁÃÁ `exLºp\¥"<ÉM|<_zÌ TWÂD/RJ ýÄM&€K…ñ¢ê¿”~¹íÚWø:£tç\DjŒYA˜À¥K—€»ß ÔŽï»× °€Íå{}IG15RJ,,,À²-ìííEÁSµZ N\ܤmDÃ.t3ᑳ{oáw“ZïÒv°vÿGF÷‚Œ‰…b! Æ,‹XFö·Æ% ï¸ú ”y[ÛÛà*L§ÛõƒÎÊe ]ç/œ¾ïgÛI6 ãc’RÏû>Ñ"ù½Rs$ $ƒòbGÿ"¾qõ‰Tt–a}Ÿ(ßX½,`ÛG†R`ˆpR©h·Ú\ ŸÏ[—¦à"¦6k¯’3z7RJ¬®®&â‹{(ôš8²ùú¸‹@Èåž/1)& щ¬»ÒrpõôG¢yú~‡.3RJ‹E,ŠÎþy°ö(*¼íímxÜÏ¢ÚétÐïõP)—1} ÿ `9#cÇ À ƒh „O ÊÓï4)BÀ†‚ì¡—„3…5¡r÷ g’®)¦iêuÏ?tM13f(îªûHÃû¨Þ½êÄÃÔ5%mÌL›Î^çÞÁˆm£º™èØEÝ<Êò=ÇåIí0¹7ÓÙ²Ûè»zˆ íƒ,&ý¾¢ëg),•‚ÀLÿe„>âc®(Ñqu˜&œ±Êáæf:ô<ÝnÍf3ª¼Œ!1én Ú’üla]”¯YûªÏ8rŽ|.ç'~põêU ‡C”J% pîùnúRÁþÚ©÷`iãéh“ôS`ûî¥b Nƒ¡¯¾°°€kßüS è_"B:ª„ºŽ„€òXj÷ðÝG "î‚{ÖÚë?‚S~22°ºÝn”5ÌŒyâÄ ¬}þ×ÁßñPôÌû^þ<£ßë¡TòJ³ÑD§ÓA>Ÿ÷™N'|ïOµw膌w8~¢ï'ÞÓN• ÖÒàHø)c¿QºÁLŽIÓu>e½êέúÆEþ$ 1üù|RÊH“ÝqlÈõé´ÀãýÍ‹ú"loX¹ðw'OœÀÿóƒX^^ŽµÃ¿Žã ¬RJlµZ‘»Œëºèõzèõz¨V«¨ÎWÁ,†v»çŸÊ ðó0Kïi‚UBC#L$$lÛk{8B¹¿Éw´vú#8ùµßƒgw»Ý(I™ŸÓŸëõëàï|(*{ï hß÷Q*–Ðëw£yP,qõê|ø§Ç¢¡kÐþy°o*\´ã/m¿¡”¿©2a2F\çšBaÐu á0ËæÍអs¡2ëÔû¨2]2L—e“%à`²lRÚÆfp-ÉžV#œžÄ‡ªó-‘)ºF C¾Øq¦%áñBÈ10¥¬þFGºÊJ”ò>ü$àp]NÆÞ(Û^°Aú÷7"™Îfz L¦¬«;Ï 2¨£Ûë h†*[[[RbnnP¯×}€ðÖ¦n@ë§Þ¸¡xBÇÔ~fÑZ­!D”Š:—Ï¡Òß}î+¤S ­´^¸ ™´I—#c=yŠÔ¤[ZÄÖ]ˆŽÚçÈår(•‚`Lîg¬­= öÒÀ‘Ígq¤s»»~â!ý$(ƒáår>6ø\XX@¡²bJ,,. T*ù.hqW´þ½^{{{¸víÚHá&H"ÓëõÐô‘Ëå°¼²f1\»v O<ñ:+·¿ø×Àò sìCÄV<OAÀeh¹xp/9Û'ÜÊ"¶_÷ÁHŸsŽ|>R©¹¦T«UT¯<vé Àüy°Ò^‹‚fý“¾!†îåržçáܹó£y«óh]cì{Øx?VB¤€Ôä<yBŠKÜ eÀ%éÎÂ2³ ÷Õ±`:ë ¦  ä ¿>Œ8…ÅU1âÐ0‚ÔÓ“¤k’x$5“[âu×UÌð¬®é_MØõitÙï”÷&|„1 #\‚o¾êB·Û@Øä†¨Œ1c–eÁ¶mÿ¯eò-,-.¢T |ÀƒºIŒØ÷àé㈰•óÀk®> f®;„c;‘Ò@«ÙŒßùùy!põêUàž÷ÕÕÔg¸ù¶VîÃÊÆSpœ#bžçææà8Úí6ªÕ*`aaõ¯ÿø=ïS2xJEÄ7ï°R,¯môûüªƒ{®½á£Xyæ/£ãî~¿ýÍå|_ØãÇŽcï¯ îǯ{á¯!%Ðl¶ËåÐëvÑjµÐëöP[¨¡^¯£ÛíFÒƒñ÷*cc‰ ‹ùZÇ Á©Š?IÑž”¥´%œ’ˆ0ÀSÛ‚þaÁó÷1ðª`wêÉrì7Ü.Dvþ{âa¤©‘„óBJ ô;3cÀ-ËŽù¥R Žã`0¶ض .ÉàÏ])Ë÷Ñ·, ¹\ù|ù\ýAí p4|ÆÆú:.\¸€ëþ‡ÀÇÿ X6cYUƒ eùXIøZðÐØOóï_{ËG±rö/}#Ë æD0€“ËÁ $ ÷>÷«ðþ«_Ã=ç?hµZÈçóèöü“¾N§ƒ………h]ÅG>±o¼ÆëžLDÁ˜##U7ÿ™b¿6aÊØ b6.(’0ÑT 'i,Ý´@q14=>p§ˆëˆGÏ´;Ý.ì\9lj6~¿ªãG¬‰ 8ì½d{}œ\®ðåöì¼¹álln |Õ …BÍr øþ©Ië¯y/–ןÜç«É˜…J¹‚F³Ápˆ|.‡¹¹9žú û PÑ%éò ï]ÆØÔн!<Š3ûxði¯ÞƒÖñû0·v–e ^ÏÃÐu‘s¬YÁ±ó_@sç"nß>ƒ½v;J ÓëõÐï÷aÙ¾ËÑÅ‹{ÞÜñ–}ãÒ?ý‘FÌó˜úƒŒ-I*DŠ„(‰}¤‘þ¶Ï|3*ŒRL…R¿v¦­¶K é#0$FšÝa_ÅõѧaÀC0Ê аσ—Û±á] yKÅ ˜å7ØÔZ˜eùêtÑ-„@§ÓA½^G.—ƒçy8sæ :ýð®þÓ ¼æ>5Q)¡°”SÃ|$b*"QÒ©À+•Lˆ=§}ü4O܇¹+gÁò9¸®‹R¹„‚Çá‡Èå¬,¯àØó_@k÷"nÝx Í^7 6ïõºô‘ W4î|˾5MNº]Ir,@=ÕE×/”}ÐÊÚo·4À(mÑL³Ú4º¡$i8(g)•Îw-é4õ;ÿNâи'0Ð|‘«6ÝóaŒYÐg¯„â¾”g«Údri ݆)'@oã"5Æ´®îºñ 4 HwoI¨»2ò·––ˆX>ê{{ØÝÝõWªXXXáÆÆ‡•Å`ù»±ÏhƒY,ŽÈ–ð>@pÀ ‡Cär¹ˆ0ð.Ñ ¡êàOn&±ß¸ö äĽÞÒgö¸/¸×hD¬5cÌw?±làM©ß €ÍSâîoü0Ï×>ö\¶cÁ¶-TkUì5öÐj6±´´Û¶Qq$zO|Þ;~"yÌ*€ãXÛ’|Àc 'çL²12ú7.C8æ þÀ⮫g|6Îbà® Çq|-cfÁ²-[^Ä}ÿ+Àá¨×wáØ6úý>Z­úý>æççÑï÷°³³üÔ›8Â1É ÆÆdøÿEÀ+OãÒÖÅõ‘ÌaÀ@3+`Ýå¾qÅ)¨ïÓöçcÛöü¬‘2rÊ1 b‘mÛ†žë…òT'Ññ>÷Á'[ ßW»Õjaqq1œÒ‘d) N¶ry…BÅ|BJ =¬¯¯£ÕjáèÑ£°mKox7ú?ù‹àw¼) ÐìgÀJ‘޹”¶=:M@ OÀsëoù(^{Ùï`Œ»ž?º]ض˱pli¯ÿÛ_,]89'˜môú=ÌÏÏ£ÛíújJ?õˉ{ÆÈÈ |óÁ‚ù71àVŽÓËÉ=/‰”Uá‚›ÊD†0Å–Ž^ñÙ:-iË€Q7i»<âF̸‰¸Ž% ž`˜hŠÇ¿лž$ÝW•6š)€{šò‹ªÍTö[ÕïºkIý¥Ó!q!)ÏÄ K£?.¥ïjú¹ŽÎ4ý­·Óñ%ùjµªóU.bì#mÂ`g°,_¯Y𠃦ðÝX¬Ñï "MaÆ|·”B¡)‚caŒülGÝ ’YmÕÉQüÔ•/'ÜgøÚl41ÆÌÙ/×Ö®¯û 0¿’®ÃfŸ,T±»úF,¯?'çûí2‘óæóyôz½(¸qaa{þ¡À¡ià<å”`,¨QÄü™ã."æê“0nvïú_þ ³ã×=ÐEÏ99¸žÛöUbÜÍ—±RÅ€ýîv:ô÷]xïühâ:#!Ç‚výLÁOÂñ0ø¤uK·¿Æ®û.€dÒGlÁ™èŽ8&gk7áÄ­ÐÙ…e1x^Ðh)!£ßI HéJáû‚£Pž*(.Œ{RÀ†5vÒÀHưW¯£¾·Á9Z­Vì4EF}Á˜ot;– 'ŸCuÞO®Ón·ƒqÆá89¬vw±ôÛ?öÂ¥ÿc¸ ÇÌOö3`%º]I ›.(\@²q¹ÔD÷¢à¿w^÷]xÍÜ Xg¹\ÎWõ©TÏûóÀb*ssð6^Æ&³ÁP.•Ðív}‰Ó >&š~4qŸ‹À¶œ<ù_Çêji¼$€tY^6aÐ'ýö½f›ˆлŸ˜ljT°i’ž¬®-SL„ÃÏ 4 Î$IÐ4.*€ÚEÃä'ëo¨Ï‘3¾–Å}Eå_®úoÝœbVp²x¸°c´‰†ºÃaæ8ÇqP­V!¤ÄãßúÖþ¤8>«««X]]ÅÂÂ",ËB¡PÐj·GL(ÂcÖd·ˆÔ`!8õO±·ƒÕ³ð¤&lÛ \p$vwwÁ¹¯³œ/ä!„ÀînøÁé×ôà³qÛû°tí[¾kG\Ã' -T*Ôëuô} E”ÊEä_øõ5ÈÅÉóJÅð)úÄ÷ñ>ÈŒ±ÊQÀkl $[i9Ø|àGpòk¿°Ã ç¨V«h4B —ËEÇûóóóB`·^G¯ßÇÜÜ<ÏÅÚÚ5àïýà8j?÷€±´˜5î1@ŒÕÇô"æc )Så‰ßGÒÖO¦9™¨s¹¹ËòO‰ü%&ýä1L"’ ƒ1ûý>°|rªýu¿»—Hýç{õ=Ôë»Rú·µ|%4Â-XV¨~Äày®l8ô“P-,, Ûí‚sÛ–( °]òÉ¿ÄkÏ<ŒËÿѹïý4¬“ÖF V’ñ Zùý‡.#ƒ/ݽH:6ÞòN|ñ7à8N´NV«µ(°ÚÉå|w!î¡Z­BJ‰úÞú½p‰¼~ü|éÁ„=]Æ N)dlŒÄ­?Â< |Ï„jÚú2cŽÙp]ö<7t)Ã4_q]'Rm}˜es6ãh–Y6a0ùL܉T•2¦³dÙÔIŠ™\Ï’eS²Û&àèª׌xÄ|ke A;v–qÿà%ÿ%æ¥xw› 8ù;o‹ØM_²í;5¹ÃÈô¾W`•D!€“W¾Û²Ðíõæþ”Rbàá¹¾tZ¥RÃn}×׫~Ó¨ÑX3v^ó^¸_û%0΃€T ˲‘Ï;˜››ÃÞÞÚ­6Š…"lfc¾RA÷±?‚÷½?§>e¤œž$0à‘¸Åßë˜_u 0Þ¼ÿ‡qâ¿70̺ÝlËB©TçŠÅúª2†Ý½=l¬¯#ŸÏƒ1†íímË>ôq ‘4’®±zÉ Ð˜ºGNm€ËXõöÇ6HHºè‚j^&´¿¶yV ‹n1kÄ~ìt:R¢/D‰žpË­zÉMgùˬ†ÕêõºBDà;Œ‘O,,K‚ó0®€™Ëå£|¹\ËËKè÷ð\ÏwW³,”ŠE ×Ãêoü 6þË_F÷ß›NÞèNôUs%T¹ãɔ“8s!.û§2t7ßôC8ñ•߉$ û½lÛÏvÆŒD¯Ü²PßÙ™˜;þ<øðÇS]F"¶;ø?Ä A©#ð¨8NñÓà”›F\çzbÒX•$ëRY«˜vSo ÄC•i4¥gᚢb–XF ÄU Zåw ÐRz`i•H7 NÍ¢”’òÞ¥†Q—ÂÉ,tÚ£ɵZ ÷È"L©¬‰ ÊD¹[®~)b¼òù|”Ü¥ßëCp…B|ÆêÞ•EZ6NxùyÔ½ Ë×¾é³eÒ÷;µmŽ“C¡PÀ`0÷pâNú:’ÔæØÜö•VƯó@z²Z­BÇç ÑíŒ|/H€³··Î9*• ,ËB/ÐÖÆëÞ5Ý>¡i{x–:Vl¨­§ßqúý¨?ô³°ÿÿö¾-Ȳë,ï[kßNwOß§oÓ#ɲ±- ¨ÆXHÈ`ÀŠ ©")EÊU!•Jü¤à!¼„Tòàœ½Ôb} O(Öî¼ÏDþg)Àð¸ÎYÆœ–ß{À°ÿpcÙ…õf¢ƒå›_βʅAÆ8ÀÍ&À€3cc '‡]EYöº”׺Ñh Ñl¢Ùl¢Õj¡Ýn'ÿ”ïkJ5¶¹¹©ÒÐŒôÑ-zž‡‘ZMe;/þ/ îä³›ˆ‚±0µ¿È`ß§èHý¸¥Ö¿‡ª›´ HêßhiÄZ­†ZÒ¾íímàãŸ)žK¬×ÊÌ3åFý}\ÉÉæ…i ôl·è2yð”^/ 5dÊ';×N¹iÓ@P;ØÄ®t“Õ¢(Y<±®*:G+Ïîî®âž^ Ÿ7§i·§þÑ:…¹oêÍ.cã_þ.êSËh$.3©kFªØ§©éëõz–œg||ûÛðV^¡;Y~Ñáž6ƒmï¢j\±pÜÚG~ª¯OÒDeéû ×Á}æ8æÊ™K½·é|Ì#FLjº<3E†§"zÂêüF*vAá9kz>hÕàÐû÷¾§è02ú"Ë ‡þÚ—ÚLƒ“‚ôäÅlïø‰žÃSÇ‚ô:^¦)%ŽÌ<'4xŸNËÐÇHä=ìۢ߉‚5%Pì! ê[¤PåõÙ`Ý¥¡^Éç<áoö¸«¿÷ÔfÏÓŒ{¢jä™3oòú½ç3Åœüc<)“«Ï{Îà5|VžÐ(JEs'ù7ë"ÆÄ!Úí68çð}œ+_ ™0oDµ¦¦¦’L–qSD?kÄñ„Diâ›ô;¾ïcllLù}Iy&&' ㎢£qÞKÕmSQ»÷GÝ÷˜Ù²›ñ¶KÍzÀÖ{¿3ó}6S౿¿ŸYý&''Äö¶¢\{ä“ùë¡gœ8S\éœsåCìuçÄ1ÐëÐì#š=†'sÒKÊVëAÍËt­¨Œ®ªN…k5oŸš›\xâsˆdŒ£FœsÔFjð|3wblmm*‹q*`ooø®O» Q÷÷c€Nµ3]½JÚ W!ÀêÏý::Bݰ5íû*¹Ñh¨l‚ Àä™1Œüî¯Òxƒ{-ÏÁ;Yÿ0‚UYšo‚’×l}ó÷BLÍw3Töd¯,\3KÀ£Ÿ<>8úøü»Šî>™¯f 5£\[„#uxåô_o¿æ1‘’K™¥:CV2ãs“yŸzÍj N3ÒÙº¨½×ƵÄQ?ÿ ¹Z¢\ÕA£ô™®Êl®>ËðŸÛÐê‚;…ÁR¯ã8Ï{Nu)¡¿tV2¿¾‰#¼€)Åó¸zU,áqH7ø^n!3‹xî8˜øªe~¿{à)ëXBçåy<á|fùÖoATð‹”¤ä³{oü?ø~€f³¥˜ +|ꎒ& J» ú¬zY0ê™ç–¢@›)ce=o6³wŽŒªtíG LOÜ㘙žÁÞWñC?\œÙ0'rʱþ©ú¤Œ]ÅîÁòß=P®ô|¬ÛO`ñË¿‘µ¹^Wi¶¯]»†N§ƒ(ŠaBéˆû,àƳÄó9¤ô Á= œ{YfL@1K°ôf¦ ÎýÔÊèñ¬/ÔüdIºc¬À×Eù&Ö(B*ðoæwp~ã2í Ul€ïŽŽŽpX?TÉ‹LM*¥pggVøØ§iù4û O˜]KÖôúYCèÇQcùì~ôÓ¾ò{ÙÍOÇ™":::ŠÃÃC Š"DQ¨¬à¯|W¿ŠÎ>Rîü+HdÖîÁ8ÁÏLœîÒóqëÂ'qîoþ[67#ìììáÚµwò×Á'? AñzM@x ºÓýƒ'’Þ匩,­E8‚#u®%&ŽðS—Š`ƒ¥Z6RKƒ‰Ù$›ÒÙŸ*CÄiÊ @S¢-•!ˆYn`[ÚTä²¥Kñ›·iéúÝÄ’bëãMéûœ5¯èÎ$$“™µÍï¹*N¯d{}¤sן®ÍGÏó”%,a{`ð¸ŸPØ¡¼ó'±¯ä”´°¼ý<$”ÒEQbádh·[`Œa}}‡‡‡I˜àSSS£¨'ˆRÕ=ãCf8æš Y7L³ÙÄþÁêõ:¦§§111 ÀÃøølmm£Ýî Õ019Ú•¿F«± Y›¤í£e•%`›óž ÂÞ›…dŒ™dzŦ§Üµ?ó_ûtõŒµ#eË`Œaffœs ÑÀ÷ÿ‰·Þó|HpHøI¶Bß÷²¤Q xpH&éóÝ´É.O]¯¸çƒð=/k¾—üí%õ*4(~» Ïü&Þ{õ+hÇ1šÍ&ÆÎœÁÈÈch·Ú¨×±zs5‹H³PnllßýÓÀÜyz; êÅ’5ÆX/Øó²›†œ*@(¬Ž¡Õïý'˜{îOÐé´3_éô]ilEýð‡‡‡¨ÕjSSSØû?ÿÿú÷‡Ãb¹ç”ÌÖCúeÆz,üŒu[HÀJ«ÿîyò n)€Üf2Î(gffàqûûjüð/rºdVo ¹òà{ý0•' ,V¸Ï¤›>?54„º7Y ©–dJÅIfÙÔµ­ €6h[zF'Õh“e’m8JÌ[Ý-Ô2C›(m.Ûï¦g¶Á™T‹_òž Iæ!¥Ì ýžÏÒ/ª+iY\7ê˜ó]Ï÷Á„²¬û¾¯€Vp|î;뻈߳þ$FõzžÏ†!ÀDâN±¶¶†MªO„h6›ØÝÛƒˆãþ¬’ò8Gtú÷\wÿ)ÿæz½Ž0 áû>|ßÇôô,vvvqpp€ÑÑQD^„ɱêÿ7Úýœ½cÈe‰¿DâÖ‘Xq9O™®eŸ®Q±Ð™Áö—þ` Qannggg³@·4p&Ôƒ0œ ]£ú}6/’9Ù;d,‹×åV0çSt•^@J‘‘Œ9ƒƒƒƒ,sæÄÄ&^ý Ž®½Œøžo© 1œ{I‚§tv™¥”`ž 2VjÎ`ûÁÀÔs–¬ƒùùyÌëÛ+vvvõàÔ< ©3™Ì· sÛéÝgÒõQxÖRnem‰=l™×n+§šü©è¼ h†€M±2Ÿd–M[K¬sM)¿ÙhÊXÜÎ,›@y•»1˦ió´ï9A üxsÀNï?u/iõ1).iÙ¾X( òÁVÌà<æsJ¢sêþõ¿ƒï«à¶4(’1†­ý}ܼyëëëð<óó ˜™™9îß=È™Í”ïø ;Æ`°ž3È(üZ-•)PùÂŽ¡V«eÏ)ØÚ|æ÷Ñ~ôçŠ$‘FQ,J€ó \ù~ײÛk‘´Qnn|蓘{õ/Ðnµ»mOo,¤¢s<::ûøg”ëaÞô‚Û ðÁ?x9çð¤§_#%\Pzç_ÌIÏ󑯏¥JŠ¢Ñ“v7i `±À¹•gñÀë……õ+ð8ÇA½Žv»ññqŒeeàÆ\»v ívóóó8{ö,Z­VWWù%à=æ[8M À ÷»Ê—ïûð<¯‡é‡÷p0ûCöæcŸÂâ×þ"VIyRW"ûR`vvØ?ØÇèØ(<ßÃìì,öþô¿àà—>WÙùÇ="ñGïUŒû¬ÊŒAzÜ Ç¬<üãXºò4›ÍÌo;†TÞ$R ÕRÛìŸéºð0ZŸÝ1áÉÚTˆÒu'mXå¨.η‘ ¼ºD<ÔÆÛõ¢ç'Mex7dÙ´é['ÃÝŽè³Û‘e³J*Ã;‘e“Òï– A;ï ÙñÒ]¥ON@p \ql£'õ! 1 CœÀ÷xGøèK2(%|ÏGÌâ|ÿSK :ÞXÃùÖut’TÞ£ccɯ‡­-Å]̰¸°ˆ¹¹¹Œþm—º×W´‡«¥ÇW¸kqäŽNÒäø¾ 033ƒ••5Ž059…ññqœ¹ü"Ž6ß‚8{¿ù@scª(?éO/+?ûtŒÑ>€øþÙâæØ}Ø~éÏÑétŽùÇK)кïdJ=ó­I†ÝC9ÀŽ>…°x˜n‹Ms²×%$q‘`Œ)žŒcÊŸÈó”õÔ÷|.°´´„›9.§~ûAëaûµÆf·ÞÀÙ7°°ó&jíºò™o¶ÐLb¦¦¦0:: Ï÷!…Àöö6^}õU¼ùæ›8<<ÄÔÔ–ÏŸ‡çy¸~ý:“‹À§~…ÆlFØ;}OáT÷=¿ÏºšZqso£çlûÌ,Ö?üãX|úó`œÁg>¤à¾r{ Ã1Œcvµ‘fff°ué/q´q ñÙ{*9ú<Î!<²|>jµA¦gÎÞÒqmô¶^èY}q4­÷]€|ÿ…ü`üœýÞï¡: ‚÷KxwLxÃslÜ)ñ€T0~› žÕa¹Ÿ˜orÓ(¢!c„w”↫ÍÂv RÕY6Må;n m€øiβ©øTÿø“ȲIíwS¿P]P4c†⸠!$ çdl¹Üdé&ò„‡‰å™1 CpÂÄM³ÇÊã{`±ÁÚm*?ùì›¶žD-аÛl Šjˆå§Ùî´±µ¹…f³‰ùùy,[ÂîÞžzòÉÜŒ¹Ka çÉìì,–——1??(ŒàÆÆFư°0ÕÕUìîìbvvÜã˜Åî×þ'?ôYózÓü¿çùâÌzÛe~é^½«1–z ›s¦¼ñ3¿ ü A‰HüðAfý—ÎÉ0èf)M­ƒ}se8ñsö§ÐïÆ Q””Lyúwƒr`½ï¾ûð_ÿ{8{öl6—ÓŽÔºêû>j##ˆ;´Z-e¬QarrQe ÐÍÕU<ÿ XYYA³ÙÄÔÔÞsß}ÃÛo½…]à×þ›¤å< ì~àgA–J)ì‚=VÀ-ÝWý–_ø¿€ŒáûJÒ“(£077‡ýý}ìîíbìÌü Àüì öþü¿bÿgÿC5Ü÷;SŠ=ç¾çƒqÖ×Fk#€×~ñ·€_4T ÂŒ À¤¸R=ßGà=Ù;/C§xäS)qU Z¾+âÕ¹ äi¢¢ c8ô>âÌòù`ùÅ1ËXÄ)ŠAQÙÌ`™Ô¹Ùô{où¢º ò®¶†Û€aʦ‚rHÖ€þzU ß÷;¯Mé¼ Zñuôˆ”,²EÏmú=íäšgy ¢ ÿEjm ÐjIxž²?ðáqŽñ3ãØÙÝA܈ X»ôGhüà¿Q¨P˜ûU™Üúÿ¿«Tõ»pƲ±NÝ<8çýAhE󶈣œæ‹=¸“Ï¢(„1‚ ç Ad´Žj>úI¦x–?Šæˆ Q'@4½• »Œ÷Ü{/676Æàq5>Rª,ˆ©ÒšÒöòCïííõÝ¢ŒŽŽâÌ™3 ìz>|ßC»ÓÁ׿þu¼ôÒKØÞÞç‹‹‹¸ÿþû122‚«W¯âwÞ~ù7|GñÙ-rú•éo‚@õy °‘ÕYô칬D„s¢5~ëÿ(–.þ1|ßK7‰ÌÏ|jj*³‚ÇqŒZàìÙ³Øxæqøÿ âÌôð Ï÷ûæ;瞟sÔ{»¢3Ú’E0VJ#A€d’#HâE¢ èc.ò|/‹ñ0f¥¦ÜšáÀKI‚AéŽp¦’Ü °‚ -ï¹ LËâC‚dÔ¥ /:lu7”²¡)“b×q‚J8[0N¹½¡¼G7§Š@Ïå­+cp³ËØ‚p#UDÅdyEñÒÐ6ß- Ú¦Ûk4T†Q%–n$4a  vâôàMü…9çˆóüuT‰ƒc–ô¿*[í0 à{Â0PTx²›…3egÉ~}B3™ ²Üxs^‡ßÇØØ($$ja„7n`###˜IøÊuà‡þ­>iZÞ¾–×îž:wþ¹ò;ð¸§(Ä8²ëþ¥sKØØÜÀÎÎ6Î;‡±±1L¶ßÁþÛ_EëþGŠçOÈìñõIêÓ4ð3¥…ëW¨•†ó¤h®ênŸ(€=™)¿xàG„Ä@]e©¹™ÒíC=ŸGa”1ßDQ˜¸EIfS†…ùyœC»ÕF˜¤TO9ß•1’%šë±€sÏC‰B¡`=/áàgW߹Чžz›ˆ;*Óåùóç±¼¼ Æ€7Þxo¼ñðóÿ øØÏçûÏS8Šö¯œ1 öbôÉx*ôîû*p2SÄ©û{"W?òqÏˉ4À¹Óé€{^æµ¼|/¿|ÛÛÛ¸çž{§Ç±ûÅßÂÞ'~yè#.‹yéàyë Ûë¸ë0 c",°’èÎE!DÀ•¢$îYBÄqœð>·]¹”x¦¢1åëûT± Çy),( ùüŠrà90ÍaOqª§\3PÜG œœV›¦+m&v‰k3È ÊSY˸i¬mü×ÊPRùÍ‹n—(æÔç:ë·,ñLn2’Ï»`G Cxž‡0Šú¢÷ã8Fà 3G è¹—)ÁpPn'qœd¢ Cø¾‡0Œ²çqgœÁ‚Å*õ`Ÿ<«lÁüù–ƒ‹¨E÷111‰0 àyZ­¶ò«m4°°°€ÚÈ677»ðHfR:ôdÌn,}ßþöçw:|O¤ž¢C\^^Æ+¯¼‚õõuÜ{ï½€sç–°ù¢uß#fvž¼º1 }tâNbUàAf]NÇ8eXHÓ†ÛÅ åÚ¸*õ̧0 ³Œ‚ €{‰U\ôÍ ô¸„䎻5eVv&àRfþù©¢(W °»»‹¹¹³83>ޏÓQõŠ!Êšþ‹áÈp< Ñiw ¤HÑþ› t-¦±qYb«ÆŽãÇ( ÑŽÛ€djL¼ £6ìUˆXq z‘u ÅûéH9N]& Þ2Y:w À7YÄucàHñi*Ëém â¤ñ*“9 n¿ÑP€°I¹+Ë ¢c  ’AOGQ †IÒCðE4Š"´[- ¡ ô ÂBÈc€Çó<´©¾† ·0ŠÐN¬a" ”`¬€Çibb€çàœðÑÆCñ«èÄø\1,££#¸zõ2VWW!„ÀÒâ"8ç¸~ý:pßwsï£9 wòY}dûgÄøú‹‰EQf.!ãgÆ1;3ƒë++¨×똘˜ÀÜܦ_ù"ö:MH?ÊŸËRscåëßiÇ,Qv‚Qô«ÔE1¦@ëK_8/‹ÖoÑg9¿­E5´š-)¸ß“½ue ež‘õ†ß^…4Œ EBˆ}e f`Šw<¹)ò’ Å‘Z q'FGtwbı€1„ð’`T¥Ä¶[ì`c}7nÜÀææfÆ3Ÿ¦`Ÿ››Ãòòr–´emm W®\ÁŽ €_ùsàCÓCi.ô0ŒÐ‰c QЂ PþƉ{H§ÓA§ÓÉâ1|ßG\rãÂOã=¯ H”þv»£â?<aàÞ{ïÃ¥K/`}}÷½ç=õ},ž ±õäç±ý=ÿx¨£, B´ý&b©¾=ÏWîoI‚ ‘g§Ô¨m`¸œ$”˜´‚=$Š"´ÚmÈÄrø]Ç1:Ž N×ÓÜâ‚pÃLU.Êán gšp˜R,&ËŸÍÀÀrÒP“ kÙ– ÜQV3¿©VfEõ$³lÂM–1S)V7 õ(U9) ÒsžEa„#¿&b¬­®áêÕ«xâ‰'”QQ(9™ J Då^Ö|^«ÕÐl6H¬Ý*.ÛO²döò1kƒdsö°¶®`"Öwð|[[›X[[ÃåË—ñâ‹/BÑÑQ,,.‚3®hÞ~è—h<ã0Yb¯/=Žï8z B(B¶í¬ÜXÁsÏ=‡ƒƒÀ­[ë˜Eø˜ ±ùÚ°ÿÍß¼_ç€ó0 Ñl6!l¬¯cåÆ |õ«_Í’çŠ CBtû¹ À¶åhÏÁµþ‘Ǹ¹¶Š·ßz _úÒ—ŽÕµ€Sh)M•©²;¤X¿u 7VVðäSOeî ©¥±—5#½-ŠEœ÷A®øÞi ãÄĦ§§177‡™™™Œ‰dww¯¿þ:®]»ñ]? üü&ÎÚ³YÂ(D«­üØo­¯cåúu|å+_Q¯O|ÜU¿{‰[M“’e3§ÜúäÖ¾åûpîå/dñŠï|—/_F£ÑÈR׿÷½ïƒçq,.-aëÉßÇÎ㟂ôÊCµ( Ñhø`B`ss 7oÜÀ³/f7nÙ~ƒýfX N5(²Þ1‰à7Ž %pkm W¯¾ƒ'žx¢ox¾ŸÑ¸Ý¥æ†×däÔáÉS•ŠÞ¤}¢ÂgÃj8¦ÔT•eÓT¶Ë²yzÁ¸mšz @|7gÙ4µ™Ò6J¿[dÙŒj5„G‡èÄ F;;;VÊþ1;;«Ob#õ GQ¤‚!qtt”[öÜÜ\æ£y¬l  wA¼¬‹0Æìîíbuu+7VÀC­VÃý÷ßÑ‘Q¬o¬ãðèxø§ÍŠŒÉ§¾9uþšõº Àkµ2…CY¬UP\ÚæóçÏcí•?SÜ’z@Æ1.¥D£ÙÄîî^æëœq’) Ãâx C»¬”Ç" x­†À 8G£~„ííícu ‚,f™O¬õmLAùQ¡yÔ„ô%ZÛ-ìíïe`‡÷fM_!¥bgÉ’r2E³—KÏó†!¢(B­VÃèè(ÆÇÇå`O`s,bÜZ¿…·ß~7oÞDû½€÷9àá,o$ ‚?©öf³ )%šÛ;ØÝÝÍ]‹~’˜* C³læ­‘+ßúxßÛORÍñv;Ȫޱö<žÅ+œv±þâ_aãÛ~¸¼<Œ7V«…½$à3•ééiÙ»×~0`¥¨Á¯‡Bâè¨qlœ={ïC°ºCœÁ@K&I½ »ípŠ J•@ܶãŠÞ}§²lR¬’w"˦ât‹øÝ˜e“:†âËÕG¼L¿ µ‘üýœyX> ‹‹xì±ÇÐnwÇ´Ûíìº3ŽcåKi'ŒÕj5Q)Ο_ÆÒÒû®Ç’«ün™qÃã¼Ï?ÜÐM°:ônbï  ßW,Ó“Ó˜øÖ <ô¡‡ {\m„¸uëä7}0±¨¿¥°Q~{äccæC˜í\„çy˜™žÁÔÔ4þö‡3ÿán¦M‰©©),½ò"nַЙ)V ê…‘:¤¥ÄÒÒñè£ßÙŸ\¨Ç-Iûþ €MßÕj5ø8fX^>‡…Å<þøã™D:7X̥ʂimçi­6‚£  `éÜñÈ#߉XåëX¹Ó¹’ù~Ç]Ö Þ±S¼ègè&îI oa3¹‰Y__ÇÞQøðÿôçoû~sàŸ.—ìö¦ZTÃQP‡çΩùñØ£BHÙãV#ªÚ}€°¿ï/bõßs¯? 099‰ÉÉI<øÐƒè¥:êåÏ_\\ĽÏü6¾õ㥒¥p?ÀEŒ…ùÌÍÍáÂ…+—;Ù­ c¬azÓIDATžŒl ‚†ß×¢Á>d,pîÜ9,..âñ~"qŒX&ÿíÝ—Ë$W¤ÜÊêÚtê‚0MΆ3— iʲIÉÂyÚ²lÚ²¦P¼â'Äm4e,(ÊÝ0>âànÄËZ¦ª¢2´|Æ9‡ÊÊÕ8:R‰@ì4 `zíÎ9ïßè¥EÛrú.Š"p0ÄPàDJ‰V£ ž°q õûf œ«@<-((ïÃìU„‡V«/»V–@ 0Á vÔ­àÖ­[ð>öÏû>Oˆ¾>uïk¿…æQC±g)”‹B«Õ‚çu3g2ưpö,æßþV¾ù§ô7 9u “Û†” B%ʉ gjéÌøIlSß¡›µSB¢Ùl%,8ic×$›¶Š‘¦NQq®€´Pn%Æ‘¢=i‚¡$1çà=¼é Œ t¾ïVK%Úi68j6qT¯ãèèõzõzfñÙ{~äûG>ŒNèÇ•rS–gà2ì_ŠñÅSí€ä‰ÅU¹¡´WV¼X`£çø|`õ":íN7+kò¾^ŸTFFF°´µ‚¹·ŸÁúý)uTÕjµ$±cW™€{$Îj#µrçõF߀?j)ËŽ'“`u@${s«ÝÊnP<¯g”ÉéBù•pãÔpOwÈãí6E£RÁ½é·¦ÉãD6ñŽ3‹ïUeÓvƒ¨Ê²îÀ8È´†zÿ_GX´ ÂÜ:©,›ƒeç­y¯³0X+¤Aé.ò‡Ož}ýÒ%<ýôÓh6šh¶š™•1µàõfnTWÅmÇ2áóK—.á©§žÊ€Ê`Ù)èO¯ [­×y`^œ¿ùEüÍå/ãÆh6›h·Ûh·[h·:sE >cØ«7!>ôãÝäñ*S÷ Gùåè,_y/=ñX»S«_ÊÒ!Â0ÄdóO×CrúæÍ7ßÀ³ŸE»ÕÎíçôúß÷ýÄ/ß`| q¿Sû®ç·é¼HÇ*µzçÕµÝn¯ÙÞ²uûAÏg/¼ðžzòI4 ž“:ôÞÈ(K·r=é­“dàD@8D£`£ÀèäÄ9`a˜]†œ½Xz?äùà¦Æx˜¸¾A8» ö¹×^{Ï<ó54M´zö^÷ ÏS yjŽÑ RX2°=¾ˆçF߇í?ýï8J’õ‚nÆ™¢ÞËxÉCa€Å'~»4óÍ7qñâÅcûMV­¤Lß÷Ñj¶†Ã~Ðà@ÂÙyùòËxêé§Ië êÜ þ*âþÖaÑŠiÙüßÉ¡æÍwÊß6{ZQœˆMÀvÑoMkYâdh`)û{—»áücÄ5TÔgTS¼ÓP‰@øð]tûxÀ©A!ðnãe¨ )>êe*5HL’Ë>T  •auÑ0¬mf_Fi0YÙáÀÔ)ÎúÆa’ûdÆk@a2 ”è&ƒƒ š¨ «“¶nP6åRhø¨€Uâu}B¥(´éwê¾®‹°˜{”÷Jœd0³ «,SUª!¢Œ C[Åþ~7œ&¬c: %Ì„e°ŠN9 yÜq^öŠÄɪ¼¦Î¡P›e“ª<è& $SµÂ“̲ bÛœÜ[Ö²ns;Ue–MSÙL£ÅÍ›$=U>ƒåçÃt[i‡ý½ W¶-8òoe‰úÙ‚øª8À«ê;[åò{ à,ÐMg•4X‘‡Q–©)ÈmƒÊ«¦­b¿ξ²8¤l–Í2I‹Î´èû“aA¡Ð1¢–oÒZtå›~Géø;•e“29ïD–M“V*း-/»ÁVEeH±˜Ý®,›€>Ë&,Ú\µE͆~ÑÔÎ*:ÕŠI¤HÔŽ£ÎZ KåÊ6í»”2 î:oÃNýže%ë¾3)f¦q’Ê<¯MJ<…P Ìm—Í-¤N98iØ*ö÷»éü+ Ä©¿·â&Cè &<5™0M”T‹ŽÖl3hÔg¶蓤2¤ô˲ùîâUl°e|m‡“βYæ;Ôk䪳lÚ€ŠÅÏ $B2 + èL󸏲‡*ƒª+ÃÉI­‹iØ¶É mƒ5qÛ0e²l¦c8ø[þs×7Ó”]tðq.랣๩ßuÏL<à:ŽrcQ^?ñ¤›n+lÞ¡«_Ñ¡˜×ö¢ÛÁâ7ÞÆ~OX¶ †¶•­[ÞoŠo^ËŽÛ`¿•#ˆãÍ™&,ç{Þœ(³¦Êæ&—$î'éšR&÷Äiâ6Á2ÉóJî—S•ˆ‡4®Hsfš‰Cùþ  /²fiH&ÿŸ¼Èw]Ý)Ï™¡¦6ç•Á,­ZEmƒ m ”…@}åÅýG±KâX˜â"˜¦|rW¥¦õmòy6•ÍO·Æ,Ÿ3ƒqÁ¦Ò°¦¥á`°4W±¢÷ëš©.&f&A˜c@>U @1#Dyí„}^HBýŠÖ©¿oGÝP°GØ– bÙ(9oLŸ ƒr_fMQöT7,ÚPdÄÐÝšÖ*%¥Nì.<ÿ@ÀDTü! €œúý ¤NI¾C™ÔàÌ*© mRtåQêc“œ§¬‹ ˆ›5yIÑØØZÆmËw¢?PlT(k@·©™Ü8†±î” Œ*e¶~Ÿ¦ô×eRcœi{5oËVA¥¤+COhû{i°)V1[*CJL3ßa˜·'Ån“ð©Ì¸éæ«)@‘2îUÎwÊ~ƒƒ“­›JÙ}ÎQVk§RúÞ¬tǸ_)0©l¦ß7U{¥øœ›&%ÓIqÝ&Mñ§Ìn*e'¥ ÿ¹:€¶Ý`Ë€d[Dÿf €¶þ¶ÜÀTå„ Ä)‰C†I^ nЩ´( °M€€É¢öÚ€X[~ò2ß+ËŽ’ʃnÜLŸÙЖQöl:ˆÛ(Ä0ì?ºßêrP\ü•a™óÏÖ XÖEåýëýJ;ÆVK+ ÐM@ÐÆˆ¸R&Ë&@¤ §´‹ ’ËPRbOj!9¹»²lšS›€eJÛm³l–±ŒUeÓ((Vôª:å¶I›9A“6ÖÖ² –ò½"7.©g¬âvQÁ´é·&0=̼ż©‚sߤÛdÙ„àŸD–M ö0íï.˦~~ØfÙ<|k¶m²Ûlš¶Ô6'•e“¢|PßO4w"Ëæ°„£2¬Æ*@ItRˆ—ͲiŠ½Ð•q»²l–±ŒQùaü0I|Êt[žoÊü³ùý°<ãUü–ºïÚevÂuö·U1רŒ;Ua´™ï¦Ïm•e[ m›eÓÆˆAÅTÃîïwÃùWæFŸÒ‡&¬tj‚0½#|Ñá1 U—I;§LV x‡åï(Y6MÏ™¡Î€™ù¤²lꬑ.ËæéØŒ(›5ˆS•¥2@œj½2)w¶fžåËæ¹èSi‡É²I±ÒÜ.€nKo8Ìïêh©ÉrÊå*x¼«â ?I€= Ox™ ¯e~@µþã6@Û6˦ÉJí\ShF(üP6ËfâWÚxÝ"³ñã¦hÛ`ÊçT.O ·ÑÊ$qÃÒq›úS6ujÛLŠLí8Ň[e-%ÃnôÃdŠ+ËÃ]&]´©MUdÙ´6uf–õ°èT°Âˆ{‰íïQâ÷'&m꼑Kèâ@¿ãF9‡ªQH)kJÂ.Ë&Ï)Aô.ËfµçßIgÙ<èçyΣc„0oò󂉭£'+Z¨Eîy¼ Ee›ÞЮµóêNyžÇ§N± š\stõ|'´MgE¤Nd Gç»ÅŸí¤­©ˆ‹­­…A É4l‘[˜éû:p©{¯Ô¬oj›lží?B³gͼ–„òL} M݋惉N®ˆ"0Ï姨Uü†ý…Ê.*ƒêBqs*ú7Rtý c;LßÙüÿ¾ˆ7[G£ Ëù®[Ã(¿¼9‘·/˜öJÀLQ"M{7³ÜËìïw 7QÚô …öòŽp ˜ç™¬¶ L˜¼Ï¹ÁZjûþ"Í[·Xmž nðÐôÜ`ù¦2šmf€½¿<#¶âNB±Šè4[Û´µNèÜÛ¶`œâ*f“m³Œu‡Âµ+ ë[j¬f0<§pSŸQ-rº1¦´ìQh%¡Ì"žpµ4oþ à ‡èP˦p”ëøÍ)–dÀÖ}¯ˆÇ›¢° ¢U›Ò.jۘŸ1Í"ˆF›ùNÙ+„ƨ%0<³†°z›ö ¦Û²–ñ2¹'î˸É%‰úû;ÀM¼§-xˆ€˜-x®q€îºا½·É¨›(6 +6m–%Ú‚FOå¶Ð¹¨ ¿^‡½z¬ŠÊ@Ü–ÿ(—Zº,à µoMÏlYRŠeÝßÐ$*ð†¼ Å )1‰ ÏxUŠ’¸†l¿7¬Ÿ;¥ýeû®Šq£òË›,ÈUÎwK %ÖÐç"ÐÝSö/ê>1l€þ»™S(ÇÀ–g>¼LD®n°uÌ å(«é ¶uØt'—Üg؉\–TŸªÉ;*C;«€mÿÂâð©B( Ä)J`Ë”íó2ý® ”ƒ² Å¡ `¡RRýxoG"=©d9e[p^¶nTtSÛ†¡•á÷”yc3¯«â܇f=Phuøæ$¨ Ëè¿›T`Ø3MxõŽpÀìËIµDÛ‚”IÖcc>é,›TpoóÛÓ’e“Ò6—eótmD§!Ë&…Æò$²lbË”å«è &8³ Hg%ö=¶ 6ä;( aLuì˜Vò˰¿5^›¶UÉNÙsób†¡^Ìœà”¹JUnÇ|·e+²1>¸,›·WîPr@¿Ò·™\L‹ˆBeXe–M .Cehrò§ÒšÀ¤îùʲIÝ$l¬­UdÙ¼›7‡Ûm ¸³lR”2“õÇ”esXî_ é0@Ü6·­Å¯ €Ney†/šRþ0<ã&à Íüb°«[:J;jŸ•åO§*K6J¥~¦rLý¤æõIdÙÌÛ7X2”gŸrT†4C^ƒàmàŒ0é¨àZ·ˆl9Ët6Ë&•nÍÖ‡Üd=¢qS»l¬ÌÃdÙ´Í® bùÎ5Å^‘.»ÁÚ&²±±c*ÿÑÚ¯‚û·è;e¨ mXÓžf£|Pê^&iÊ0‰€¨Óa@² H¤ºŸ˜ÎÃ2 ¨Ž¢°*ô2}wüò&ZÕœûÃ*ËT7¾*baÊÒÀRÎÚ2IàNóùwÂT„¥¸”Ügãúë Ó†ÍD¡X˨‘Ö ¾Ãôß4õ×=ÓEÖÚXmŠú]Vôxß…¥%ëˆï¢øz:)îÇaÒñJ" 2ýÎ&iÅÂ'‰sÝ´!Û¤-§*'”M߯@5(PßUæFÑÆõÐH– x,S'Vò·lˆþa#F1T1Ð}]9¡L›ú óYå›ÞÁ,>×½k˜g”vr¢qÒ6xp˜`Ãw«‘K`Ã7΀K)ÁóÖþâ9Lª8E˜>sâÄÉÝg])¢“sâĉ'§³I`a¡ûw @îÛ•§À·”ë_¸”(:qâÄI) Ný܉'Nœœ¢=œkkÀü<Ày)N¾\R‚qÑê`óï^:Âo'Nœ8qâĉ'ߘ |cˆcõ·´»¾$p)%˜Çµ°ýìkõ&Àøvâĉ'Nœ8qò À¥¶¶€N§k ¯ €§–ïø¨çßD¼W<î:Þ‰'Nœ8qâÄÉ76ØÙÚm+K87¿›Avbì<ûâ½CÀ÷\‡;qâĉ'Nœ8q˜rCÙÙQ–p"×p)%À€/¿Œø°x|;qâĉ'Nœ8qr „om)‹8!F’ëÀ7÷nýõóíķʼn'Nœ8qâĉ'ÇA¸”Àúºú¯Á Îó€7Åóý—Ïw_êĉ'Nœ8qâĉ“bžRvµ€§—R¬ñ’5¥Š'Nœ8qâĉ'ßÐÂ9pëV×%OóAð-šl>y²;Ë·'Nœ8qâĉ'eDÃÎ3ðò|_|âÐñ|;qâĉ'Nœ8qRJ <á<³|7žïÝCÇóíĉ'Nœ8qâÄɰ ¼€'œ+žo­g^SIvÏ·'Nœ8qâĉ'Õ€ð8¶·ûÜQ¸âù~ ¢Þp–o'Nœ8qâĉ'NªáB››Y`&¿õÅÏ·'Nœ8qâĉ'' Â{xÂÿ?©;¯¾® 3IEND®B`‚qsstv_8.2.12/qsstv/icons/replay.png000664 001750 001750 00000002611 12440612574 017270 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;sBIT|dˆ@IDAT8…•KŒ\W†¿sϹý¸ýw÷t·gl÷$„1X2ŽÉŽØd’ˆQ²b…Ä)ë E‚bAØXX°Ê%àA(â!<"ñØIì`Æmæ=ÝîÛÏÛ}Ÿç°pÆ6r %Õê¨þS¥ÿ¯¿ÿ;”¥25•-7dÊqtäûÑ´»§#¿ &|\¡x܃íTÏ”Ͻ”]>.4š2]Î# ™º^8ÞÛšvo~ிýV8Þûü_`™.6Ë‹ç¾W;õêwJµ'ªZEÕÊY«#;æ¶›ç_C·³›Üí´Ç½[øëþÕ_ý8l®ñ§[*3w䫯ý¼zêÕçO4¾q¦ÈéM£œÂJÜQÄÍ݈߭ù\ºÖýý—Û«?yÍkü{ wzä+?øÙ±³/Ÿûæ—+Ö+ÏdY>*IÛÞ4›Æ‘!J@*A­¤øB3E£l³3­$NóìxçòûI0ÜÌ}àÚç¿ýÃÆ—¾ÿÊsg+ÖóOÛdlAo8¥?†!ƒ7ññ|MCƒ10W¶)åm±îVÊþ¨£Æ;k+@$ïU9sìë¯ÿèäÒ|îüe ü0ÆQ!OÌ—˜¯iTó*f˜ÉÛì¸ad"Cfr’I(Ù êÍÁw¯ÆÁðލògŸ{©4{¬üŧÒhmprvÀ瞪3StHÙ €tJádl&¦ïÅ÷s4M8>g¨ÕËKç_Â:¤,•©eg—O—UU5Ój%ÍÒBc žŸ°ÖòèbòŽ…1°Õ qÒaA»sy«DÏË2¶r–S]>)Ó…¥²åFºp¸Y-¦ÆØš…F[I^Ìo/¹L}OÛ#Á‰¦C¥QplÎ/MY|÷´=@ÚØùF#•¯-(™r™©ä;b0I˜H¨WrìtC^‚6÷ÎÉOÖ ,Î9TÌ<ºmdz&#m§ Ô<í¡!mƒ”÷Ä2œZ¼¿™%ˆ-ž]ò³Ÿ!eK„x }ð+â“­!¤Ò‘ï'S×Û÷&‰a¶`ØsŽÕJyE`rlÃ0AJë¿@ú^LY!Á€{ަ¾M»{áxok0Ñ ‚,›=›¿·"âİ8'yý[ ËsšìgYß>2þÀKHƒ-! B¯Ý ½»»JG~{Ú½ù™îM¤Š•ëYN6cޱYœÏðÓ—#£ÙréàÞ8ÁhAJ &A[ûÝV+ ‡Û˜Ð]û­ ×ríØ¥–õŸ_üqÊõûLM:eS«1Àxš°Ñ™m îHãÈ iÝÃlx½Ö;u» Ç[ šÅùÓO›U31FÇÜØôé#ÜqÌÖݛ۫7&¬\õh÷Cz£˜ë!£IÄÖ®ËÖå_¯ô[©µÞ?ð  7ï*ŸÈÌm©ÚÂI”w³ÑŽØh‡ltB“ezã„ÍNÈÈ imöõ­ßý¨½váÍÈ\†÷MHÇ~w´ýÞ{¡jœŠÓG›Ǧœ·I) [ ”¤”õ ¥ÀF\»=àÆ•?}´ùç7ÞF{«Æ˜ȇ‰0IØï^¹2޲}s¸é…V*kk‘Ë*”HK îÀãÚ‘þðŸ[ãõÕ߬ì¯]x3í­j­÷ùÄ?í4Y€“)}¦¼tþE§º|2]¨7JÅ\Fè½ w:~·ÕêµÞ¹è»·.i­÷1]wA ¤„%gUº°”.Ô—,åX`"Mýл»›„Ãm£“±ÖºL:=ˆÿÁ¨PûFc½IEND®B`‚qsstv_8.2.12/qsstv/icons/start.png000664 001750 001750 00000002357 12440612574 017140 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs ?@"ÈtIMEÓ $*[õ¦S|IDATxÚ…•Ýo”E‡Ÿ™÷c¿ºÛ--–",b©@ÝŠ?‚QS‰&¢1~Å»¸ á†ø(é ¦¯ráM/äÒ#Æ‚„P–ÔŠ ”*ín»Ý}—íîû5ãÅ–¥5´Nr2™Ì™'¿srÎÁ+bÒ½TZ'AºVs–r‹Wœ×üõÞŠ  ‡€÷A"È!¬Ê[FG÷€I¡Âsy}ö’ã8Ñÿ‚ó'&wƒ8…a}Ô‘Jf·ôddowœ==5VÄ_åî ¥’*W 6.YúÁûõøeÇqÂÇ‚ó'&w€ÃÎ îJðæÁ4û¶kžÈZ²åª¥ZÈô\ÀùB“‹SKø ÷fL•?{ZŸ;ÿnüGé×™Ìoꟾ’à©>ƒ˜eðÍOöná‡?ÔRГ1ٷâ·ËâvQ÷¸Mñì¢ÞYJÌ Ý÷<>ŠþàÈsYñÖ…mIüPãšw^ÈòÕ‹ìÚbáù /Px¡FkÍÖMé¤%þ˜º›¾¶¶rýÂÐÐP`´Ô^;$ŒØèÝ™øpÞBJðE3hA¶õÄxq ÅÉï4Ïä¼@¯Ü·"ØÔ!©û&3¥ ¿mŸìåæm#|ÂN¥Óé—^L‰®ðM3h©õÍî­qÞ{Þàô¸`ïÍ}3P؆Ïô¼²ëÍ00ÂêEØ f22qër£Òfü¤Í‡_ÂÑ.Q¤™-GLÍeqIjtHEeÀ¹œ ô!d®'-høŠ†¯Ð+å¢×)ô<ÃþÞ “§˜u[aš Œ> ;'$2–JZ•ºÂ]Vx¾¦éëö¾žòßæ³”–“šB±„€t;n·i1_•]Iµ!©4 îUb\Im˜?2‚–µ›CItå-Ï×Ô£x+~@#¨ù6Z¯Ÿï×GWµ°XiŸ¨Ù:ôL´šîU—ÕÎH$Ö<ÔÈu§Éá3¬LÓ 1³uŽÛ­=fj·f\µX®NtG7ƲâŸm0À‘¼µ¸¨sÕ†9à.‡ýé¤Å¦´‰mI.߬c›bY,T¦¦«Ì•܉ÍáõÑœ,\ljÚàB¡ ‡‡’åEݽÚ0’¥jÐ_[í¸ŠTÂÄ”)@ëˆÅ¥:¿ßYVÎÔT*îÝѱhÑqœà±?ÈÈȈRS¼{8”GÖ€”¢/0µFÔT‘*š4oÅ£ù +9*ëþ «à°‹QÖ¹†()tèIUŸËê»÷;…2PŽã¨ÕŒeóAnZÈEèIEND®B`‚qsstv_8.2.12/qsstv/icons/stop.png000664 001750 001750 00000002142 12440612574 016760 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs m„·tIMEÓ  ©ÒyAïIDATxÚ•ÛSEÇ?3çÒžnOé^¸µ,¢Ù˜‚­˜ðBŒ‰$ú€ QLôi ¼™øà“OšðNB|ãAL4&B„˜E¼,ݬˆÈ-K·»í¶§´§í9gƇ²Ë‚€‹ßä›Éo.Ÿùå7™ÁCT80m^ *‡Ö)ЀЪl)¿ò‹÷rïAkÅC Û= ·"È#¬T·Ž¯ÓBEG úð)ÏóâÿLoñ>†µ7=Ê®ÉȵÃIÆFš8VÌ¥Zš+ÅüÜœª5‚@EÁ)Kßúd‹>rÚó¼è¾àÂé agvn}Òáµm.›ŸÐ¬ÉZ²?U ͈Ëåc¥?œ] ø%TíÃgõÑc‹pãžL?Mg2¯¾±}•x÷E‡§s Ë Œ¡é%R0’1Ù¼Ábí Åß=âwÄóU½±´³èÜ(•Jz œÛ¶ÿ ¶ûÖ®²âõ¢…mIz‘¦Þ㞢*º‘FkÍú! 7e‰?oÄÞ¶Ö3u¢X,†¢Ÿí™íÂH~³å©¡ìÞ®#ùv*`%zå9‡0Ò|õkÀ÷S•†Ñyo3_7 û'-´Þ“Hf ›lb¥h´4½½æ¡ÐThwžb,óû¥„[«¦wWÂÑŸM`5°5“Y%³É¿%y}öc?HÑ$-õq_äó&CÈüˆ+zŠ §è绲 „êq±–é¦ ÂÈaØyH!)+¤ÞRH¶)V½4Ÿ¼{!@&¡pÍÅN¿c1ÛÐ\G¬¸kÄât½x9”4A¨n{¶åЊ“KƒñHµîÃ5ÄŽÐQ×D«2p½ÑVcáðdý¹tAÇ©Zei)¿LÓ­)ËÐØË¼R%ÍÛŒ½ª2é\Èê«7@qßéÂN™Ë­tíG*‚!!R°ÐìQž™i:óŒÉ“_›}øÔ™hâóf}nßèð SôŸ'}ÏS¥ï4ˬi®ÕP½ÆwcòäO@Ó(•JúñÂ;—»!Ï(oxlØ©„ aé¾Í»Û¤}'„\¸æ«j­19Ÿ;”3ç–À» Vµªó“À÷ÛѨ›²rMlKb›â_¶ ˜o„œ½Ü <çO®Ž¦æeé7`Þó¼x \*•ôÎbªVÕ£SÀHÍ5ÂÑf;²“f$SJ¤­cª -þ¸ÒVç¯5oÕëþñáøÜ¡ÛЊçyá}‰‰ œåÍ—"™Þ­°Æ¥9×1€fwT¬*& ÉxöÄíšÎõþ Ëà°+ñhÖù<†à ”:êJÕ*gõÕ›«ŒùÐÏóÔrÆ?B¸ä¿.ì¬ìIEND®B`‚qsstv_8.2.12/qsstv/icons/sweep.png000664 001750 001750 00000000426 12440612574 017121 0ustar00jomajoma000000 000000 ‰PNG  IHDRðÍ­'sBIT|dˆÍIDAT8­S±ƒ M@guèéàÖ«Ÿë,¿æì,×¹*] ¤@¬z}S޼Ç#Ø"îæÿ‹ÎèŒáÒâjßt!e¢1y3ϸj O¥`ÕÚ^ºg¹õ}ÄHXcÆ”!ôŒe ݼÏsªÙoWeUY¼Ô°sÞ¶>·mTjšqütM“‹ Û1©_î¾/L¹ùcYxF*ÍZ?Æ["œývR8Ø)rßeƒzœ<”DYFŵRñÖ ù'Q7  8aÞé­O`–kr ˆxDîY¶\!Ó"kIEND®B`‚qsstv_8.2.12/qsstv/icons/text.png000664 001750 001750 00000001005 12440612574 016754 0ustar00jomajoma000000 000000 ‰PNG  IHDRÄ´l;sBIT|dˆ pHYsvv}Õ‚ÌtEXtSoftwarewww.inkscape.org›î<‚IDAT8µ•=K+A†Ÿ™¬›‘$®`£ERþ† Átr[áVn“ÎÒÎÆÂÂBl%¤+ÜÞ? ¿Ä«+fØÀªÙ9®°æC“˜¼ðórÎ3ÙQ"Â2¤³‹Ë›û¹wîõ† jµÚ\ðƒÓŸÖ#àB¡0wDcÁ"‡žç=EQä‹E“$É@.—[‹ã86ÆhçÜ:p&"§;çÎÃ0üŸFI£ÑPI’Ðn·3åQ'ZëéÀZëÛqù8•Ëå®sn$·Z-5œU*¢( n6› ¾}“4ë¥N ö}9`kíâÁNcÌâÁ°Ä—J¥Åƒz½ÞrÀ³ŽB_ÝnwËZ‹µ–jµº½0°µv÷Üï÷÷¦éùrƘ?À‘ˆüÎÄǾï×µÖq_MêU_ÓO~¬öw6Ô'°R*^ß ‚úæ/ øÀJj÷±)@ €×Ô/áõÝCPß,Ï"’(A)¥S@>µÉx5u>…¿ñ~o{žïA`ó1IEND®B`‚qsstv_8.2.12/qsstv/icons/tone.png000664 001750 001750 00000000546 12440612574 016746 0ustar00jomajoma000000 000000 ‰PNG  IHDRðÍ­'sBIT|dˆIDAT8­“=KA@ß]’óнJ©‚¤1µ ˆ­¦•ô‰¥… ?@Kñ„”6vV +A°J!.U‚è%ŒEì.·› 80Íì¾}û1 ®¨ŠØ†|'耗ƒ8˜/ß<ÏeÎd¡*¢Õ<ˆú b¦_–>ÜÔ`Ã\,oJ ÷IÂ:ƒÓ}h?BQlÁXŸ¬ãeõÍùš×ŸËsKçÐ9†¤ë{Ã{Bàî¬ÍàÛjÔò'hÈ5œmýÙ”0Ÿct¥]h¾…dÈ^cü™ ZÏXƒËé¼öÙ€(3a^$†îvZ³Øn5¨\ÉLäŽR­©áh1ý92÷¢ºï ¸"¤ÿTÿ¢öOê€~§Ð{ÁäoÃgIEND®B`‚qsstv_8.2.12/qsstv/icons/transparency.png000664 001750 001750 00000000230 12440612574 020500 0ustar00jomajoma000000 000000 ‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÝ ,3j*Ñ%IDATHÇíÍA0ôï|JðÛ ¬“Ô§©g@ 7 º-É ï‘IEND®B`‚qsstv_8.2.12/qsstv/icons/whatsthis.png000664 001750 001750 00000000330 12440612574 020006 0ustar00jomajoma000000 000000 ‰PNG  IHDRô„蹟IDAT•í”±€0D©qâwý—ÙÁ+\Á6Œñ&;ôõŽ3¡Z¦P~Ð#­úÅÌ­™÷ú(²%Ž˜9 è}à Ï2”€fä}ÕY`. ‚¬TÍÖN–ˆˆŠ6]˜ýàsGžPr²b Õ?¤Qïz±3Óź9 n¦Ñ®)%î±¥] ¤Ã­ ˜š¶p´½oÕ~t|M{½†.ÐIEND®B`‚qsstv_8.2.12/qsstv/logbook/logbook.cpp000664 001750 001750 00000004062 12440612574 017751 0ustar00jomajoma000000 000000 #include "logbook.h" #include "qsstvglobal.h" #include "xmlrpc/xmlinterface.h" #include "xmlrpc/ipcmessage.h" #include "configparams.h" #include "rig/rigcontrol.h" #include slogParam logParamArray[NUMLOGPARAMS]= { {"program","QSSTV 8"}, {"version", "1"}, {"date","" }, {"time","" }, {"endTime","" }, {"call","" , }, {"mhz","" }, {"mode","" }, {"tx","" }, {"rx","" }, {"name","" }, {"qth","" }, {"state","" }, {"province","" }, {"country","" }, {"locator","" }, {"serialout","" }, {"serialin","" }, {"free1","" }, {"notes","" }, {"power","" } }; // to be independent from localization QString monthArray[12]= { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; logBook::logBook() { ipcQueue=new ipcMessage(1238); } void logBook::logQSO(QString call,QString comment) { int i; QDateTime dt(QDateTime::currentDateTimeUtc()); QString tmp; getFrequency(); if(frequency!=-1) setParam(LFREQ,QString::number(frequency/1000000.,'g',9)); setParam(LCALL,call); setParam(LNOTES,comment); tmp=QString::number(dt.date().day())+" "+monthArray[dt.date().month()-1]+" "+QString::number(dt.date().year()); setParam(LDATE,tmp); tmp=QString::number(dt.time().hour()*100+dt.time().minute()).rightJustified(4,'0'); setParam(LTIME,tmp); setParam(LENDTIME,tmp); // setParam(LENDTIME,""); setParam(LMODE,"SSTV"); setParam(LNOTES,comment); tmp.clear(); for(i=0;isendMessage(tmp); } void logBook::getFrequency() { if(rigController->params()->enableXMLRPC) // we get the frequency from flrig or alike { frequency=xmlIntfPtr->getFrequency(); } else if(rigController->params()->enableCAT) // we get the frequency from hamlib { if(!rigController->getFrequency(frequency)) { frequency=-1; } } } void logBook::setParam(eIndex tag,QString value) { logParamArray[tag].val=value; } qsstv_8.2.12/qsstv/logbook/logbook.h000664 001750 001750 00000001007 12440612574 017412 0ustar00jomajoma000000 000000 #ifndef LOGBOOK_H #define LOGBOOK_H #include class ipcMessage; #define NUMLOGPARAMS 21 struct slogParam { QString tag; QString val; }; class logBook { public: enum eIndex {LPROG,LVER,LDATE,LTIME,LENDTIME,LCALL,LFREQ,LMODE,LTX,LRX,LNAME,LQTH,LSTATE,LPROV,LCNTRY,LLOC,LSO,LSI,LFREE,LNOTES,LPWR}; logBook(); void logQSO(QString call,QString comment); private: void getFrequency(); double frequency; void setParam(eIndex tag,QString value); ipcMessage *ipcQueue; }; #endif // LOGBOOK_H qsstv_8.2.12/qsstv/rig/freqdisplay.cpp000664 001750 001750 00000000505 12440612574 017763 0ustar00jomajoma000000 000000 #include "freqdisplay.h" #include "ui_freqdisplay.h" freqDisplay::freqDisplay(QWidget *parent) : QWidget(parent), ui(new Ui::freqDisplay) { ui->setupUi(this); } freqDisplay::~freqDisplay() { delete ui; } void freqDisplay::display(double freq) { ui->frequencyLCD->display(QString("%1").arg(freq/1000,8,'f',3)); } qsstv_8.2.12/qsstv/rig/freqdisplay.h000664 001750 001750 00000000500 12440612574 017423 0ustar00jomajoma000000 000000 #ifndef FREQDISPLAY_H #define FREQDISPLAY_H #include namespace Ui { class freqDisplay; } class freqDisplay : public QWidget { Q_OBJECT public: explicit freqDisplay(QWidget *parent = 0); ~freqDisplay(); void display(double freq); private: Ui::freqDisplay *ui; }; #endif // FREQDISPLAY_H qsstv_8.2.12/qsstv/rig/freqdisplay.ui000664 001750 001750 00000023162 12440612574 017622 0ustar00jomajoma000000 000000 freqDisplay 0 0 214 52 Form 2 1 75 true KHz 180 50 0 170 255 255 255 127 0 255 255 0 255 127 0 170 0 255 255 0 0 0 0 85 255 127 0 0 127 0 0 127 0 85 0 0 170 255 255 255 127 0 255 255 0 255 127 0 170 0 255 255 0 0 0 0 85 255 127 0 0 127 0 0 127 0 85 0 0 170 0 255 255 127 0 255 255 0 255 127 0 170 0 255 255 0 0 170 0 85 255 127 0 0 127 0 0 127 0 85 0 true QFrame::Box QFrame::Sunken 10 QLCDNumber::Filled qsstv_8.2.12/qsstv/rig/rigcontrol.cpp000664 001750 001750 00000027532 12503514704 017627 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "rigcontrol.h" #include "qsstvglobal.h" #include "rigparams.h" #include #include #include #include #include #include #include "mainwindow.h" #include #include "txwidget.h" #define MAXCONFLEN 128 rigControl *rigControllerR1; rigControl *rigControllerR2; rigControl *rigController; QList capsList; bool radiolistLoaded=false; int collect(const rig_caps *caps,rig_ptr_t) { capsList.append(caps); return 1; } rigControl::rigControl(int radioIndex) { rigControlEnabled=false; catParams.configLabel=QString("radio%1").arg(radioIndex); rig_set_debug(RIG_DEBUG_NONE); getRadioList(); serialP=0; xmlIntfPtr=new xmlInterface; } rigControl::~rigControl() { rig_close(my_rig); /* close port */ rig_cleanup(my_rig); /* if you care about memory */ } bool rigControl::init() { int retcode; if(!catParams.enableCAT) return false; myport.type.rig = RIG_PORT_SERIAL; myport.parm.serial.rate = catParams.baudrate; myport.parm.serial.data_bits =catParams.databits; myport.parm.serial.stop_bits =catParams.stopbits; if(catParams.parity=="Even") myport.parm.serial.parity = RIG_PARITY_EVEN; else if (catParams.parity=="Odd") myport.parm.serial.parity = RIG_PARITY_ODD; else myport.parm.serial.parity = RIG_PARITY_NONE; if(catParams.handshake=="XOn/Xoff") { myport.parm.serial.handshake = RIG_HANDSHAKE_XONXOFF; } if(catParams.handshake=="Hardware") { myport.parm.serial.handshake = RIG_HANDSHAKE_HARDWARE; } else { myport.parm.serial.handshake = RIG_HANDSHAKE_NONE; } strncpy(myport.pathname, (const char *)catParams.serialPort.toLatin1().data(), FILPATHLEN); // myport.parm.serial.rts_state=RIG_SIGNAL_OFF; // myport.parm.serial.dtr_state=RIG_SIGNAL_OFF; addToLog(QString("rigcontrol:init myport pathname: %1").arg(myport.pathname),LOGRIGCTRL); catParams.radioModelNumber=getModelNumber(getRadioModelIndex()); my_rig = rig_init(catParams.radioModelNumber); if(!my_rig) { addToLog(QString("Error in connection using radio model %1").arg(catParams.radioModel),LOGRIGCTRL); initError=QString("Error in connection using radio model %1").arg(catParams.radioModel); return false; } if(QString(my_rig->caps->mfg_name)=="Icom") { if(!catParams.civAddress.isEmpty()) { rig_set_conf(my_rig, rig_token_lookup(my_rig, "civaddr"), catParams.civAddress.toLatin1()); } } strncpy(my_rig->state.rigport.pathname,(const char *)catParams.serialPort.toLatin1().data(),FILPATHLEN); strncpy(my_rig->state.pttport.pathname,(const char *)catParams.serialPort.toLatin1().data(),FILPATHLEN); my_rig->state.rigport.parm.serial.rate = catParams.baudrate; my_rig->state.rigport.parm.serial.data_bits=catParams.databits; my_rig->state.rigport.parm.serial.stop_bits=catParams.stopbits; if(catParams.parity=="Even") my_rig->state.rigport.parm.serial.parity= RIG_PARITY_EVEN; else if (catParams.parity=="Odd") my_rig->state.rigport.parm.serial.parity = RIG_PARITY_ODD; else my_rig->state.rigport.parm.serial.parity = RIG_PARITY_NONE; if(catParams.handshake=="XOn/Xoff") my_rig->state.rigport.parm.serial.handshake = RIG_HANDSHAKE_XONXOFF; if(catParams.handshake=="Hardware") my_rig->state.rigport.parm.serial.handshake = RIG_HANDSHAKE_HARDWARE; else my_rig->state.rigport.parm.serial.handshake = RIG_HANDSHAKE_NONE; //my_rig->state.rigport.parm.serial.rts_state=RIG_SIGNAL_OFF; //my_rig->state.rigport.parm.serial.dtr_state=RIG_SIGNAL_OFF; my_rig->state.pttport.type.ptt = catParams.pttType; addToLog(QString("rigcontrol:init rigport.pathname: %1").arg(my_rig->state.rigport.pathname),LOGRIGCTRL); retcode = rig_open(my_rig); if (retcode != RIG_OK ) { addToLog(QString("CAT Error: %1").arg(QString(rigerror(retcode))),LOGRIGCTRL); initError=QString("CAT Error: %1").arg(QString(rigerror(retcode))); return false; } addToLog("rigcontroller successfully opened",LOGRIGCTRL); rigControlEnabled=true; // int verbose=0; // rig_set_debug(verbose<2 ? RIG_DEBUG_NONE: (rig_debug_level_e)verbose); //rig_debug(RIG_DEBUG_VERBOSE, "rigctl, %s\n", hamlib_version); // test if we can contact the tranceiver double fr; if(!getFrequency(fr)) { // rigControlEnabled=false; } return true; } bool rigControl::getFrequency(double &frequency) { int retcode; if(!rigControlEnabled) return false; // retcode = rig_set_vfo(my_rig, RIG_VFO_A); // if (retcode != RIG_OK ) {errorMessage(retcode,"setVFO"); return false; } retcode = rig_get_freq(my_rig, RIG_VFO_CURR, &frequency); if (retcode != RIG_OK ) {errorMessage(retcode,"getFrequency"); return false; } return true; } bool rigControl::setFrequency(double frequency) { int retcode; if(!rigControlEnabled) return false; retcode = rig_set_vfo(my_rig, RIG_VFO_CURR); if (retcode != RIG_OK ) {errorMessage(retcode,"setVFO"); return false; } retcode = rig_set_freq(my_rig, RIG_VFO_CURR, frequency); if (retcode != RIG_OK ) {errorMessage(retcode,"setFrequency"); return false; } return true; } void rigControl::disable() { if(rigControlEnabled) { rig_close(my_rig); /* close port */ rig_cleanup(my_rig); /* if you care about memory */ rigControlEnabled=false; } } bool rigControl::getMode(QString &mode) { rmode_t rmode; pbwidth_t width; int retcode; if(!rigControlEnabled) return false; retcode = rig_get_mode(my_rig, RIG_VFO_CURR, &rmode, &width); if (retcode != RIG_OK ) {errorMessage(retcode,"getMode"); return false; } mode=QString(rig_strrmode(rmode)); return true; } bool rigControl::setMode(QString mode) { rmode_t rmode=rig_parse_mode(mode.toLatin1().data()); int retcode; if(!rigControlEnabled) return false; retcode = rig_set_mode(my_rig, RIG_VFO_CURR, rmode, rig_passband_normal(my_rig,rmode)); if (retcode != RIG_OK ) {errorMessage(retcode,"setMode"); return false; } return true; } bool rigControl::setPTT(bool on) { int retcode; ptt_t ptt; if(on) ptt=RIG_PTT_ON; else ptt=RIG_PTT_OFF; if(!rigControlEnabled) return false; retcode = rig_set_ptt (my_rig, RIG_VFO_CURR,ptt); if (retcode != RIG_OK ) {errorMessage(retcode,"setPTT"); return false; } return true; } void rigControl::errorMessage(int errorCode,QString command) { QMessageBox::information(0,"Cat interface",QString("Error in connection: %1\n%2").arg(QString(rigerror(errorCode))).arg(command)); } void rigControl::getRadioList() { if(!radiolistLoaded) { capsList.clear(); rig_load_all_backends(); rig_list_foreach(collect,0); qSort(capsList.begin(),capsList.end(),model_Sort); radiolistLoaded=true; } } bool rigControl::getRadioList(QComboBox *cb) { int i; if(capsList.count()==0) return false; QStringList sl; for (i=0;irig_model); t=t.rightJustified(5,' ')+" "; t+= capsList.at(i)->mfg_name; t+=","; t+=capsList.at(i)->model_name; sl << t; } cb->addItems(sl); return true; } int rigControl::getModelNumber(int idx) { if(idx<0) return 0; return capsList.at(idx)->rig_model; } int rigControl::getRadioModelIndex() { int i; QString t=catParams.radioModel; t=t.remove(0,5); t=t.simplified(); QStringList sl=t.split(","); if(sl.count()==1) sl.append(""); for(i=0;imfg_name==sl.at(0)) && (capsList.at(i)->model_name==sl.at(1))) { return i; } } return -1; } bool model_Sort(const rig_caps *caps1,const rig_caps *caps2) { if(caps1->mfg_name==caps2->mfg_name) { if (QString::compare(caps1->model_name,caps2->model_name)<0) return true; return false; } if (QString::compare(caps1->mfg_name,caps2->mfg_name)<0) return true; return false; } void rigControl::activatePTT(bool b) { int modemlines; if(catParams.enableSerialPTT) { if (catParams.pttSerialPort.isEmpty()) return; if(serialP==0) { serialP=::open(catParams.pttSerialPort.toLatin1().data(),O_RDWR); if (serialP<=0) { QMessageBox::warning(txWidgetPtr,"Serial Port Error", QString("Unable to open serial port %1\ncheck Options->Configuration\n" "make sure that you have read/write permission\nIf you do not have a serial port,\n" "then disable -Serial PTT- option in the configuration").arg(catParams.pttSerialPort) , QMessageBox::Ok,0 ); return; } else { ioctl(serialP,TIOCMGET,&modemlines); modemlines &= ~TIOCM_DTR; modemlines &= ~TIOCM_RTS; if(catParams.activeDTR) modemlines &= ~TIOCM_DTR; if(catParams.activeRTS)modemlines &= ~TIOCM_RTS; if(catParams.nactiveDTR) modemlines |= ~TIOCM_DTR; if(catParams.nactiveRTS)modemlines |= ~TIOCM_RTS; ioctl(serialP,TIOCMSET,&modemlines); } } if(serialP>0) { if(b) { ioctl(serialP,TIOCMGET,&modemlines); if(catParams.activeDTR) modemlines |= TIOCM_DTR; if(catParams.activeRTS)modemlines |= TIOCM_RTS; if(catParams.nactiveDTR) modemlines &= ~TIOCM_DTR; if(catParams.nactiveRTS)modemlines &= ~TIOCM_RTS; ioctl(serialP,TIOCMSET,&modemlines); //ioctl(serial,TIOCMBIS,&t); } else { ioctl(serialP,TIOCMGET,&modemlines); if(catParams.activeDTR) modemlines &= ~TIOCM_DTR; if(catParams.activeRTS) modemlines &= ~TIOCM_RTS; if(catParams.nactiveDTR) modemlines |= ~TIOCM_DTR; if(catParams.nactiveRTS)modemlines |= ~TIOCM_RTS; ioctl(serialP,TIOCMSET,&modemlines); // ioctl(serial,TIOCMBIC,&t); } } } else if(catParams.enableXMLRPC) { xmlIntfPtr->activatePTT(b); } else rigController->setPTT(b); // does nothing if rigController is disabled mainWindowPtr->setPTT(b); if(b) { addToLog("dispatcher: PTT activated",LOGDISPAT); } else { addToLog("dispatcher: PTT deactivated",LOGDISPAT); } } qsstv_8.2.12/qsstv/rig/rigcontrol.h000664 001750 001750 00000002634 12437307434 017276 0ustar00jomajoma000000 000000 #ifndef RIGCONTROL_H #define RIGCONTROL_H #include #include #include #include "rigparams.h" #include "xmlrpc/xmlinterface.h" bool model_Sort(const rig_caps *caps1,const rig_caps *caps2); class rigControl: public QObject { Q_OBJECT public: rigControl(int radioIndex); ~rigControl(); bool init(); bool enabled() {return rigControlEnabled;} bool getFrequency(double &frequency); bool setFrequency(double frequency); bool getMode(QString &mode); bool setMode(QString mode); bool setPTT(bool On); int getModelNumber(int idx); int getRadioModelIndex(); bool getRadioList(QComboBox *cb); void disable(); scatParams* params() {return &catParams;} void activatePTT(bool b); double getTxDelay() {return catParams.txOnDelay;} QString initError; private: hamlib_port_t myport; RIG *my_rig; // handle to rig (nstance) freq_t freq; // frequency rmode_t rmode; // radio mode of operation pbwidth_t width; vfo_t vfo; // vfo selection int strength; // S-Meter level int retcode; // generic return code from functions rig_model_t myrig_model; bool rigControlEnabled; void errorMessage(int errorCode,QString command); void getRadioList(); scatParams catParams; int serialP; }; extern rigControl *rigControllerR1; extern rigControl *rigControllerR2; extern rigControl *rigController; #endif qsstv_8.2.12/qsstv/rig/rigcontrolform.cpp000664 001750 001750 00000021071 12440612574 020507 0ustar00jomajoma000000 000000 #include "rigcontrolform.h" #include "ui_rigcontrolform.h" #include "qsstvglobal.h" #include "configparams.h" #include "utils/supportfunctions.h" #include "rigparams.h" #include "rigcontrol.h" #include #include rigControlForm::rigControlForm(QWidget *parent) : QWidget(parent), ui(new Ui::rigControlForm) { ui->setupUi(this); connect(ui->enableCATCheckBox,SIGNAL(clicked()),SLOT(slotEnableCAT())); connect(ui->enablePTTCheckBox,SIGNAL(clicked()),SLOT(slotEnablePTT())); connect(ui->enableXMLRPCCheckBox,SIGNAL(clicked()),SLOT(slotEnableXMLRPC())); connect(ui->restartPushButton,SIGNAL(clicked()),SLOT(slotRestart())); connect(ui->RTSCheckBox,SIGNAL(clicked()),SLOT(slotCheckPTT0())); connect(ui->DTRCheckBox,SIGNAL(clicked()),SLOT(slotCheckPTT1())); connect(ui->nRTSCheckBox,SIGNAL(clicked()),SLOT(slotCheckPTT2())); connect(ui->nDTRCheckBox,SIGNAL(clicked()),SLOT(slotCheckPTT3())); rigController=NULL; } rigControlForm::~rigControlForm() { delete ui; } void rigControlForm::attachRigController(rigControl *rigCtrl) { rigController=rigCtrl; } void rigControlForm::readSettings() { cp=rigController->params(); QSettings qSettings; qSettings.beginGroup(cp->configLabel); cp->serialPort=qSettings.value("serialPort","/dev/ttyS0").toString(); cp->radioModel=qSettings.value("radioModel","dummy").toString(); cp->civAddress=qSettings.value("civAddress","").toString(); cp->baudrate=qSettings.value("baudrate",9600).toInt(); cp->parity=qSettings.value("parity","None").toString(); cp->stopbits=qSettings.value("stopbits",1).toInt(); cp->databits=qSettings.value("databits",8).toInt(); cp->handshake=qSettings.value("handshake","None").toString(); cp->enableCAT=qSettings.value("enableCAT",0).toBool(); cp->enableSerialPTT=qSettings.value("enableSerialPTT",0).toBool(); cp->pttSerialPort=qSettings.value("pttSerialPort","/dev/ttyS0").toString(); cp->activeRTS=qSettings.value("activeRTS",1).toBool(); cp->activeDTR=qSettings.value("activeDTR",0).toBool(); cp->nactiveRTS=qSettings.value("nactiveRTS",1).toBool(); cp->nactiveDTR=qSettings.value("nactiveDTR",0).toBool(); cp->enableXMLRPC=qSettings.value("enableXMLRPC",0).toBool(); cp->XMLRPCPort=qSettings.value("XMLRPCPort","7362").toInt(); cp->txOnDelay=qSettings.value("txOnDelay",0.0).toDouble(); cp->pttType=(ptt_type_t)qSettings.value("pttType",(int)RIG_PTT_RIG).toInt(); qSettings.endGroup(); setParams(); } void rigControlForm::writeSettings() { getParams(); QSettings qSettings; qSettings.beginGroup(cp->configLabel); qSettings.setValue("serialPort",cp->serialPort); qSettings.setValue("radioModel",cp->radioModel); qSettings.setValue("civAddress",cp->civAddress); qSettings.setValue("baudrate",cp->baudrate); qSettings.setValue("parity",cp->parity); qSettings.setValue("stopbits",cp->stopbits); qSettings.setValue("databits",cp->databits); qSettings.setValue("handshake",cp->handshake); qSettings.setValue("enableCAT",cp->enableCAT); qSettings.setValue("enableSerialPTT",cp->enableSerialPTT); qSettings.setValue("pttSerialPort",cp->pttSerialPort); qSettings.setValue("activeRTS",cp->activeRTS); qSettings.setValue("activeDTR",cp->activeDTR); qSettings.setValue("nactiveRTS",cp->nactiveRTS); qSettings.setValue("nactiveDTR",cp->nactiveDTR); qSettings.setValue("pttType",(int) cp->pttType); qSettings.setValue("enableXMLRPC",cp->enableXMLRPC); qSettings.setValue("XMLRPCPort",cp->XMLRPCPort); qSettings.setValue("txOnDelay",cp->txOnDelay); qSettings.endGroup(); } void rigControlForm::setParams() { if(rigController->getRadioList(ui->radioModelComboBox)) setValue(cp->radioModel,ui->radioModelComboBox); setValue(cp->serialPort,ui->serialPortLineEdit); setValue(cp->civAddress,ui->civAddressLineEdit); setValue(cp->baudrate,ui->baudrateComboBox); setValue(cp->parity,ui->parityComboBox); setValue(cp->stopbits,ui->stopbitsComboBox); setValue(cp->databits,ui->databitsComboBox); setValue(cp->handshake,ui->handshakeComboBox); setValue(cp->enableCAT,ui->enableCATCheckBox); setValue(cp->enableSerialPTT,ui->enablePTTCheckBox); setValue(cp->pttSerialPort,ui->pttSerialPortLineEdit); if(cp->activeRTS) cp->nactiveRTS=false; if(cp->activeDTR) cp->nactiveDTR=false; setValue(cp->activeRTS,ui->RTSCheckBox); setValue(cp->activeDTR,ui->DTRCheckBox); setValue(cp->nactiveRTS,ui->nRTSCheckBox); setValue(cp->nactiveDTR,ui->nDTRCheckBox); switch(cp->pttType) { case RIG_PTT_RIG: setValue(true,ui->catRadioButton); break; case RIG_PTT_SERIAL_RTS: setValue(true,ui->rtsRadioButton); break; case RIG_PTT_SERIAL_DTR: setValue(true,ui->dtrRadioButton); break; default: setValue(true,ui->catRadioButton); break; } if(cp->enableCAT && cp->enableSerialPTT) { if(cp->serialPort==cp->pttSerialPort) { cp->enableSerialPTT=false; } } setValue(cp->enableSerialPTT,ui->enablePTTCheckBox); setValue(cp->txOnDelay,ui->txOnDelayDoubleSpinBox); setValue(cp->enableXMLRPC,ui->enableXMLRPCCheckBox); setValue(cp->XMLRPCPort,ui->XMLRPCPortLineEdit); } void rigControlForm::getParams() { getValue(cp->serialPort,ui->serialPortLineEdit); if(ui->radioModelComboBox->count()!=0) getValue(cp->radioModel,ui->radioModelComboBox); getValue(cp->civAddress,ui->civAddressLineEdit); getValue(cp->baudrate,ui->baudrateComboBox); getValue(cp->parity,ui->parityComboBox); getValue(cp->stopbits,ui->stopbitsComboBox); getValue(cp->databits,ui->databitsComboBox); getValue(cp->handshake,ui->handshakeComboBox); getValue(cp->enableCAT,ui->enableCATCheckBox); getValue(cp->enableSerialPTT,ui->enablePTTCheckBox); getValue(cp->pttSerialPort,ui->pttSerialPortLineEdit); getValue(cp->activeRTS,ui->RTSCheckBox); getValue(cp->activeDTR,ui->DTRCheckBox); getValue(cp->nactiveRTS,ui->nRTSCheckBox); getValue(cp->nactiveDTR,ui->nDTRCheckBox); if(ui->catRadioButton->isChecked()) cp->pttType=RIG_PTT_RIG; if(ui->rtsRadioButton->isChecked()) cp->pttType=RIG_PTT_SERIAL_RTS; if(ui->dtrRadioButton->isChecked()) cp->pttType=RIG_PTT_SERIAL_DTR; getValue(cp->txOnDelay,ui->txOnDelayDoubleSpinBox); getValue(cp->enableXMLRPC,ui->enableXMLRPCCheckBox); getValue(cp->XMLRPCPort,ui->XMLRPCPortLineEdit); } void rigControlForm::slotEnableCAT() { if(ui->enableCATCheckBox->isChecked() && ui->enablePTTCheckBox->isChecked()) { if(ui->pttSerialPortLineEdit->text()==ui->serialPortLineEdit->text()) { QMessageBox::critical(this,"Configuration error", "The PTT serialport must be different from the CAT serial port if both are enabled"); ui->enablePTTCheckBox->setChecked(false); } } if(ui->enableCATCheckBox->isChecked()) { ui->enableXMLRPCCheckBox->setChecked(false); rigController->init(); } else { rigController->disable(); } getParams(); } void rigControlForm::slotEnablePTT() { if(ui->enableCATCheckBox->isChecked() && ui->enablePTTCheckBox->isChecked()) { if(ui->pttSerialPortLineEdit->text()==ui->serialPortLineEdit->text()) { QMessageBox::critical(this,"Configuration error", "The PTT serialport must be different from the CAT serial port if both are enabled"); ui->enablePTTCheckBox->setChecked(false); return; } } if(ui->enablePTTCheckBox->isChecked()) { ui->enableXMLRPCCheckBox->setChecked(false); } getParams(); } void rigControlForm::slotEnableXMLRPC() { ui->enableCATCheckBox->setChecked(false); ui->enablePTTCheckBox->setChecked(false); } void rigControlForm::slotRestart() { getParams(); if(ui->enableCATCheckBox->isChecked()) { if(rigController->init()) { ui->restartPushButton->setStyleSheet("background-color: green"); } else { ui->restartPushButton->setStyleSheet("background-color: red"); } } } void rigControlForm::slotCheckPTT0() { checkPTT(0,ui->RTSCheckBox->isChecked()); } void rigControlForm::slotCheckPTT1() {checkPTT(1,ui->DTRCheckBox->isChecked()); } void rigControlForm::slotCheckPTT2() { checkPTT(2,ui->nRTSCheckBox->isChecked()); } void rigControlForm::slotCheckPTT3() { checkPTT(3,ui->nDTRCheckBox->isChecked()); } void rigControlForm::checkPTT(int p,bool b) { if(!b) return; switch (p) { case 0: setValue(false,ui->nRTSCheckBox); break; case 1: setValue(false,ui->nDTRCheckBox); break; case 2: setValue(false,ui->RTSCheckBox); break; case 3: setValue(false,ui->DTRCheckBox); break; } } qsstv_8.2.12/qsstv/rig/rigcontrolform.h000664 001750 001750 00000001462 12440612574 020156 0ustar00jomajoma000000 000000 #ifndef RIGCONTROLFORM_H #define RIGCONTROLFORM_H #include #include "rigcontrol.h" namespace Ui { class rigControlForm; } class rigControlForm : public QWidget { Q_OBJECT public: explicit rigControlForm(QWidget *parent = 0); ~rigControlForm(); void attachRigController(rigControl *rigCtrl); void readSettings(); void writeSettings(); bool needsRestart() { return changed;} public slots: void slotEnableCAT(); void slotEnablePTT(); void slotEnableXMLRPC(); void slotRestart(); void slotCheckPTT0(); void slotCheckPTT1(); void slotCheckPTT2(); void slotCheckPTT3(); private: Ui::rigControlForm *ui; bool changed; void getParams(); void setParams(); scatParams *cp; rigControl *rigController; void checkPTT(int p,bool b); }; #endif // RIGCONTROLFORM_H qsstv_8.2.12/qsstv/rig/rigcontrolform.ui000664 001750 001750 00000170651 12440612574 020353 0ustar00jomajoma000000 000000 rigControlForm 0 0 673 764 9 Form 1 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 104 104 104 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 104 104 104 255 255 255 104 104 104 208 208 208 208 208 208 0 0 0 208 208 208 255 255 220 0 0 0 true Special Serial Port 2 1 Enable PTT serial Interface Qt::Horizontal 40 20 60 0 PTT Serial Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 Qt::Horizontal 40 20 +RTS +DTR -RTS -DTR Qt::Horizontal 40 20 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 104 104 104 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 104 104 104 255 255 255 104 104 104 208 208 208 208 208 208 0 0 0 208 208 208 255 255 220 0 0 0 true Hamlib Control 2 1 2 Enable Hamlib Cat Interface Qt::Horizontal 40 20 2 60 0 Radio Model Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Ubuntu Mono 75 false true false 60 0 CIV Address Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 50 16777215 Qt::Horizontal 40 20 108 0 Serial Port/Host Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 60 0 Handshake Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 2 0 0 None Hardware XOn/XOff Qt::Horizontal 40 20 60 0 Parity Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 70 16777215 None Odd Even Qt::Horizontal 40 20 60 0 Databits Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 7 8 Qt::Horizontal 40 20 60 0 Baudrate Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 70 16777215 5 300 600 1200 2400 4800 9600 19200 38400 57600 115200 230400 460800 60 0 StopBits Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 1 2 Qt::Horizontal 40 20 PTT Control via: CAT Command true RTS DTR Qt::Horizontal 40 20 Qt::Horizontal 40 20 Restart CAT Interface Qt::Horizontal 40 20 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 0 0 0 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 0 0 0 255 255 255 0 0 0 255 255 255 208 208 208 0 0 0 231 231 231 255 255 220 0 0 0 104 104 104 208 208 208 255 255 255 231 231 231 104 104 104 139 139 139 104 104 104 255 255 255 104 104 104 208 208 208 208 208 208 0 0 0 208 208 208 255 255 220 0 0 0 true XMLRPC Interface 2 1 Enable XMLRPC Interface Qt::Horizontal 40 20 60 0 Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 Qt::Horizontal 40 20 60 0 TX on Delay Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 1 5.000000000000000 0.100000000000000 60 0 in seconds Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Qt::Horizontal 40 20 Qt::Vertical 20 17 qsstv_8.2.12/qsstv/rig/rigparams.h000664 001750 001750 00000001141 12440612574 017067 0ustar00jomajoma000000 000000 #ifndef RIGPARAMS_H #define RIGPARAMS_H #include #include struct scatParams { QString configLabel; QString serialPort; /**< serial port device*/ QString radioModel; int radioModelNumber; QString civAddress; int baudrate; /**< serial port baudrate*/ QString parity; int stopbits; int databits; QString handshake; bool enableCAT; bool enableSerialPTT; QString pttSerialPort; bool activeRTS; bool activeDTR; bool nactiveRTS; bool nactiveDTR; ptt_type_t pttType; bool enableXMLRPC; int XMLRPCPort; double txOnDelay; }; #endif // RIGPARAMS_H qsstv_8.2.12/qsstv/scope/plotform.ui000664 001750 001750 00000015611 12440612574 017471 0ustar00jomajoma000000 000000 plotForm 0 0 866 524 Scope 2 1 0 10 2 300 0 QFrame::Box QFrame::Sunken 2 false 300 0 QFrame::Box QFrame::Sunken 2 false 300 0 QFrame::Box QFrame::Sunken 2 false Qt::Horizontal QSizePolicy::Expanding 74 20 75 true < 75 true > Samples true Qt::Horizontal QSizePolicy::Expanding 73 20 2 Position 1 0 150 0 Zoom 10 0 150 0 QwtPlot QFrame
qwt_plot.h
1
QwtWheel QWidget
qwt_wheel.h
qsstv_8.2.12/qsstv/scope/scopeoffset.cpp000664 001750 001750 00000000572 12440612574 020314 0ustar00jomajoma000000 000000 #include "scopeoffset.h" #include "ui_scopeoffset.h" scopeOffset::scopeOffset(QWidget *parent) : QDialog(parent), ui(new Ui::scopeOffset) { ui->setupUi(this); } scopeOffset::~scopeOffset() { delete ui; } void scopeOffset::setOffset(unsigned int offset) { ui->spinBox->setValue(offset); } unsigned int scopeOffset::getOffset() { return ui->spinBox->value(); } qsstv_8.2.12/qsstv/scope/scopeoffset.h000664 001750 001750 00000000546 12440612574 017762 0ustar00jomajoma000000 000000 #ifndef SCOPEOFFSET_H #define SCOPEOFFSET_H #include namespace Ui { class scopeOffset; } class scopeOffset : public QDialog { Q_OBJECT public: explicit scopeOffset(QWidget *parent = 0); ~scopeOffset(); void setOffset(unsigned int offset); unsigned int getOffset(); private: Ui::scopeOffset *ui; }; #endif // SCOPEOFFSET_H qsstv_8.2.12/qsstv/scope/scopeoffset.ui000664 001750 001750 00000004113 12440612574 020142 0ustar00jomajoma000000 000000 scopeOffset 0 0 417 149 Scope Sample Offset Select offset 10000 10 K samples Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() scopeOffset accept() 248 254 157 274 buttonBox rejected() scopeOffset reject() 316 260 286 274 qsstv_8.2.12/qsstv/scope/scopeplot.cpp000664 001750 001750 00000034726 12474354470 020021 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2008 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "scopeplot.h" #include "qwt_plot.h" #include "qwt_plot_curve.h" #include "qwt_plot_grid.h" #include "qwt_plot_marker.h" #include "qwt_plot_canvas.h" #include "qwt_plot_picker.h" #include "qwt_picker_machine.h" #include "qwt_legend_label.h" #include "qwt_symbol.h" #include #include #include scopePlot::scopePlot(QString title, QWidget *parent) : QMainWindow(parent) { wd=new QWidget(this); ui.setupUi(wd); mrk1=0; mrk2=0; initActions(); initMenuBar(); initToolBar(); initStatusBar(); curve1 = new QwtPlotCurve("Curve 1"); curve2 = new QwtPlotCurve("Curve 2"); curve3 = new QwtPlotCurve("Curve 3"); curve4 = new QwtPlotCurve("Curve 4"); xScaleMul=1.; xPrimeScaleMul=1.; xAltScaleMul=1; xAxisTitle="Samples"; xAltAxisTitle="Time (s)"; toggleMarker=false; showCrv1=true; showCrv2=true; showCrv3=true; showCrv4=true; init(title); } scopePlot::~scopePlot() { delete curve1; delete curve2; delete curve3; delete curve4; delete toolsMenu; } void scopePlot::setXScaleMultiplier(double mul) { xPrimeScaleMul=mul; xScaleMul=mul; } void scopePlot::setAlternativeScaleMultiplier(double mul) { xAltScaleMul=mul; } void scopePlot::initActions() { zoomAction = new QAction(QIcon(":/icons/viewmagplus.png"), tr("&Zoom"), this); zoomAction->setCheckable(true); zoomAction->setStatusTip(tr("Zoom in or out")); connect(zoomAction, SIGNAL(toggled(bool)), this, SLOT(slotZoom(bool))); } void scopePlot::initMenuBar() { toolsMenu=new QMenu(tr("&Zoom")); toolsMenu->addAction(zoomAction); menuBar()->addMenu(toolsMenu); } void scopePlot::initToolBar() { } void scopePlot::initStatusBar() { } void scopePlot::init(QString title) { setup=true; setCentralWidget(wd); connect(ui.offsetWheel, SIGNAL(valueChanged(double)),SLOT(slotOffsetChanged(double ))); connect(ui.rangeWheel, SIGNAL(valueChanged(double)), SLOT(slotRangeChanged(double ))); connect(ui.samplesPushButton, SIGNAL(clicked()), this, SLOT(slotSamplesButtton())); plW=ui.plotWindow; plW->setTitle(title); plW->setCanvasBackground(Qt::darkBlue); curve1->attach(plW); curve2->attach(plW); curve3->attach(plW); curve4->attach(plW); plW->setAxisTitle(QwtPlot::xBottom,xAxisTitle); plW->setAxisScale(QwtPlot::xBottom, 0, 100); plW->setAxisTitle(QwtPlot::yLeft, "Values"); plW->setAxisScale(QwtPlot::yLeft, -1.5, 1.5); QwtPlotGrid *grid = new QwtPlotGrid; grid->enableXMin(true); grid->setMajorPen(QPen(Qt::white, 0, Qt::DotLine)); grid->setMinorPen(QPen(Qt::gray, 0 , Qt::DotLine)); grid->attach(plW); QwtText m1("M1"); m1.setColor(QColor(Qt::white)); marker1=new QwtPlotMarker(); marker1->setValue(0.0, 0.0); marker1->setLabel(m1); marker1->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom); marker1->setLinePen(QPen(QColor(200,150,0), 0, Qt::DashDotLine)); marker1->setSymbol( new QwtSymbol(QwtSymbol::Diamond,QColor(Qt::green), QColor(Qt::green), QSize(7,7))); // marker1->hide(); marker1->attach(plW); QwtText m2("M2"); m2.setColor(QColor(Qt::white)); marker2=new QwtPlotMarker(); marker2->setValue(0.0, 0.0); marker2->setLabel(m2); marker2->setLabelAlignment(Qt::AlignLeft | Qt::AlignTop); marker2->setLinePen(QPen(QColor(200,150,0), 0, Qt::DashDotLine)); marker2->setSymbol( new QwtSymbol(QwtSymbol::Diamond,QColor(Qt::yellow), QColor(Qt::yellow), QSize(7,7))); // marker2->hide(); marker2->attach(plW); legend = new QwtLegend; legend->setFrameStyle(QFrame::Box|QFrame::Sunken); legend->setDefaultItemMode(QwtLegendData::Checkable); QPalette pal(legend->palette()); pal.setColor(QPalette::Window,Qt::darkBlue); pal.setColor(QPalette::WindowText,Qt::white); pal.setColor(QPalette::Text,Qt::black); legend->setPalette(pal); plW->insertLegend(legend, QwtPlot::BottomLegend); picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOn, plW->canvas()); picker->setStateMachine(new QwtPickerDragPointMachine()); picker->setRubberBandPen(QColor(Qt::green)); picker->setRubberBand(QwtPicker::CrossRubberBand); picker->setTrackerPen(QColor(Qt::white)); picker->setEnabled(true); plW->replot(); QwtPlotItemList items = plW->itemList( QwtPlotItem::Rtti_PlotCurve); for ( int i = 0; i < items.size(); i++ ) { const QVariant itemInfo = plW->itemToInfo( items[i] ); QwtLegendLabel *legendLabel =qobject_cast( legend->legendWidget( itemInfo ) ); if (legendLabel ) { legendLabel->setChecked( true ); } items[i]->setVisible( true ); } connect(picker, SIGNAL(moved(const QPointF &)),SLOT(pickerMoved(const QPointF &))); connect(picker, SIGNAL(selected(const QPointF &)), SLOT(pickerSelected(const QPointF &))); connect(legend, SIGNAL(checked(const QVariant &, bool ,int)),SLOT(legendClicked(const QVariant &,bool))); connect(ui.nextButton, SIGNAL(clicked()),SLOT(slotNext())); connect(ui.previousButton, SIGNAL(clicked()),SLOT(slotPrevious())); plW->setAxisTitle(QwtPlot::xBottom,xAxisTitle); xOffset=0; } void scopePlot::setCurveOn(int i,bool b) { QwtPlotItemList items = plW->itemList( QwtPlotItem::Rtti_PlotCurve); if(i>=items.size()) return; const QVariant itemInfo = plW->itemToInfo( items[i] ); QwtLegendLabel *legendLabel =qobject_cast( legend->legendWidget( itemInfo ) ); if (legendLabel ) { legendLabel->setChecked(b); } items[i]->setVisible( b ); } void scopePlot::slotSamplesButtton() { long i; if (ui.samplesPushButton->isChecked()) { ui.samplesPushButton->setText(xAltAxisTitle); plW->setAxisTitle(QwtPlot::xBottom,xAltAxisTitle); xScaleMul=xAltScaleMul; ui.offsetWheel->setSingleStep(10*xScaleMul); ui.rangeWheel->setSingleStep(10*xScaleMul); } else { ui.samplesPushButton->setText(xAxisTitle); plW->setAxisTitle(QwtPlot::xBottom,xAxisTitle); xScaleMul=xPrimeScaleMul; ui.offsetWheel->setSingleStep(1); ui.rangeWheel->setSingleStep(1); } for(i=0;isetPageStepCount(10); ui.rangeWheel->setPageStepCount(10); if(x.size()==c1.size()) curve1->setSamples(x.data(), c1.data(), x.size()); if(x.size()==c3.size()) curve2->setSamples(x.data(), c3.data(), x.size()); if(x.size()==c3.size()) curve3->setSamples(x.data(), c3.data(), x.size()); if(x.size()==c4.size()) curve4->setSamples(x.data(), c4.data(), x.size()); setupWheels(x.size()); plW->replot(); } void scopePlot::plot1DUpdate(double *data) { for (long i = 0; i < c1.size(); i++) { c1[i]=data[i]; } curve1->setSamples(x.data(), c1.data(), x.size()); plW->replot(); } void scopePlot::plotData(unsigned int size, short int * iData, QString curve1Name,QString yLLabel, double * dData, QString curve2Name, QString yRLabel) { add1(iData,size,curve1Name,yLLabel); add3(dData,size,curve2Name,yRLabel); show(); } void scopePlot::plotData(unsigned int size, double * dData1, QString curve1Name, QString yLLabel, double * dData2, QString curve2Name, QString yRLabel) { add1(dData1,size,curve1Name,yLLabel); add3(dData2,size,curve2Name,yRLabel); show(); } void scopePlot::add1(short int *data, unsigned long len,QString name,QString yLeftLabel) { x.resize(len); c1.resize(len); for (unsigned long i = 0; i < len; i++) { x[i]=(double)(i+xOffset)*xScaleMul; c1[i]=(double)data[i]; } plot1(name,yLeftLabel); } void scopePlot::add1(double *data, unsigned long len,QString curveName,QString yLeftLabel) { x.resize(len); c1.resize(len); for (unsigned long i = 0; i < len; i++) { x[i]=(double)(i+xOffset)*xScaleMul; c1[i]=data[i]; } plot1(curveName,yLeftLabel); } void scopePlot::add2(double *data, unsigned long len,QString curveName) { c2.resize(len); for (unsigned long i = 0; i < len; i++) { c2[i]=data[i]; } plot2(curveName); } void scopePlot::add3(double *data, unsigned long len,QString curveName,QString yRightLabel) { c3.resize(len); for (unsigned long i = 0; i < len; i++) { c3[i]=data[i]; } plot3(curveName,yRightLabel); } void scopePlot::add4(double *data, unsigned long len,QString curveName) { c4.resize(len); for (unsigned long i = 0; i < len; i++) { c4[i]=data[i]; } plot4(curveName); } void scopePlot::show() { QMainWindow::show(); plW->show(); plW->replot(); } void scopePlot::refresh() { plW->replot(); } void scopePlot::plot1(QString curveName,QString yLeftLabel) { plW->setAxisTitle(QwtPlot::yLeft, yLeftLabel); plW->setAxisAutoScale(QwtPlot::yLeft); plW->setAxisAutoScale(QwtPlot::xBottom); curve1->setTitle(curveName); curve1->setPen(QPen(Qt::yellow)); curve1->setYAxis(QwtPlot::yLeft); curve1->setSamples(x.data(), c1.data(), x.size()); setupWheels(x.size()); } void scopePlot::plot2(QString curveName) { // axes plW->setAxisAutoScale(QwtPlot::yLeft); plW->enableAxis(QwtPlot::yLeft); curve2->setTitle(curveName); curve2->setPen(QPen(Qt::red)); curve2->setYAxis(QwtPlot::yLeft); curve2->setSamples(x.data(), c2.data(), x.size()); plW->replot(); } void scopePlot::plot3(QString curveName,QString yRightLabel) { // axes plW->setAxisTitle(QwtPlot::yRight,yRightLabel); plW->enableAxis(QwtPlot::yRight); curve3->setTitle(curveName); curve3->setPen(QPen(Qt::green)); curve3->setYAxis(QwtPlot::yRight); curve3->setSamples(x.data(), c3.data(), x.size()); plW->setAxisAutoScale(QwtPlot::yRight); plW->replot(); } void scopePlot::plot4(QString curveName) { // axes plW->setAxisAutoScale(QwtPlot::yRight); plW->enableAxis(QwtPlot::yRight); curve4->setTitle(curveName); curve4->setPen(QPen(Qt::white)); curve4->setYAxis(QwtPlot::yRight); curve4->setSamples(x.data(), c4.data(), x.size()); plW->replot(); } void scopePlot::slotZoom(bool) { } void scopePlot::slotOffsetChanged(double ioffset) { if (setup) return; if((ioffset-range/2)setValue(startPoint+range/2); return; } if((ioffset+range/2)>endPoint) { ui.offsetWheel->setValue(endPoint-range/2); return; } dispCenter=ioffset; plW->setAxisScale(QwtPlot::xBottom,dispCenter-range/2,dispCenter+range/2); plW->replot(); } void scopePlot::slotRangeChanged(double irange) { if (setup) return; if((dispCenter-irange/2)setValue((dispCenter-startPoint)*1.999); return; } if((dispCenter+irange/2)>endPoint) { ui.rangeWheel->setValue((endPoint-dispCenter)*1.999); return; } range=irange; plW->setAxisScale(QwtPlot::xBottom,dispCenter-range/2,dispCenter+range/2); plW->replot(); } void scopePlot::setupWheels(int size) { setup=true; // offset is from 0 to size-range // range is from 10 to if (x.size()==0) { QMessageBox::warning(0,"Scope Plot", "No data in Scope Plot" , QMessageBox::Ok,0 ); return; } blockSignals(true); startPoint=x[0]; endPoint=x[size-1]; range=endPoint-startPoint; dispCenter=(endPoint+startPoint)/2; ui.offsetWheel->setMass(0.5); ui.rangeWheel->setMass(0.5); ui.offsetWheel->setRange(startPoint, endPoint); ui.offsetWheel->setTotalAngle(3600.0); ui.rangeWheel->setRange(range/200., range); // range=endPoint-startPoint; ui.rangeWheel->setTotalAngle(3600.0); blockSignals(false); ui.offsetWheel->setValue(dispCenter); ui.rangeWheel->setValue(range); setup=false; plW->setAxisScale(QwtPlot::xBottom,dispCenter-range/2,dispCenter+range/2); } void scopePlot::pickerMoved(const QPointF &pos) { QString info; info.sprintf("x=%7g, yL=%7g, yR=%7g", plW->invTransform(QwtPlot::xBottom, pos.x()), plW->invTransform(QwtPlot::yLeft, pos.y()), plW->invTransform(QwtPlot::yRight, pos.y()) ); // ui.positionLabel->setText(info); } void scopePlot::pickerSelected(const QPointF &pos) { // qDebug() << "selected" << toggleMarker; if (!toggleMarker) { marker1->setValue(pos); } else { marker2->setValue(pos); } toggleMarker=!toggleMarker; showMarker(); plW->replot(); } void scopePlot::showMarker() { QString t1,t2,t3; t1="M1 : "+QString::number(marker1->xValue(),'g',7).rightJustified(11)+QString::number(marker1->yValue(),'g',7).rightJustified(11); t2="M2 : "+QString::number(marker2->xValue(),'g',7).rightJustified(11)+QString::number(marker2->yValue(),'g',7).rightJustified(11); t3="DIF: "+QString::number(marker2->xValue()-marker1->xValue(),'g',7).rightJustified(11)+QString::number(marker2->yValue()-marker1->yValue(),'g',7).rightJustified(11); ui.marker1Label->setText(t1); ui.marker2Label->setText(t2); ui.marker3Label->setText(t3); } void scopePlot::legendClicked(const QVariant &itemInfo, bool on) { QwtPlotItem *plotItem = plW->infoToItem( itemInfo ); if ( plotItem ) { plotItem->setVisible( on ); plW->replot(); } } qsstv_8.2.12/qsstv/scope/scopeplot.h000664 001750 001750 00000012543 12440612574 017452 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2008 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef SCOPEPLOT_H #define SCOPEPLOT_H #include #include #include "ui_plotform.h" #include "qwt_plot.h" #include "qwt_legend.h" class QwtPlotCurve; class QwtPlotMarker; class QwtPlotPicker; /**Data plotting in scope format *@author Johan Maes -- ON4QZ */ class scopePlot : public QMainWindow { Q_OBJECT public: scopePlot(QString title,QWidget *parent=0); ~scopePlot(); void setXScaleMultiplier(double mul); void setAlternativeScaleMultiplier(double mul); void setOffset(unsigned int offset) {xOffset=offset;} void init(QString title=QString::null); void add1(short int *data, unsigned long len,QString curveName,QString yLeftLabel); void add1(double *data, unsigned long len,QString curveName,QString yLeftLabel); void add2(double *data, unsigned long len,QString curveName); void add3(double *data, unsigned long len,QString curveName,QString yRightLabel); void add4(double *data, unsigned long len,QString curveName); void plot1(QString name,QString yLeftLabel); void plot2(QString curveName); void plot3(QString curveName,QString yRightLabel); void plot4(QString curveName); void plotData(unsigned int size, short int * iData, QString curve1Name, QString yLLabel, double * dData, QString curve2Name, QString yRLabel); void plotData(unsigned int size, double * dData1, QString curve1Name, QString yLLabel, double * dData2, QString curve2Name, QString yRLabel); void show(); void plot1DUpdate(double *data); void XYL(unsigned int i,int ix,int iy) { x[i]=(double)ix; c1[i]=(double)iy; } void X(unsigned int i,int ix) { x[i]=(double)ix; } void YL(unsigned int i,int iy) { c1[i]=(double)iy; } void YR(unsigned int i,int iy) { c3[i]=(double)iy; } void XYLYR(unsigned int i,int ix,int iyl,int iyr) { x[i]=(double)ix; c1[i]=(double)iyl; c3[i]=(double)iyr; } void XYL(unsigned int i,double ix,double iy) { x[i]=ix; c1[i]=iy; } void X(unsigned int i,double ix) { x[i]=ix; } void YL(unsigned int i,double iy) { c1[i]=iy; } void YR(unsigned int i,double iy) { c3[i]=iy; } void XYLYR(unsigned int i,double ix,double iyl,double iyr) { x[i]=ix; c1[i]=iyl; c3[i]=iyr; } void resize(unsigned long i) { x.resize(i); c1.resize(i); c3.resize(i); } void refresh(); public slots: void slotZoom(bool b); void slotOffsetChanged(double offset); void slotRangeChanged(double range); void pickerMoved(const QPointF &pos); void pickerSelected(const QPointF &pos); // void plotMouseMoved(const QMouseEvent &e); // void plotMouseReleased(const QMouseEvent &e); void legendClicked(const QVariant &itemInfo, bool on); void slotNext() { emit next(); } void slotPrevious() { emit previous(); } void slotSamplesButtton(); void setCurveOn(int i,bool b); signals: void next(); void previous(); private: QwtPlot *plW; QToolBar *toolsToolbar; QMenu *toolsMenu; QAction *zoomAction; // plotForm *pl; QVector x; QVector c1; QVector c2; QVector c3; QVector c4; double startPoint; double endPoint; double dispCenter; void initActions(); void initMenuBar(); void initToolBar(); void initStatusBar(); void setupWheels(int size); double xScaleMul; double xPrimeScaleMul; double xAltScaleMul; bool setup; long int mrk1,mrk2; void showMarker(); bool toggleMarker; bool showCrv1; bool showCrv2; bool showCrv3; bool showCrv4; Ui::plotForm ui; QWidget *wd; QwtPlotCurve *curve1; QwtPlotCurve *curve2; QwtPlotCurve *curve3; QwtPlotCurve *curve4; QwtPlotMarker *marker1; QwtPlotMarker *marker2; QwtLegend *legend; QwtPlotPicker *picker; QString xAxisTitle; QString xAltAxisTitle; double range; unsigned int xOffset; }; #endif qsstv_8.2.12/qsstv/scope/scopeview.cpp000664 001750 001750 00000017611 12440612574 020002 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #include "scopeview.h" #include "utils/loggingparams.h" scopeView::scopeView(QString title) : scopePlot(title) { xOffset=0; init(); } scopeView::~scopeView() { } void scopeView::init() { int i; index=0; for (i=0;iSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,float *data,unsigned int position,unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx, qint8 *data, unsigned int position, unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,quint8 *data, unsigned int position, unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,qint16 *data,unsigned int position,unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,quint16 *data,unsigned int position,unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,qint32 *data,unsigned int position,unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::addData(ecurve Idx,quint32 *data,unsigned int position,unsigned int len) { unsigned int i,j; double *ar; if(positionSCOPEMAXDATA) i=SCOPEMAXDATA; index=i; addToLog(QString("data1 %1").arg(index+xOffset),LOGSCOPE); } void scopeView::setCurveName(QString title,int idx) { if((idx>=0)&&(idx<=SCDATA4)) { curveNameArray[idx]=title; } } void scopeView::show(bool d1,bool d2,bool d3,bool d4) { if(d1) { add1(array1,index,curveNameArray[SCDATA1],yLeftTitle); setCurveOn(SCDATA1,true); } else setCurveOn(SCDATA1,false); if(d2) { add2(array2,index,curveNameArray[SCDATA2]); setCurveOn(SCDATA2,true); } else setCurveOn(SCDATA2,false); if (d3) { add3(array3,index,curveNameArray[SCDATA3],yRightTitle); setCurveOn(SCDATA3,true); } else setCurveOn(SCDATA3,false); if (d4) { add4(array4,index,curveNameArray[SCDATA4]); setCurveOn(SCDATA4,true); } else setCurveOn(SCDATA4,false); scopePlot::show(); } qsstv_8.2.12/qsstv/scope/scopeview.h000664 001750 001750 00000007306 12440612574 017447 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2005 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of this program with any edition of * * the Qt library by Trolltech AS, Norway (or with modified versions * * of Qt that use the same license as Qt), and distribute linked * * combinations including the two. You must obey the GNU General * * Public License in all respects for all of the code used other than * * Qt. If you modify this file, you may extend this exception to * * your version of the file, but you are not obligated to do so. If * * you do not wish to do so, delete this exception statement from * * your version. * ***************************************************************************/ #ifndef SCOPEVIEW_H #define SCOPEVIEW_H #include "qsstvglobal.h" #include #include "scopeplot.h" #define SCOPEMAXDATA 200000 /** @author Johan Maes */ enum ecurve{SCDATA1,SCDATA2,SCDATA3,SCDATA4}; #define NUMCURVES 4 class scopeView: public scopePlot { public: scopeView(QString title); ~scopeView(); void init(); void setOffset (int xoffset); void addData(ecurve Idx,double *data,unsigned int position,unsigned int len); void addData(ecurve Idx,float *data,unsigned int position,unsigned int len); void addData(ecurve Idx,qint8 *data,unsigned int position,unsigned int len); void addData(ecurve Idx,quint8 *data,unsigned int position,unsigned int len); void addData(ecurve Idx,qint16 *data,unsigned int position,unsigned int len); void addData(ecurve Idx,quint16 *data,unsigned int position,unsigned int len); void addData(ecurve Idx,qint32 *data,unsigned int position,unsigned int len); void addData(ecurve Idx,quint32 *data,unsigned int position,unsigned int len); void show(bool data,bool sync,bool state,bool d4); void setCurveName(QString title,int idx); void setAxisTitles(QString x,QString yData1,QString yData2) { xTitle=x; yLeftTitle=yData1; yRightTitle=yData2; } private: double array1[SCOPEMAXDATA]; double array2[SCOPEMAXDATA]; double array3[SCOPEMAXDATA]; double array4[SCOPEMAXDATA]; unsigned int index; QString curveNameArray[NUMCURVES]; QString xTitle; QString yLeftTitle; QString yRightTitle; unsigned int xOffset; }; #endif qsstv_8.2.12/qsstv/sound/calibration.cpp000664 001750 001750 00000013470 12440612574 020303 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "calibration.h" #include "ui_calibration.h" #include #include "qsstvglobal.h" #include "sound/soundio.h" #include #include "QMessageBox" #include #define ITERATIONS 100 /** * \class calibration * * Check first if ntp is running and it is synchronised. A dialog window will appear and show the progress ofr the RX and TX clocks. * About 10000 blocks of data will be read/written to calculate the exact timing. If the OK button is pressed, the clocks will be saved for later use. * **/ /** * @brief Calibration constructor * * @param parent parent widget pointer */ calibration::calibration(QWidget *parent) : QDialog(parent), ui(new Ui::calibration) { ui->setupUi(this); init(); } calibration::~calibration() { delete ui; } /** * @brief start calibration * * Call this function to start the calibration proces. The use the results, check the return status and get the value of the clocks by calling getRXClock() and getTXClock(). * * \sa getRXClock() \sa getTXClock() * * @return bool true if calibration is successful. Return false if an error occured or the dialog was canceled */ int calibration::exec() { init(); show(); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); if(!start(true)) return QDialog::Rejected; if(!start(false)) return QDialog::Rejected; ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); while(!stopped) { qApp->processEvents(); } if(!canceled) return QDialog::Accepted; return QDialog::Rejected; } /** * @brief initialize * * This function is called by exec to initialize the calibration and setup the dialog box * */ void calibration::init() { stopped=false; canceled=false; // find out if we working with nanoseconds or microseconds ui->rxProgress->setMaximum(ITERATIONS-1); ui->txProgress->setMaximum(ITERATIONS-1); ui->rxProgress->setValue(0); ui->txProgress->setValue(0); display(BASESAMPLERATE,ui->rxLCD); display(BASESAMPLERATE,ui->txLCD); connect(this,SIGNAL(finished(int)),SLOT(hasFinished(int))); } /** * @brief slot for finish * * This slot is called when the dialog is closed by pressing CANCEL or OK. It will abort the loop executed in start and set the bool canceled to false or true * depending on the CANCEL or OK button being presssed. **/ void calibration::hasFinished(int result) { stopped=true; if(result==QDialog::Rejected) canceled=true; } /** * @brief initialize * * @param bool isRX: If isRX is set then the receive clock will be calibrated, else the transmit clock will be calibrated. * * Start is called by exec and performs the clock calibration using NTP (Network Time Protocol). * It starts counting when the first 100 blocks are read or when the first 100 blocks are written in order to start with a stable condition. * @return bool returns true if calibration is successful or false when either the CANCEL button was pressed or a read NTP time erro has occured. * **/ bool calibration::start(bool isRX) { unsigned int i; double clock=48000; int frames; int framesDone=-1; int elapsed; QString blockStr; if(isRX) { blockStr="blockRX: "; } else { blockStr="blockTX: "; } if(!soundIOPtr->startCalibration(isRX)) { QMessageBox::critical(this,"Calibration Error","Souncard not active"); return false; } for(i=0;iprocessEvents(); if(!soundIOPtr->isRunning()) return false; elapsed=soundIOPtr->calibrationCount(frames); if((frames%50==0)&&(frames>0)&&(frames!=framesDone)) { i++; framesDone=frames; clock=((double)frames*1000.*PERIODSIZE)/((double)elapsed); if(isRX) { display(clock,ui->rxLCD); ui->rxProgress->setValue(i); } else { display(clock,ui->txLCD); ui->txProgress->setValue(i); } } } soundIOPtr->idle(); if(isRX) { rxCardClock=clock; } else { txCardClock=clock; } return true; } void calibration::display(double value,QLCDNumber *dspl) { QString tmp=QString::number(value,'g',7); switch(tmp.length()) { case 5: tmp+=".00"; break; case 6: tmp+="00"; break; case 7: tmp+="0"; break; } dspl->display(tmp); } qsstv_8.2.12/qsstv/sound/calibration.h000664 001750 001750 00000001536 12440612574 017750 0ustar00jomajoma000000 000000 #ifndef CALIBRATION_H #define CALIBRATION_H #include #include class QLCDNumber; namespace Ui { class calibration; } class calibration : public QDialog { Q_OBJECT public: explicit calibration(QWidget *parent = 0); ~calibration(); int exec(); /** ** @brief get calibrated receive clock * * @return double calibrated value of the rxclock */ double getRXClock() {return rxCardClock;} /** * @brief get calibrated transmit clock * * @return double calibrated value of the txclock */ double getTXClock(){return txCardClock;} public slots: void hasFinished(int result); private: Ui::calibration *ui; double rxCardClock; double txCardClock; bool stopped; void init(); bool start(bool isRX); void display(double value,QLCDNumber *dspl); bool canceled; }; #endif // CALIBRATION_H qsstv_8.2.12/qsstv/sound/calibration.ui000664 001750 001750 00000051057 12440612574 020141 0ustar00jomajoma000000 000000 calibration 0 0 488 207 Soundcard Calibration RX Clock 24 144 46 85 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 0 76 76 76 255 85 0 0 0 255 85 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 0 76 76 76 255 85 0 0 0 255 255 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 0 255 0 0 255 true 2 2 false 8 8 QLCDNumber::Filled 48000.000000000000000 48000 TX Clock 24 144 46 85 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 0 76 76 76 255 85 0 0 0 255 85 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 0 76 76 76 255 85 0 0 0 255 255 255 255 0 0 255 255 255 127 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 0 255 0 0 255 true 2 2 false 8 8 QLCDNumber::Filled 48000.000000000000000 48000 Qt::Vertical 20 238 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() calibration accept() 248 254 157 274 buttonBox rejected() calibration reject() 316 260 286 274 qsstv_8.2.12/qsstv/sound/calibrationform.ui000664 001750 001750 00000005632 12440612574 021023 0ustar00jomajoma000000 000000 CalibrationForm 0 0 345 96 0 0 16777215 110 Calibration 150 0 RX 24 150 0 TX 24 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok true buttonBox accepted() CalibrationForm accept() 248 254 157 274 buttonBox rejected() CalibrationForm reject() 316 260 286 274 qsstv_8.2.12/qsstv/sound/resamplefilter.cpp000664 001750 001750 00000006617 12440612574 021037 0ustar00jomajoma000000 000000 /* Automatically generated file with MATLAB */ /* File name: "ResampleFilter.m" */ /* Filter taps in time-domain */ #include "resamplefilter.h" /* Filter for ratios close to 1 */ float fResTaps1To1[INTERP_DECIM_I_D][RES_FILT_NUM_TAPS_PER_PHASE] = { { -0.00129181992672801360f, 0.00561586829442904840f, -0.01349857823816511800f, 0.02541150940858524100f, -0.04267869501534898200f, 0.07724474282951483700f, 0.96609875058711103000f, -0.01641812005088002400f, -0.00427135103965109450f, 0.00726225824406205160f, -0.00544188094946287510f, 0.00266742068076876060f }, { -0.00207886551285772290f, 0.00866090598717600930f, -0.02161960909069559500f, 0.04383507935997314800f, -0.08302470868585065700f, 0.18738870090358245000f, 0.93524350914423104000f, -0.09031872116141286000f, 0.02909509423931267600f, -0.00897188476756275060f, 0.00178311012364952820f, 0.00010586149691723067f }, { -0.00287519800425638110f, 0.01143197533872717000f, -0.02889142869399521600f, 0.06060641890050100900f, -0.12152802242786863000f, 0.30933747340895279000f, 0.87539536840978205000f, -0.14271415809850990000f, 0.05516985095031713000f, -0.02205265100214613000f, 0.00761119378345958850f, -0.00187713739944610450f }, { -0.00354120720771153910f, 0.01351098086300389300f, -0.03433664370844288100f, 0.07367662235517660800f, -0.15398027155782226000f, 0.43728178746780866000f, 0.79013921003423337000f, -0.17341770937821352000f, 0.07263788052016696700f, -0.03120859084480779800f, 0.01170664402374247200f, -0.00319259334815649940f }, { -0.00391755659664638590f, 0.01447751287549226700f, -0.03701682481313090000f, 0.08107302414568577600f, -0.17606165300033697000f, 0.56464344237183917000f, 0.68451472884717957000f, -0.18369620562420094000f, 0.08111657494320076400f, -0.03614676421513295800f, 0.01396276906259418800f, -0.00384568128202934270f }, { -0.00384568128202934270f, 0.01396276906259418800f, -0.03614676421513295800f, 0.08111657494320076400f, -0.18369620562420094000f, 0.68451472884717957000f, 0.56464344237183917000f, -0.17606165300033697000f, 0.08107302414568577600f, -0.03701682481313090000f, 0.01447751287549226700f, -0.00391755659664638590f }, { -0.00319259334815649940f, 0.01170664402374247200f, -0.03120859084480779800f, 0.07263788052016696700f, -0.17341770937821352000f, 0.79013921003423337000f, 0.43728178746780866000f, -0.15398027155782226000f, 0.07367662235517660800f, -0.03433664370844288100f, 0.01351098086300389300f, -0.00354120720771153910f }, { -0.00187713739944610450f, 0.00761119378345958850f, -0.02205265100214613000f, 0.05516985095031713000f, -0.14271415809850990000f, 0.87539536840978205000f, 0.30933747340895279000f, -0.12152802242786863000f, 0.06060641890050100900f, -0.02889142869399521600f, 0.01143197533872717000f, -0.00287519800425638110f }, { 0.00010586149691723067f, 0.00178311012364952820f, -0.00897188476756275060f, 0.02909509423931267600f, -0.09031872116141286000f, 0.93524350914423104000f, 0.18738870090358245000f, -0.08302470868585065700f, 0.04383507935997314800f, -0.02161960909069559500f, 0.00866090598717600930f, -0.00207886551285772290f }, { 0.00266742068076876060f, -0.00544188094946287510f, 0.00726225824406205160f, -0.00427135103965109450f, -0.01641812005088002400f, 0.96609875058711103000f, 0.07724474282951483700f, -0.04267869501534898200f, 0.02541150940858524100f, -0.01349857823816511800f, 0.00561586829442904840f, -0.00129181992672801360f } }; qsstv_8.2.12/qsstv/sound/resamplefilter.h000664 001750 001750 00000000613 12440612574 020472 0ustar00jomajoma000000 000000 /* Automatically generated file with MATLAB */ /* File name: "ResampleFilter.m" */ /* Filter taps in time-domain */ #ifndef _RESAMPLEFILTER_H_ #define _RESAMPLEFILTER_H_ #define RES_FILT_NUM_TAPS_PER_PHASE 12 #define INTERP_DECIM_I_D 10 /* Filter for ratios close to 1 */ extern float fResTaps1To1[INTERP_DECIM_I_D][RES_FILT_NUM_TAPS_PER_PHASE]; #endif /* _RESAMPLEFILTER_H_ */ qsstv_8.2.12/qsstv/sound/resampler.cpp000664 001750 001750 00000012733 12440612574 020007 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * Based on software from * * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * * Author(s): * * Volker Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "resampler.h" #include "qsstvglobal.h" #include "sound/soundio.h" /** * @brief Resample routine for arbitrary sample-rate conversions * * Resample routine for arbitrary sample-rate conversions in a low range (for * frequency offset correction). * The algorithm is based on a polyphase structure. We upsample the input * signal with a factor INTERP_DECIM_I_D and calculate two successive samples * whereby we perform a linear interpolation between these two samples to get * an arbitraty sample grid. * * @param prInput input buffer data (e.g. soundcard) * @param prOutput output buffer (resampled data) * @param rRation conversion ratio * @return int */ resampler::resampler() { resamplerBuffer=NULL; } resampler::~resampler() { if(resamplerBuffer!=NULL) delete resamplerBuffer; } /** * @brief resample the audio data * * When this function is called, there is already enough data in the sound carad buffers * * @param rRation the resample ratio */ void resampler::resample(DSPFLOAT rRation, DSPFLOAT *inputBuffer) { unsigned int i; /* Move old data from the end to the history part of the buffer and add new data (shift register) */ for (i = 0; i < iHistorySize; i++) resamplerBuffer[i] = resamplerBuffer[i + iInputBlockSize]; for (i = 0; i < iInputBlockSize; i++) resamplerBuffer[i + iHistorySize] = inputBuffer[i]; /* Sample-interval of new sample frequency in relation to interpolated sample-interval */ rTStep = (DSPFLOAT) INTERP_DECIM_I_D / rRation; /* Init output counter */ int im = 0; // if (input_samples_buffer_request == 0) /* no resampling needed, just copy */ { im = iInputBlockSize; for (i = 0; i < iInputBlockSize; i++) rxBuffer.put(resamplerBuffer[i + iHistorySize]); return ; } /* Main loop */ do { /* Quantize output-time to interpolated time-index */ const int ik = (int) rtOut; /* Calculate convolutions for the two interpolation-taps ------------ */ /* Phase for the linear interpolation-taps */ const int ip1 = ik % INTERP_DECIM_I_D; const int ip2 = (ik + 1) % INTERP_DECIM_I_D; /* Sample positions in input vector */ const int in1 = (int) (ik / INTERP_DECIM_I_D); const int in2 = (int) ((ik + 1) / INTERP_DECIM_I_D); /* Convolution */ DSPFLOAT ry1 = (DSPFLOAT) 0.0; DSPFLOAT ry2 = (DSPFLOAT) 0.0; for (int i = 0; i < RES_FILT_NUM_TAPS_PER_PHASE; i++) { ry1 += fResTaps1To1[ip1][i] * resamplerBuffer[in1 - i]; ry2 += fResTaps1To1[ip2][i] * resamplerBuffer[in2 - i]; } /* Linear interpolation --------------------------------------------- */ /* Get numbers after the comma */ const DSPFLOAT rxInt = rtOut - (int) rtOut; rxBuffer.put((ry2 - ry1) * rxInt + ry1); /* Increase output counter */ im++; /* Increase output-time and index one step */ rtOut = rtOut + rTStep; } while (rtOut < rBlockDuration); /* Set rtOut back */ rtOut -= iInputBlockSize * INTERP_DECIM_I_D; } void resampler::init(int blocksize) { unsigned int i; iInputBlockSize = blocksize; /* History size must be one sample larger, because we use always TWO convolutions */ iHistorySize = RES_FILT_NUM_TAPS_PER_PHASE + 1; /* Calculate block duration */ rBlockDuration = (iInputBlockSize + RES_FILT_NUM_TAPS_PER_PHASE) * INTERP_DECIM_I_D; /* Allocate memory for internal buffer, clear sample history */ resamplerBuffer= new DSPFLOAT[iInputBlockSize + iHistorySize]; for(i=0;i<(iInputBlockSize + iHistorySize);i++) resamplerBuffer[i]= 0; /* Init absolute time for output stream (at the end of the history part) */ rtOut = (DSPFLOAT) RES_FILT_NUM_TAPS_PER_PHASE * INTERP_DECIM_I_D; rxBuffer.reset(); } qsstv_8.2.12/qsstv/sound/resampler.cpp_new000664 001750 001750 00000012770 12440612574 020661 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * Based on software from * * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * * Author(s): * * Volker Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "resampler.h" #include "qsstvglobal.h" #include "sound/soundio.h" /** * @brief Resample routine for arbitrary sample-rate conversions * * Resample routine for arbitrary sample-rate conversions in a low range (for * frequency offset correction). * The algorithm is based on a polyphase structure. We upsample the input * signal with a factor INTERP_DECIM_I_D and calculate two successive samples * whereby we perform a linear interpolation between these two samples to get * an arbitraty sample grid. * * @param prInput input buffer data (e.g. soundcard) * @param prOutput output buffer (resampled data) * @param rRation conversion ratio * @return int */ resampler::resampler() { resamplerBuffer=NULL; } resampler::~resampler() { if(resamplerBuffer!=NULL) delete resamplerBuffer; } /** * @brief resample the audio data * * When this function is called, there is already enough data in the sound carad buffers * * @param rRation the resample ratio */ void resampler::resample(DSPFLOAT rRation, short int *inputBuffer) { unsigned int i; /* Move old data from the end to the history part of the buffer and add new data (shift register) */ for (i = 0; i < iHistorySize; i++) resamplerBuffer[i] = resamplerBuffer[i + iInputBlockSize]; for (i = 0; i < iInputBlockSize; i++) resamplerBuffer[i + iHistorySize] = (DSPFLOAT) inputBuffer[i]; /* Sample-interval of new sample frequency in relation to interpolated sample-interval */ rTStep = (DSPFLOAT) INTERP_DECIM_I_D / rRation; /* Init output counter */ int im = 0; if(rRation==1) // if (input_samples_buffer_request == 0) /* no resampling needed, just copy */ { im = iInputBlockSize; for (i = 0; i < iInputBlockSize; i++) rxBuffer.put(resamplerBuffer[i + iHistorySize]); return ; } /* Main loop */ do { /* Quantize output-time to interpolated time-index */ const int ik = (int) rtOut; /* Calculate convolutions for the two interpolation-taps ------------ */ /* Phase for the linear interpolation-taps */ const int ip1 = ik % INTERP_DECIM_I_D; const int ip2 = (ik + 1) % INTERP_DECIM_I_D; /* Sample positions in input vector */ const int in1 = (int) (ik / INTERP_DECIM_I_D); const int in2 = (int) ((ik + 1) / INTERP_DECIM_I_D); /* Convolution */ DSPFLOAT ry1 = (DSPFLOAT) 0.0; DSPFLOAT ry2 = (DSPFLOAT) 0.0; for (int i = 0; i < RES_FILT_NUM_TAPS_PER_PHASE; i++) { ry1 += fResTaps1To1[ip1][i] * resamplerBuffer[in1 - i]; ry2 += fResTaps1To1[ip2][i] * resamplerBuffer[in2 - i]; } /* Linear interpolation --------------------------------------------- */ /* Get numbers after the comma */ const DSPFLOAT rxInt = rtOut - (int) rtOut; rxBuffer.put((ry2 - ry1) * rxInt + ry1); /* Increase output counter */ im++; /* Increase output-time and index one step */ rtOut = rtOut + rTStep; } while (rtOut < rBlockDuration); /* Set rtOut back */ rtOut -= iInputBlockSize * INTERP_DECIM_I_D; } void resampler::init(int blocksize) { unsigned int i; iInputBlockSize = blocksize; /* History size must be one sample larger, because we use always TWO convolutions */ iHistorySize = RES_FILT_NUM_TAPS_PER_PHASE + 1; /* Calculate block duration */ rBlockDuration = (iInputBlockSize + RES_FILT_NUM_TAPS_PER_PHASE) * INTERP_DECIM_I_D; /* Allocate memory for internal buffer, clear sample history */ resamplerBuffer= new DSPFLOAT[iInputBlockSize + iHistorySize]; for(i=0;i<(iInputBlockSize + iHistorySize);i++) resamplerBuffer[i]= 0; /* Init absolute time for output stream (at the end of the history part) */ rtOut = (DSPFLOAT) RES_FILT_NUM_TAPS_PER_PHASE * INTERP_DECIM_I_D; rxBuffer.reset(); } qsstv_8.2.12/qsstv/sound/resampler.h000664 001750 001750 00000001056 12440612574 017450 0ustar00jomajoma000000 000000 #ifndef RESAMPLER_H #define RESAMPLER_H #include "resamplefilter.h" #include "qsstvdefs.h" #include "utils/buffermanag.h" /* Classes ********************************************************************/ class resampler { public: resampler(); ~resampler(); void init(int blocksize); void resample(DSPFLOAT rRation, DSPFLOAT *inputBuffer); buffer rxBuffer; protected: DSPFLOAT *resamplerBuffer; DSPFLOAT rTStep; DSPFLOAT rtOut; DSPFLOAT rBlockDuration; unsigned int iHistorySize; unsigned int iInputBlockSize; }; #endif qsstv_8.2.12/qsstv/sound/soundcontrol.cpp000664 001750 001750 00000012263 12440612574 020544 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "soundcontrol.h" #include "ui_soundcontrol.h" #include "configparams.h" #include "utils/supportfunctions.h" #include "soundio.h" #include soundControl::soundControl(QWidget *parent) : QWidget(parent), ui(new Ui::soundControl) { QStringList *inputPCMList, *outputPCMList; ui->setupUi(this); soundIOPtr->listCards(); //get input devices inputPCMList=soundIOPtr->getPCMNamList(true); ui->inputPCMNameComboBox->addItems(*inputPCMList); outputPCMList=soundIOPtr->getPCMNamList(false); ui->outputPCMNameComboBox->addItems(*outputPCMList); changed=false; } soundControl::~soundControl() { delete ui; } void soundControl::readSettings() { QSettings qSettings; qSettings.beginGroup("Sound"); rxClock=qSettings.value("rxclock",BASESAMPLERATE).toDouble(); txClock=qSettings.value("txclock",BASESAMPLERATE).toDouble(); if(fabs(1-rxClock/BASESAMPLERATE)>0.002) rxClock=BASESAMPLERATE; if(fabs(1-txClock/BASESAMPLERATE)>0.002) txClock=BASESAMPLERATE; inputAudioDeviceIndex=qSettings.value("inputAudioDeviceIndex",0).toInt(); outputAudioDeviceIndex=qSettings.value("outputAudioDeviceIndex",0).toInt(); soundIOPtr->soundRoutingInput= (soundIO::edataSrc)qSettings.value("soundRoutingInput", 0 ).toInt(); soundIOPtr->soundRoutingOutput= (soundIO::edataDst)qSettings.value("soundRoutingOutput", 0 ).toInt(); soundIOPtr->recordingSize= qSettings.value("recordingSize", 100 ).toInt(); qSettings.endGroup(); setParams(); } void soundControl::writeSettings() { getParams(); QSettings qSettings; qSettings.beginGroup("Sound"); qSettings.setValue("rxclock",rxClock); qSettings.setValue("txclock",txClock); qSettings.setValue("inputAudioDeviceIndex",inputAudioDeviceIndex); qSettings.setValue("outputAudioDeviceIndex",outputAudioDeviceIndex); qSettings.setValue ("soundRoutingInput", soundIOPtr->soundRoutingInput ); qSettings.setValue ("soundRoutingOutput",soundIOPtr->soundRoutingOutput ); qSettings.setValue ("recordingSize",soundIOPtr->recordingSize ); qSettings.endGroup(); } void soundControl::setParams() { setValue(rxClock,ui->inputClockLineEdit,9); setValue(txClock,ui->outputClockLineEdit,9); setIndex(inputAudioDeviceIndex,ui->inputPCMNameComboBox); setIndex(outputAudioDeviceIndex,ui->outputPCMNameComboBox); soundIOPtr->inputAudioDevice=ui->inputPCMNameComboBox->currentText(); soundIOPtr->outputAudioDevice=ui->outputPCMNameComboBox->currentText(); if(soundIOPtr->soundRoutingInput==soundIO::SNDINCARD) ui->inFromCard->setChecked(true); else if (soundIOPtr->soundRoutingInput==soundIO::SNDINFILE) ui->inFromFile->setChecked(true); else ui->inRecordFromCard->setChecked(true); if(soundIOPtr->soundRoutingOutput==soundIO::SNDOUTCARD) ui->outToCard->setChecked(true); else ui->outRecord->setChecked(true); setValue(soundIOPtr->recordingSize,ui->mbSpinBox); } void soundControl::getParams() { changed=false; int savedInputIdx=inputAudioDeviceIndex; int savedOutputIdx=outputAudioDeviceIndex; getValue(rxClock,ui->inputClockLineEdit); getValue(txClock,ui->inputClockLineEdit); getIndex(inputAudioDeviceIndex,ui->inputPCMNameComboBox); getIndex(outputAudioDeviceIndex,ui->outputPCMNameComboBox); if (ui->inFromCard->isChecked()) soundIOPtr->soundRoutingInput=soundIO::SNDINCARD; else if(ui->inFromFile->isChecked()) soundIOPtr->soundRoutingInput=soundIO::SNDINFILE; else soundIOPtr->soundRoutingInput=soundIO::SNDINCARDTOFILE; if (ui->outToCard->isChecked()) soundIOPtr->soundRoutingOutput=soundIO::SNDOUTCARD; else soundIOPtr->soundRoutingOutput=soundIO::SNDOUTTOFILE; getValue(soundIOPtr->recordingSize,ui->mbSpinBox); if(savedInputIdx!=inputAudioDeviceIndex) changed=true; if(savedOutputIdx!=outputAudioDeviceIndex) changed=true; } qsstv_8.2.12/qsstv/sound/soundcontrol.h000664 001750 001750 00000000765 12440612574 020215 0ustar00jomajoma000000 000000 #ifndef SOUNDCONTROL_H #define SOUNDCONTROL_H #include namespace Ui { class soundControl; } class soundControl : public QWidget { Q_OBJECT public: explicit soundControl(QWidget *parent = 0); ~soundControl(); void readSettings(); void writeSettings(); void setParams(); bool needsRestart() { return changed;} private: Ui::soundControl *ui; int inputAudioDeviceIndex; int outputAudioDeviceIndex; bool changed; void getParams(); }; #endif // SOUNDCONTROL_H qsstv_8.2.12/qsstv/sound/soundcontrol.ui000664 001750 001750 00000017060 12440612574 020377 0ustar00jomajoma000000 000000 soundControl 0 0 600 341 Form 0 0 0 25 Input Audio Device false 0 0 0 25 Output Audio Device false 0 0 145 0 Input Clock Frequency false Qt::Horizontal 40 20 0 0 0 25 Output Clock Frequency false Qt::Horizontal 40 20 Sound Input From sound card true From file From sound card and record Sound Output To sound card true To sound card and record 1 999 5 100 Maximum recording size (in MB) false Qt::Horizontal QSizePolicy::Expanding 51 20 Qt::Vertical 20 25 qsstv_8.2.12/qsstv/sound/soundio.cpp000664 001750 001750 00000060560 12474354470 017503 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "soundio.h" #include "qsstvglobal.h" #include"soundcontrol.h" #include #include #include #include #include "utils/supportfunctions.h" //#include "scope/scopeview.h" #include #include soundIO *soundIOPtr; static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; soundIO::soundIO(int s) { setSamplerate(s); soundOK=false; } void soundIO::setSamplerate(int s) { samplerate=s; } void soundIO::run() { unsigned int delay; delay=((playbackBufferSize*1000)/samplerate); abort=false; playbackState=PBINIT; captureState=CPINIT; if(!soundOK) return; while(!abort) { switch(playbackState) { case PBINIT: txBuffer.reset(); detectedPlaybackState= PBINIT; break; case PBSTARTING: if (play()==0) msleep(10); else { playbackState=PBRUNNING; addToLog("playback started",LOGPERFORM); } detectedPlaybackState= PBSTARTING; break; case PBRUNNING: if (play()==0) { addToLog(QString("playback stopped: delay=%1").arg(delay),LOGPERFORM); msleep(delay); waveOut.close(); addToLog("playback stopped",LOGPERFORM); emit playbackStopped(); playbackState=PBINIT; } detectedPlaybackState= PBRUNNING; break; case PBCALIBRATE1: { detectedPlaybackState= PBCALIBRATE1; if (playbackCalibration()!=0) { playbackState=PBCALIBRATE2; } } break; case PBCALIBRATE2: { if (playbackCalibration()==0) break; detectedPlaybackState= PBCALIBRATE2; } break; } switch(captureState) { case CPINIT: // rxBuffer.reset(); detectedCaptureState=CPINIT; break; case CPSTARTING: rxBuffer.reset(); //clear the rxBuffer snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); detectedCaptureState=CPSTARTING; captureState=CPRUNNING; break; case CPRUNNING: if (capture()==0) msleep(60); detectedCaptureState=CPRUNNING; break; case CPCALIBRATE: { if (captureCalibration()==0) msleep(0); detectedCaptureState= CPCALIBRATE; } break; case CPEND: msleep(1000); captureState=CPINIT; break; } if((captureState==CPINIT) &&(playbackState==PBINIT)) msleep(200); } abort=false; playbackState=PBINIT; captureState=CPINIT; } double soundIO::getPlaybackStartupTime() { return (double)playbackBufferSize/BASESAMPLERATE; } /** * @brief play sound from txBuffer * * The sound is controlled by soundRoutingOutput (via configuration). * - SNDOUTCARD sound to card only * - SNDOUTTOFILE sound to card and saved in wav file * - SNDOUTFILETOCARD sound from wav file to card * * @return number of frames sent. * * The readIndex must always be a multiple of 2*PERIODSIZE because we don't check the txBuffer for wrap-around. * */ int soundIO::play() { unsigned int numFrames,restFrames; int framesWritten,error; addToLog(QString("readIndex: %1,writeIndex: %2 count: %3").arg(txBuffer.getReadIndex()).arg(txBuffer.getWriteIndex()).arg(txBuffer.count()),LOGSOUND); if(playbackState==PBSTARTING) { // prefill buffers to the max if((numFrames=txBuffer.count())=(2*PERIODSIZE)) { numFrames=2*PERIODSIZE; } } if(soundRoutingOutput==SNDOUTTOFILE) { if(storedFrames<=(ulong)recordingSize*1048576L) { waveOut.write((quint16*)txBuffer.readPointer(),numFrames,isStereo); storedFrames+=numFrames; // msleep(10); // give some processingtime // return numFrames; } } restFrames=numFrames; while(restFrames) { framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), restFrames); // arrayDump(QString("sio %1").arg(frameCounter++),txBuffer.readPointer(),32,true); if(framesWritten<0) { if ( framesWritten == -EAGAIN ) { return -1; } else if ( framesWritten == -EPIPE ) { /* underrun */ errorHandler(framesWritten,QString("Underrun recovery for %1").arg(numFrames)); error = snd_pcm_prepare (playbackHandle); if ( error < 0 ) { errorHandler(framesWritten,"Can't recover from underrun, prepare failed"); snd_pcm_drop (playbackHandle); } } else { errorHandler(framesWritten,"Unhandled error in playback"); snd_pcm_drop (playbackHandle ); } } else { addToLog(QString("framesWritten:%1").arg(framesWritten),LOGSOUND); txBuffer.skip(framesWritten); if(restFrames!=numFrames) { addToLog(QString("restFrames: %1; framesWritten %2").arg(restFrames).arg(framesWritten),LOGSOUND); } msleep(10); restFrames-=framesWritten; } } return numFrames; } int soundIO::playbackCalibration() { int numFrames,framesWritten; if(playbackState==PBCALIBRATE1) { numFrames=playbackBufferSize; framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), numFrames); calibrationFrames=0; return numFrames; } else { numFrames=1*PERIODSIZE; } framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), numFrames); if(numFrames!=framesWritten) { framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), numFrames-framesWritten); } else { } mutex.lock(); calibrationFrames+=1; calibrationTime=stopwatch.elapsed(); if(calibrationFrames==CALIBRATIONLEADIN) { stopwatch.start(); addToLog("start calrx",LOGCAM); } mutex.unlock(); return numFrames; } /** * @brief capture sound to rxBuffer * * The sound recording is controlled by soundRoutingInput (via configuration). * * - SNDINCARD sound from card * - SNDINFILE sound from a wav file * - SNDINCARDTOFILE sound from card and recording to wav file * * @return number of frames recorded. */ int soundIO::capture() { int count; QString debugStr; if(rxBuffer.spaceLeft()=PERIODSIZE) { count = snd_pcm_readi(captureHandle, tempRXBuffer,PERIODSIZE); } if ( count < 0 ) { if ( count != -EAGAIN ) { if ( count == -EPIPE ) { // Overrun snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); qDebug()<< "Overrun"; } else { snd_pcm_drop (captureHandle ); qDebug()<<"Overrun , reason: "<< count << "Stopping device"; } } addToLog("soundIO: sound eagain",LOGSOUND); return 0; } if(count!=PERIODSIZE) { return 0; } else { if(soundRoutingInput==SNDINCARDTOFILE) { if(storedFrames<=(ulong)recordingSize*1048576L) { addToLog(QString("writen %1 tofile").arg(count),LOGSOUND); waveOut.write((quint16*)tempRXBuffer,count,isStereo); storedFrames+=count; } else { captureState=CPINIT; } } } } // addToLog(QString("rxBuffercount: %1").arg(count),LOGSOUND); if((isStereo) || (soundRoutingInput==SNDINFILE)) { for(int i=0;i=0) { count = snd_pcm_readi( captureHandle, tempRXBuffer,PERIODSIZE-count); mutex.lock(); calibrationFrames++; calibrationTime=stopwatch.elapsed(); mutex.unlock(); } else { calibrationFrames=0; // restart calibration qDebug() << "restarting calibration"; if ( count != -EAGAIN ) { if ( count == -EPIPE ) { // Overrun snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); qDebug() << "Overrun"; } else { snd_pcm_drop (captureHandle ); qDebug()<<"Overrun , reason: "<< count << "Stopping device"; } } addToLog("soundIO: sound eagain",LOGSOUND); return 0; } return count; } /** * @brief Initialisation of the soundcard hardware in full-duplex * * This function must be called before using the soundcard and after the configuration has been loaded *@return bool true if call was succesfull */ bool soundIO::init() { int err; QString tempDevice; lastError.clear(); if(soundOK) { // we have to stop thread first stopAndWait(); snd_pcm_close(playbackHandle); snd_pcm_close(captureHandle); } soundOK=false; tempDevice=outputAudioDevice.left(outputAudioDevice.indexOf(" ")); err = snd_pcm_open(&playbackHandle,tempDevice.toLatin1().data(), SND_PCM_STREAM_PLAYBACK,0); //open in blocking mode if(!errorHandler(err,"Unable to open "+outputAudioDevice)) return false; tempDevice=inputAudioDevice.left(inputAudioDevice.indexOf(" ")); err = snd_pcm_open(&captureHandle,tempDevice.toLatin1().data(), SND_PCM_STREAM_CAPTURE, 0); if(!errorHandler(err,"Unable to open "+inputAudioDevice)) return false; snd_pcm_hw_params_malloc ( &hwparams ); snd_pcm_sw_params_malloc ( &swparams ); if(setupSoundParams(true)) { if(setupSoundParams(false)) soundOK=true; } snd_pcm_hw_params_free ( hwparams ); snd_pcm_sw_params_free ( swparams ); return soundOK; } bool soundIO::stoppedPlaying() { if(playbackState==PBINIT) { return true; } else { return false; } } bool soundIO::setupSoundParams(bool isCapture) { int err; int dir=0; snd_pcm_t *handle; playbackPeriodSize=PERIODSIZE; playbackBufferSize=BUFFERSIZE; capturePeriodSize=PERIODSIZE; captureBufferSize=BUFFERSIZE; if(isCapture) handle=captureHandle; else handle=playbackHandle; /* Choose all parameters */ err = snd_pcm_hw_params_any ( handle, hwparams ); if(!errorHandler(err,"Broken configuration : no configurations available")) return false; /* Set the interleaved read/write format */ err = snd_pcm_hw_params_set_access ( handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ); if(!errorHandler(err,"Access type not available : ")) return false; /* Set the sample format */ err = snd_pcm_hw_params_set_format ( handle, hwparams, SND_PCM_FORMAT_S16_LE ); if(!errorHandler(err,"Sample format Float not available : ")) return false; /* Set the count of channels */ if(isCapture) { err=snd_pcm_hw_params_get_channels_min(hwparams,&minChannelsCapture); err=snd_pcm_hw_params_get_channels_max(hwparams,&maxChannelsCapture); err = snd_pcm_hw_params_set_channels ( handle, hwparams, minChannelsCapture); if(!errorHandler(err,"Channels count not correct; " )) return false; } else { err=snd_pcm_hw_params_get_channels_min(hwparams,&minChannelsPlayback); err=snd_pcm_hw_params_get_channels_max(hwparams,&maxChannelsPlayback); err = snd_pcm_hw_params_set_channels ( handle, hwparams, 2); //allways stereo output if(!errorHandler(err,"Channels count not correct; " )) { return false; } } err = snd_pcm_hw_params_set_rate ( handle, hwparams, samplerate, 0 ); if(!errorHandler(err,QString("Samplerate %1 not available").arg(samplerate))) return false; if(isCapture) { err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &capturePeriodSize, &dir ); if(!errorHandler(err,QString("Unable to set period size %1 for capture").arg(capturePeriodSize))) return false; err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &captureBufferSize ); if(!errorHandler(err,QString("Unable to set buffersize %1 for capture").arg(captureBufferSize))) return false; } else { err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &playbackPeriodSize, &dir ); if(!errorHandler(err,QString("Unable to set period size %1 for playback").arg(playbackPeriodSize))) return false; err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &playbackBufferSize ); if(!errorHandler(err,QString("Unable to set buffersize %1 for playback").arg(playbackBufferSize))) return false; } err = snd_pcm_hw_params ( handle, hwparams ); if(isCapture) { if(!errorHandler(err,QString("Unable to set hw params for capture:"))) return false; } else { if(!errorHandler(err,QString("Unable to set hw params for playback:"))) return false; } /* Get the current swparams */ err = snd_pcm_sw_params_current ( handle, swparams ); if(!errorHandler(err,"Unable to determine current swparams")) return false; err = snd_pcm_sw_params_set_start_threshold ( handle, swparams, 2048 ); if(!errorHandler(err,"Unable to set start threshold mode")) return false; /* Write the parameters to the record/playback device */ err = snd_pcm_sw_params ( handle, swparams ); if(!errorHandler(err,"Unable to set sw params for output")) return false; return true; } bool soundIO::listCards() { int err; int cardNum, totalCards; char str[64]; snd_ctl_card_info_t *cardInfo; int devNum; // int totalDevices; snd_pcm_info_t *pcmInfo; snd_ctl_t *cardHandle; inputPCMNameList << "default"; outputPCMNameList << "default"; // No cards found yet totalCards = 0; // Start with first card cardNum = -1; for (;;) { // Get next sound card's card number. When "cardNum" == -1, then ALSA fetches the first card if ((err = snd_card_next(&cardNum)) < 0) { qDebug() << "Can't get the next card number:" << snd_strerror(err); return false; } if (cardNum < 0) break; // No more cards? ALSA sets "cardNum" to -1 if so sprintf(str, "hw:%i", cardNum); if ((err = snd_ctl_open(&cardHandle, str, 0)) < 0) { qDebug() << "Can't open card "<< cardNum << snd_strerror(err); continue; } // We need to get a snd_ctl_card_info_t. Just alloc it on the stack snd_ctl_card_info_alloca(&cardInfo); // Tell ALSA to fill in our snd_ctl_card_info_t with info about this card if ((err = snd_ctl_card_info(cardHandle, cardInfo)) >= 0) qDebug() << "Card " << cardNum << "name: " << snd_ctl_card_info_get_name(cardInfo); // totalDevices = 0; devNum = -1; // Start with the first wave device on this card for (;;) { if ((err = snd_ctl_pcm_next_device(cardHandle, &devNum)) < 0) // Get the number of the next wave device on this card { qDebug()<< "Can't get next wave device number: " << snd_strerror(err); break; } // No more wave devices on this card? ALSA sets "devNum" to -1 if so. // NOTE: It's possible that this sound card may have no wave devices on it // at all, for example if it's only a MIDI card if (devNum < 0) break; // To get some info about the subdevices of this wave device (on the card), we need a // snd_pcm_info_t, so let's allocate one on the stack snd_pcm_info_alloca(&pcmInfo); memset(pcmInfo, 0, snd_pcm_info_sizeof()); // Tell ALSA which device (number) we want info about snd_pcm_info_set_device(pcmInfo, devNum); // Get info on the wave outs of this device getDevices(cardHandle,cardNum,devNum,pcmInfo, SND_PCM_STREAM_PLAYBACK); getDevices(cardHandle,cardNum,devNum,pcmInfo, SND_PCM_STREAM_CAPTURE); } ++totalCards; // Close the card's control interface after we're done with it snd_ctl_close(cardHandle); // qDebug() << "Found:" << totalDevices << " digital audio devices on card " << cardNum; } // qDebug() << "ALSA found cards" << totalCards; // ALSA allocates some mem to load its config file when we call // snd_card_next. Now that we're done getting the info, let's tell ALSA // to unload the info and free up that mem snd_config_update_free_global(); return true; } void soundIO::getDevices(snd_ctl_t *cardHandle,int cardNum,int devNum,snd_pcm_info_t *pcmInfo, snd_pcm_stream_t direction) { int err; int i= -1; int subDevCount = 1; snd_pcm_info_set_stream(pcmInfo, direction); // More subdevices? while (++i < subDevCount) { // Tell ALSA to fill in our snd_pcm_info_t with info on this subdevice snd_pcm_info_set_subdevice(pcmInfo, i); if ((err = snd_ctl_pcm_info(cardHandle, pcmInfo)) < 0) { // qDebug() << QString("Can't get info for wave output subdevice hw:%1,%2,%3: %4").arg(cardNum).arg(devNum).arg(i).arg(snd_strerror(err)); continue; } // qDebug() << "PCM name" << snd_pcm_info_get_name(pcmInfo); // Print out how many subdevices (once only) if (!i) { subDevCount = snd_pcm_info_get_subdevices_count(pcmInfo); // qDebug() << QString("Found %1 wave output subdevices on card %2").arg(subDevCount).arg(cardNum); } // NOTE: If there's only one subdevice, then the subdevice number is immaterial, // and can be omitted when you specify the hardware name if(subDevCount>1) { // qDebug()<< QString("hw:%1,%2,%3").arg(cardNum).arg(devNum).arg(i); if(direction==SND_PCM_STREAM_CAPTURE) { inputPCMNameList << QString("hw:%1,%2,%3 %4").arg(cardNum).arg(devNum).arg(i).arg(snd_pcm_info_get_name(pcmInfo)); } else { outputPCMNameList << QString("hw:%1,%2,%3 %4").arg(cardNum).arg(devNum).arg(i).arg(snd_pcm_info_get_name(pcmInfo)); } } else { // qDebug()<< QString("hw:%1,%2").arg(cardNum).arg(devNum); if(direction==SND_PCM_STREAM_CAPTURE) { inputPCMNameList << QString("hw:%1,%2 %3").arg(cardNum).arg(devNum).arg(snd_pcm_info_get_name(pcmInfo)); } else { outputPCMNameList << QString("hw:%1,%2 %3").arg(cardNum).arg(devNum).arg(snd_pcm_info_get_name(pcmInfo)); } } } } bool soundIO::errorHandler(int err,QString info) { if(err<0) { lastError=info+ ": "+ QString ( snd_strerror ( err ) ); qDebug() << lastError; addToLog(lastError,LOGALL); return false; } return true; } void soundIO::errorHandler(QString info) { lastError=info; qDebug() << lastError; addToLog(lastError,LOGALL); } bool soundIO::startCapture() { playbackState=PBINIT; if(!soundOK) return false; switch(soundRoutingInput) { case SNDINCARD: if(minChannelsCapture==1) isStereo=false; else isStereo=true; break; case SNDINFILE: if(!waveIn.openFileForRead("",true)) { errorHandler("File not opened"); return false; } if(waveIn.getNumberOfChannels()==1) isStereo=false; else isStereo=true; break; case SNDINCARDTOFILE: { if(minChannelsCapture==1) isStereo=false; else isStereo=true; if(!waveOut.openFileForWrite("",true,isStereo)) { errorHandler("File not opened"); return false; } } break; } rxBuffer.reset(); captureState=CPSTARTING; addToLog("start capturing",LOGSOUND); return true; } bool soundIO::startPlayback() { frameCounter=0; captureState=CPINIT; if(!soundOK) return false; soundIOPtr->txBuffer.reset(); if(soundRoutingOutput==SNDOUTTOFILE) { if(!waveOut.openFileForWrite("",true,true)) // indicate stereo { errorHandler("File not opened"); return false; } } playbackState=PBSTARTING; snd_pcm_prepare (playbackHandle); addToLog(QString("start playback, txbuffercount: %1").arg(txBuffer.count()),LOGSOUND); return true; } bool soundIO::startCalibration(bool capture) { captureState=CPINIT; playbackState=PBINIT; if(!soundOK) return false; while(detectedCaptureState!=CPINIT) { qApp->processEvents(); }; while(detectedPlaybackState!=PBINIT) { qApp->processEvents(); }; calibrationFrames=0; if(capture) { snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); captureState=CPCALIBRATE; } else { txBuffer.fill(0); // snd_pcm_start (playbackHandle); //snd_pcm_prepare (playbackHandle ); playbackState=PBCALIBRATE1; } return true; } void soundIO::idle() { waveOut.close(); waveIn.closeFile(); captureState=CPINIT; playbackState=PBINIT; } /** * @brief stopping soundio thread */ void soundIO::stopAndWait() { if(!soundOK) return; waveOut.write(NULL,0,false); abort=true; while(abort) { qApp->processEvents(); } } int soundIO::calibrationCount(int &frames) { int tempT,tempC; mutex.lock(); tempC=calibrationFrames; tempT=calibrationTime; mutex.unlock(); frames=tempC-CALIBRATIONLEADIN; return tempT; } qsstv_8.2.12/qsstv/sound/soundio.cpp_new000664 001750 001750 00000061514 12440612574 020347 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "soundio.h" #include "qsstvglobal.h" #include"soundcontrol.h" #include #include #include #include #include "utils/supportfunctions.h" //#include "scope/scopeview.h" #include #include soundIO *soundIOPtr; static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; soundIO::soundIO(int s) { setSamplerate(s); soundOK=FALSE; } void soundIO::setSamplerate(int s) { samplerate=s; } void soundIO::run() { unsigned int delay; delay=((playbackBufferSize*1000)/samplerate); abort=FALSE; playbackState=PBINIT; captureState=CPINIT; if(!soundOK) return; while(!abort) { switch(playbackState) { case PBINIT: msleep(10); detectedPlaybackState= PBINIT; break; case PBSTARTING: if (play()==0) msleep(10); else { playbackState=PBRUNNING; addToLog("playback started",LOGPERFORM); } detectedPlaybackState= PBSTARTING; break; case PBRUNNING: if (play()==0) { addToLog(QString("playback stopped: delay=%1").arg(delay),LOGPERFORM); msleep(delay); waveOut.close(); addToLog("playback stopped",LOGPERFORM); emit playbackStopped(); playbackState=PBINIT; } detectedPlaybackState= PBRUNNING; break; case PBCALIBRATE1: { detectedPlaybackState= PBCALIBRATE1; if (playbackCalibration()!=0) { playbackState=PBCALIBRATE2; } } break; case PBCALIBRATE2: { if (playbackCalibration()==0) break; detectedPlaybackState= PBCALIBRATE2; } break; } switch(captureState) { case CPINIT: msleep(10); detectedCaptureState=CPINIT; break; case CPSTARTING: rxBuffer.reset(); //clear the rxBuffer snd_pcm_readi( captureHandle, tempRXBuffer,PERIODSIZE); detectedCaptureState=CPSTARTING; captureState=CPRUNNING; break; case CPRUNNING: if (capture()==0) msleep(75); detectedCaptureState=CPRUNNING; break; case CPCALIBRATE: { if (captureCalibration()==0) msleep(0); detectedCaptureState= CPCALIBRATE; } } } abort=FALSE; playbackState=PBINIT; captureState=CPINIT; } /** * @brief play sound from txBuffer * * The sound is controlled by soundRoutingOutput (via configuration). * - SNDOUTCARD sound to card only * - SNDOUTTOFILE sound to card and saved in wav file * - SNDOUTFILETOCARD sound from wav file to card * * @return number of frames sent. * * The readIndex must always be a multiple of 2*PERIODSIZE because we don't check the txBuffer for wrap-around. * */ double soundIO::getPlaybackStartupTime() { return (double)playbackBufferSize/BASESAMPLERATE; } int soundIO::play() { unsigned int numFrames,restFrames; int framesWritten,error; addToLog(QString("readIndex: %1,writeIndex: %2 count: %3").arg(txBuffer.getReadIndex()).arg(txBuffer.getWriteIndex()).arg(txBuffer.count()),LOGSOUND); if(playbackState==PBSTARTING) { // prefill buffers to the max if((numFrames=txBuffer.count())=(2*PERIODSIZE)) { numFrames=2*PERIODSIZE; } } if(soundRoutingOutput==SNDOUTTOFILE) { if(storedFrames<=(ulong)recordingSize*1048576L) { waveOut.write(txBuffer.readPointer(),numFrames); storedFrames+=numFrames; txBuffer.skip(numFrames); return numFrames; } else { return 0; } } restFrames=numFrames; while(restFrames) { framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), restFrames); // arrayDump(QString("sio %1").arg(frameCounter++),txBuffer.readPointer(),32,TRUE); if(framesWritten<0) { if ( framesWritten == -EAGAIN ) { return -1; } else if ( framesWritten == -EPIPE ) { /* underrun */ errorHandler(framesWritten,QString("Underrun recovery for %1").arg(numFrames)); error = snd_pcm_prepare (playbackHandle); if ( error < 0 ) { errorHandler(framesWritten,"Can't recover from underrun, prepare failed"); snd_pcm_drop (playbackHandle); } } else { errorHandler(framesWritten,"Unhandled error in playback"); snd_pcm_drop (playbackHandle ); } } else { addToLog(QString("framesWritten:%1").arg(framesWritten),LOGSOUND); txBuffer.skip(framesWritten); if(restFrames!=numFrames) { addToLog(QString("restFrames: %1; framesWritten %2").arg(restFrames).arg(framesWritten),LOGSOUND); } msleep(10); restFrames-=framesWritten; } } return numFrames; } int soundIO::playbackCalibration() { int numFrames,framesWritten; if(playbackState==PBCALIBRATE1) { numFrames=playbackBufferSize; framesWritten = snd_pcm_writei ( playbackHandle, txBuffer.readPointer(), numFrames); if(numFrames!=framesWritten) { // qDebug() << " error in calibration framesWriiten" <=PERIODSIZE) { count = snd_pcm_readi( captureHandle, tempRXBuffer,PERIODSIZE); } if ( count < 0 ) { if ( count != -EAGAIN ) { if ( count == -EPIPE ) { // Overrun snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); printf ( "Overrun\n" ); } else { snd_pcm_drop (captureHandle ); printf ( "Overrun , reason %d\nStopping device", count ); } } addToLog("soundIO: sound eagain",LOGSOUND); return 0; } else { if(soundRoutingInput==SNDINCARDTOFILE) { if(storedFrames<=(ulong)recordingSize*1048576L) { waveOut.write((quint32*)tempRXBuffer,count); // addToLog(QString("storing data: %1").arg(storedFrames),LOGSOUND); storedFrames+=count; } else { captureState=CPINIT; } } } } // addToLog(QString("rxBuffercount: %1").arg(count),LOGSOUND); if(count!=PERIODSIZE) { // addToLog("count not periodsize",LOGSOUND); return 0; } if(isStereo) { for(int i=0;i=0) { qDebug() << "invalid count" << count << "frames" << calibrationFrames << "time" << calibrationTime; qDebug() << "requested" << PERIODSIZE-count; count = snd_pcm_readi( captureHandle, tempRXBuffer,PERIODSIZE-count); qDebug() << "new count" << count ; mutex.lock(); calibrationFrames++; calibrationTime=stopwatch.elapsed(); mutex.unlock(); } else { calibrationFrames=0; // restart calibration qDebug() << "restarting calibration"; if ( count != -EAGAIN ) { if ( count == -EPIPE ) { // Overrun snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); printf ( "Overrun\n" ); } else { snd_pcm_drop (captureHandle ); printf ( "Overrun , reason %d\nStopping device", count ); } } addToLog("soundIO: sound eagain",LOGSOUND); return 0; } return count; } /** * @brief Initialisation of the soundcard hardware in full-duplex * * This function must be called before using the soundcard and after the configuration has been loaded *@return bool TRUE if call was succesfull */ bool soundIO::init() { int err; stopSoundIO(); QString tempDevice; lastError.clear(); soundOK=FALSE; tempDevice=outputAudioDevice.left(outputAudioDevice.indexOf(" ")); err = snd_pcm_open(&playbackHandle,tempDevice.toLatin1().data(), SND_PCM_STREAM_PLAYBACK,0); //open in blocking mode if(!errorHandler(err,"Unable to open "+outputAudioDevice)) return FALSE; tempDevice=inputAudioDevice.left(inputAudioDevice.indexOf(" ")); err = snd_pcm_open(&captureHandle,tempDevice.toLatin1().data(), SND_PCM_STREAM_CAPTURE, 0); if(!errorHandler(err,"Unable to open "+inputAudioDevice)) return FALSE; snd_pcm_hw_params_malloc ( &hwparams ); snd_pcm_sw_params_malloc ( &swparams ); if(setupSoundParams(TRUE)) { if(setupSoundParams(FALSE)) soundOK=TRUE; } snd_pcm_hw_params_free ( hwparams ); snd_pcm_sw_params_free ( swparams ); return soundOK; } void soundIO::stopSoundIO() { int err; if(soundOK) { err=snd_pcm_close(playbackHandle); err=snd_pcm_close(captureHandle); soundOK=FALSE; } } bool soundIO::setupSoundParams(bool isCapture) { int err; int dir=0; snd_pcm_t *handle; playbackPeriodSize=PERIODSIZE; playbackBufferSize=BUFFERSIZE; capturePeriodSize=PERIODSIZE; captureBufferSize=BUFFERSIZE; if(isCapture) handle=captureHandle; else handle=playbackHandle; /* Choose all parameters */ err = snd_pcm_hw_params_any ( handle, hwparams ); if(!errorHandler(err,"Broken configuration : no configurations available")) return FALSE; /* Set the interleaved read/write format */ err = snd_pcm_hw_params_set_access ( handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ); if(!errorHandler(err,"Access type not available : ")) return FALSE; /* Set the sample format */ err = snd_pcm_hw_params_set_format ( handle, hwparams, SND_PCM_FORMAT_S16_LE ); if(!errorHandler(err,"Sample format Float not available : ")) return FALSE; /* Set the count of channels */ if(isCapture) { err=snd_pcm_hw_params_get_channels_min(hwparams,&minChannelsCapture); err=snd_pcm_hw_params_get_channels_max(hwparams,&maxChannelsCapture); qDebug() << "numChannels Capture" << minChannelsCapture << maxChannelsCapture; err = snd_pcm_hw_params_set_channels ( handle, hwparams, minChannelsCapture); if(!errorHandler(err,"Channels count not correct; " )) return FALSE; } else { err=snd_pcm_hw_params_get_channels_min(hwparams,&minChannelsPlayback); err=snd_pcm_hw_params_get_channels_max(hwparams,&maxChannelsPlayback); qDebug() << "numChannels Playback" << minChannelsPlayback << maxChannelsPlayback; err = snd_pcm_hw_params_set_channels ( handle, hwparams, minChannelsPlayback); if(!errorHandler(err,"Channels count not correct; " )) { return FALSE; } } err = snd_pcm_hw_params_set_rate ( handle, hwparams, samplerate, 0 ); if(!errorHandler(err,QString("Samplerate %1 not available").arg(samplerate))) return FALSE; if(isCapture) { err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &capturePeriodSize, &dir ); if(!errorHandler(err,QString("Unable to set period size %1 for capture").arg(capturePeriodSize))) return FALSE; err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &captureBufferSize ); if(!errorHandler(err,QString("Unable to set buffersize %1 for capture").arg(captureBufferSize))) return FALSE; } else { err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &playbackPeriodSize, &dir ); if(!errorHandler(err,QString("Unable to set period size %1 for playback").arg(playbackPeriodSize))) return FALSE; err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &playbackBufferSize ); if(!errorHandler(err,QString("Unable to set buffersize %1 for playback").arg(playbackBufferSize))) return FALSE; } err = snd_pcm_hw_params ( handle, hwparams ); if(isCapture) { if(!errorHandler(err,QString("Unable to set hw params for capture:"))) return FALSE; } else { if(!errorHandler(err,QString("Unable to set hw params for playback:"))) return FALSE; } /* Get the current swparams */ err = snd_pcm_sw_params_current ( handle, swparams ); if(!errorHandler(err,"Unable to determine current swparams")) return FALSE; err = snd_pcm_sw_params_set_start_threshold ( handle, swparams, 2048 ); if(!errorHandler(err,"Unable to set start threshold mode")) return FALSE; /* Write the parameters to the record/playback device */ err = snd_pcm_sw_params ( handle, swparams ); if(!errorHandler(err,"Unable to set sw params for output")) return FALSE; return TRUE; } bool soundIO::listCards() { int err; int cardNum, totalCards; char str[64]; snd_ctl_card_info_t *cardInfo; int devNum, totalDevices; snd_pcm_info_t *pcmInfo; snd_ctl_t *cardHandle; // No cards found yet totalCards = 0; // Start with first card cardNum = -1; for (;;) { // Get next sound card's card number. When "cardNum" == -1, then ALSA fetches the first card if ((err = snd_card_next(&cardNum)) < 0) { qDebug() << "Can't get the next card number:" << snd_strerror(err); return FALSE; } if (cardNum < 0) break; // No more cards? ALSA sets "cardNum" to -1 if so sprintf(str, "hw:%i", cardNum); if ((err = snd_ctl_open(&cardHandle, str, 0)) < 0) { qDebug() << "Can't open card "<< cardNum << snd_strerror(err); continue; } // We need to get a snd_ctl_card_info_t. Just alloc it on the stack snd_ctl_card_info_alloca(&cardInfo); // Tell ALSA to fill in our snd_ctl_card_info_t with info about this card if ((err = snd_ctl_card_info(cardHandle, cardInfo)) < 0) qDebug() << "Can't get info for card" << cardNum << snd_strerror(err); else qDebug() << "Card " << cardNum << "name: " << snd_ctl_card_info_get_name(cardInfo); totalDevices = 0; devNum = -1; // Start with the first wave device on this card for (;;) { if ((err = snd_ctl_pcm_next_device(cardHandle, &devNum)) < 0) // Get the number of the next wave device on this card { qDebug()<< "Can't get next wave device number: " << snd_strerror(err); break; } // No more wave devices on this card? ALSA sets "devNum" to -1 if so. // NOTE: It's possible that this sound card may have no wave devices on it // at all, for example if it's only a MIDI card if (devNum < 0) break; // To get some info about the subdevices of this wave device (on the card), we need a // snd_pcm_info_t, so let's allocate one on the stack snd_pcm_info_alloca(&pcmInfo); memset(pcmInfo, 0, snd_pcm_info_sizeof()); // Tell ALSA which device (number) we want info about snd_pcm_info_set_device(pcmInfo, devNum); // Get info on the wave outs of this device getDevices(cardHandle,cardNum,devNum,pcmInfo, SND_PCM_STREAM_PLAYBACK); getDevices(cardHandle,cardNum,devNum,pcmInfo, SND_PCM_STREAM_CAPTURE); } ++totalCards; // Close the card's control interface after we're done with it snd_ctl_close(cardHandle); qDebug() << "Found:" << totalDevices << " digital audio devices on card " << cardNum; } qDebug() << "ALSA found cards" << totalCards; // ALSA allocates some mem to load its config file when we call // snd_card_next. Now that we're done getting the info, let's tell ALSA // to unload the info and free up that mem snd_config_update_free_global(); return TRUE; } void soundIO::getDevices(snd_ctl_t *cardHandle,int cardNum,int devNum,snd_pcm_info_t *pcmInfo, snd_pcm_stream_t direction) { int err; int i= -1; int subDevCount = 1; snd_pcm_info_set_stream(pcmInfo, direction); // More subdevices? while (++i < subDevCount) { // Tell ALSA to fill in our snd_pcm_info_t with info on this subdevice snd_pcm_info_set_subdevice(pcmInfo, i); if ((err = snd_ctl_pcm_info(cardHandle, pcmInfo)) < 0) { qDebug() << QString("Can't get info for wave output subdevice hw:%1,%2,%3: %4").arg(cardNum).arg(devNum).arg(i).arg(snd_strerror(err)); continue; } qDebug() << "PCM name" << snd_pcm_info_get_name(pcmInfo); // Print out how many subdevices (once only) if (!i) { subDevCount = snd_pcm_info_get_subdevices_count(pcmInfo); qDebug() << QString("Found %1 wave output subdevices on card %2").arg(subDevCount).arg(cardNum); } // NOTE: If there's only one subdevice, then the subdevice number is immaterial, // and can be omitted when you specify the hardware name if(subDevCount>1) { qDebug()<< QString("hw:%1,%2,%3").arg(cardNum).arg(devNum).arg(i); if(direction==SND_PCM_STREAM_CAPTURE) { inputPCMNameList << QString("hw:%1,%2,%3 %4").arg(cardNum).arg(devNum).arg(i).arg(snd_pcm_info_get_name(pcmInfo)); } else { outputPCMNameList << QString("hw:%1,%2,%3 %4").arg(cardNum).arg(devNum).arg(i).arg(snd_pcm_info_get_name(pcmInfo)); } } else { qDebug()<< QString("hw:%1,%2").arg(cardNum).arg(devNum); if(direction==SND_PCM_STREAM_CAPTURE) { inputPCMNameList << QString("hw:%1,%2 %3").arg(cardNum).arg(devNum).arg(snd_pcm_info_get_name(pcmInfo)); } else { outputPCMNameList << QString("hw:%1,%2 %3").arg(cardNum).arg(devNum).arg(snd_pcm_info_get_name(pcmInfo)); } } } } bool soundIO::errorHandler(int err,QString info) { if(err<0) { lastError=info+ ": "+ QString ( snd_strerror ( err ) ); qDebug() << lastError; addToLog(lastError,LOGALL); return FALSE; } return TRUE; } void soundIO::errorHandler(QString info) { lastError=info; qDebug() << lastError; addToLog(lastError,LOGALL); } bool soundIO::startCapture() { init(); playbackState=PBINIT; if(!soundOK) return FALSE; switch(soundRoutingInput) { case SNDINCARD: if(minChannelsCapture==1) isStereo=FALSE; else isStereo=TRUE; break; case SNDINFILE: if(!waveIn.openFileForRead("",TRUE)) { errorHandler("File not opened"); return FALSE; } if(waveIn.getNumberOfChannels()==1) isStereo=FALSE; else isStereo=TRUE; break; case SNDINCARDTOFILE: { if(!waveOut.openFileForWrite("",TRUE)) { errorHandler("File not opened"); return FALSE; } } break; } rxBuffer.reset(); captureState=CPSTARTING; addToLog("start capturing",LOGSOUND); return TRUE; } bool soundIO::startPlayback() { int count; frameCounter=0; captureState=CPINIT; if(!soundOK) return FALSE; soundIOPtr->txBuffer.reset(); if(soundRoutingOutput==SNDOUTFILETOCARD) { if(!waveIn.openFileForRead("",TRUE)) { errorHandler("File not opened"); return FALSE; } snd_pcm_prepare (playbackHandle); playbackState=PBSTARTING; do { while(txBuffer.spaceLeft()<1024) { qApp->processEvents(); } count=waveIn.read(txBuffer.writePointer(),1024); txBuffer.advance(count); } while(count>0); waveIn.close(); } else { if(soundRoutingOutput==SNDOUTTOFILE) { if(!waveOut.openFileForWrite("",TRUE)) { errorHandler("File not opened"); return FALSE; } } playbackState=PBSTARTING; snd_pcm_prepare (playbackHandle); addToLog(QString("start playback, txbuffercount: %1").arg(txBuffer.count()),LOGSOUND); } return TRUE; } bool soundIO::startCalibration(bool capture) { captureState=CPINIT; playbackState=PBINIT; if(!soundOK) return FALSE; while(detectedCaptureState!=CPINIT) {}; while(detectedPlaybackState!=PBINIT) {}; calibrationFrames=0; if(capture) { snd_pcm_prepare (captureHandle ); snd_pcm_start (captureHandle); captureState=CPCALIBRATE; } else { txBuffer.fill(0); // snd_pcm_start (playbackHandle); //snd_pcm_prepare (playbackHandle ); playbackState=PBCALIBRATE1; } return TRUE; } void soundIO::idle() { captureState=CPINIT; playbackState=PBINIT; } /** * @brief stopping soundio thread */ void soundIO::stopAndWait() { if(!soundOK) return; abort=TRUE; while(abort) { qApp->processEvents(); } } qsstv_8.2.12/qsstv/sound/soundio.h000664 001750 001750 00000011126 12440612574 017135 0ustar00jomajoma000000 000000 #ifndef SOUNDIO_H #define SOUNDIO_H #include #include "qsstvglobal.h" #include #include #include "utils/buffermanag.h" #include "wavio.h" #include "qsstvdefs.h" #include /*! \file soundio.h */ /** * @brief soundio class * *General Info
* A frame is equivalent of one sample being played, irrespective of the number of channels or the number of bits.
* e.g. 1 frame of a Stereo 48khz 16bit PCM stream is 4 bytes. 1 frame of a 5.1 48khz 16bit PCM stream is 12 bytes. A period is the number of frames in between each hardware interrupt. The poll() will return once a period. The buffer is a ring buffer. The buffer size always has to be greater than one period size. Commonly this is 2*period size, but some hardware can do 8 periods per buffer. It is also possible for the buffer size to not be an integer multiple of the period size. Now, if the hardware has been set to 48000Hz , 2 periods, of 1024 frames each, making a buffer size of 2048 frames. The hardware will interrupt 2 times per buffer. ALSA will endeavor to keep the buffer as full as possible. Once the first period of samples has been played, the third period of samples is transfered into the space the first one occupied while the second period of samples is being played. (normal ring buffer behaviour). */ #define CALIBRATIONLEADIN 100 class soundIO:public QThread { Q_OBJECT public: enum edataSrc{SNDINCARD,SNDINFILE,SNDINCARDTOFILE}; enum edataDst{SNDOUTCARD,SNDOUTTOFILE}; enum eplaybackState{PBINIT,PBSTARTING,PBRUNNING,PBCALIBRATE1,PBCALIBRATE2}; enum ecaptureState{CPINIT,CPSTARTING,CPRUNNING,CPCALIBRATE,CPEND}; #define PERIODBITS 12 #define PERIODSIZE (1< rxBuffer; buffer txBuffer; short int tempRXBuffer[2*PERIODSIZE]; // twice because we are using stereo input wavIO waveIn; wavIO waveOut; uint frameCounter; void setStereo(bool st) {isStereo=st;} int calibrationCount(int &frames); // { // int tempT,tempC; // mutex.lock(); // tempC=calibrationFrames; // tempT=calibrationTime; // mutex.unlock(); // frames=tempC-CALIBRATIONLEADIN; // return tempT; // } signals: void playbackStopped(); private: bool initialized; snd_pcm_t *playbackHandle; snd_pcm_t *captureHandle; QStringList inputPCMNameList; /**< list of PCM Names for input*/ //QStringList inputPCMInfoList; /**< list of PCM Descriptions for input*/ QStringList outputPCMNameList; /**< list of PCM Names for output*/ //QStringList outputPCMInfoList; /**< list of PCM Descriptions for output*/ QString lastError; bool errorHandler(int err,QString info); void errorHandler(QString info); bool setupSoundParams(bool isCapture); int samplerate; snd_pcm_uframes_t playbackPeriodSize; snd_pcm_uframes_t playbackBufferSize; snd_pcm_uframes_t capturePeriodSize; snd_pcm_uframes_t captureBufferSize; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; bool abort; unsigned long storedFrames; eplaybackState playbackState; eplaybackState detectedPlaybackState; ecaptureState captureState; ecaptureState detectedCaptureState; bool soundOK; unsigned int minChannelsCapture; unsigned int maxChannelsCapture; unsigned int minChannelsPlayback; unsigned int maxChannelsPlayback; bool isStereo; void getDevices(snd_ctl_t *cardHandle, int cardNum, int devNum, snd_pcm_info_t *pcmInfo, snd_pcm_stream_t direction); QTime stopwatch; QMutex mutex; unsigned int calibrationFrames; int calibrationTime; }; /*! \var soundIO *soundIOPtr \brief predefined pointer to soundIO, must be initialized by the main program */ extern soundIO *soundIOPtr; #endif // SOUNDIO_H qsstv_8.2.12/qsstv/sound/waterfalltext.cpp000664 001750 001750 00000010152 12440612574 020674 0ustar00jomajoma000000 000000 #include "waterfalltext.h" #include "qsstvglobal.h" #include "configparams.h" #include "math.h" #include "widgets/imageviewer.h" #include #include #include "dsp/filter.h" #include "dsp/filterparam.h" #include "utils/supportfunctions.h" #define FREQ_AMPLITUDE 16E3 #define FREQ_OFFSET 350.0 #define FREQ_MAX 2600. #define FONTSIZE 13 #define FONTNAME "Arial" waterfallText::waterfallText() { out=NULL; outFiltered=NULL; dataBuffer=NULL; txFilter=NULL; phr=phi=NULL; } waterfallText::~waterfallText() { fftw_destroy_plan(plan); if(out) fftw_free(out); if(outFiltered) delete outFiltered; if(dataBuffer) fftw_free(dataBuffer); } void waterfallText::init() { int i; double ph; double binSize; if(phr!=NULL) delete phr; if(phi!=NULL) delete phi; fftLength=TXSTRIPE*SUBSAMPLINGRATIO/2; samplingrate=BASESAMPLERATE; binSize=(double)(BASESAMPLERATE)/((double)fftLength); txFilter= new filter(TXSTRIPE*SUBSAMPLINGRATIO,wfFilter,TXWFNUMTAPS,0,BASESAMPLERATE,true,1); out = (fftw_complex *) fftw_malloc(sizeof(fftw_complex)*fftLength); dataBuffer = (fftw_complex *) fftw_malloc(sizeof(fftw_complex)*fftLength); outFiltered = new DSPFLOAT [fftLength]; audioBuf = new DSPFLOAT [fftLength]; // create the fftw plan plan = fftw_plan_dft_1d(fftLength, dataBuffer, out, FFTW_BACKWARD, FFTW_ESTIMATE); imageWidth=(FREQ_MAX-FREQ_OFFSET)/binSize; // imageWidth=200; startFreqIndex=(int)round(FREQ_OFFSET/binSize); //Chirp phr=new double[imageWidth]; phi=new double[imageWidth]; amplitude=FREQ_AMPLITUDE/sqrt(imageWidth); for(i=0;iprocess(outFiltered,audioBuf,fftLength); } // for (i=0; i <10; i++) // { // outFiltered[i] = (audioBuf[i]*exp(-(10-i)*0.100)); // } // for (i=10; i #include "fftw3.h" #include #include #include "utils/macroexpansion.h" class imageViewer; class filter; class waterfallText { public: waterfallText(); ~ waterfallText(); void init(); void setText(QString txt); QImage *getImagePtr() {return ℑ} DSPFLOAT *nextLine(); int getLength() {return fftLength;} double getDuration(QString txt=NULL); private: int fftLength; int samplingrate; fftw_complex *out; fftw_complex *dataBuffer; DSPFLOAT *outFiltered; DSPFLOAT *audioBuf; fftw_plan plan; void setupImage(QString txt); QString convert(QString txt); int imageWidth; int width; int height; int line; filter *txFilter; QImage image; int dLine; int startFreqIndex; double *phr; double *phi; double amplitude; macroExpansion mexp; }; #endif // WATERFALLTEXT_H qsstv_8.2.12/qsstv/sound/wavio.cpp000664 001750 001750 00000023073 12440612574 017141 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "wavio.h" #include "qsstvglobal.h" #include #include "configparams.h" #include "utils/supportfunctions.h" #include "unistd.h" /** constructor: creates a waveIO instance \param samplingRate wave file samplingrate (e.g. 8000, 11025 ...) */ wavIO::wavIO(unsigned int samplingRate) { samplingrate=samplingRate; reading=false; writing=false; } wavIO::~wavIO() { } void wavIO::closeFile() { inopf.close(); reading=false; writing=false; } /** opens a wave file for reading \param fname the name of the file to open \param ask if ask==true, a filedialog will be opened \return true if the file is succcesfully opened. The file is also checked if it is a supported format. \sa read */ bool wavIO::openFileForRead(QString fname,bool ask) { QString tmp; if (ask) { dirDialog d((QWidget *)mainWindowPtr,"Wave file"); QString s=d.openFileName(audioPath,"*"); if (s==QString::null) return false; if (s.isEmpty()) return false; inopf.setFileName(s); } else { inopf.setFileName(fname); } if(!inopf.open(QIODevice::ReadOnly)) { return false; } reading=true; if(inopf.read(&waveHeader.chunkID[0],sizeof(sWave))!=sizeof(sWave)) { closeFile(); return false; } // check the header if( (!checkString(waveHeader.chunkID,"RIFF")) ||(!checkString(waveHeader.format,"WAVE")) ||(!checkString(waveHeader.subChunk1ID,"fmt ")) ||(!checkString(waveHeader.subChunk2ID,"data"))) { addToLog("wavio read header error",LOGALL); closeFile(); return false; } if( (waveHeader.subChunk1Size!=16) ||(waveHeader.audioFormat!=1) ||(waveHeader.numChannels>MAXNUMCHANNELS) ||(waveHeader.sampleRate!=samplingrate) // ||(waveHeader.byteRate!=sizeof(SOUNDFRAME)*samplingrate) ||(waveHeader.blockAlign!=waveHeader.numChannels*2) ||(waveHeader.bitsPerSample!=16)) { addToLog("wavio read header error, not supported",LOGALL); closeFile(); return false; } numberOfChannels=waveHeader.numChannels; numberOfSamples=waveHeader.subChunk2Size/(2*numberOfChannels); samplesRead=0; return true; } /** read data from wave file \param dPtr pointer to buffer for SOUNDFRAME type samples. \param numSamples number of samples to read \return returns the nummber of samples read. -1 is returned if the end of the file is reached. The file is then automatically closed. */ int wavIO::read(SOUNDFRAME *dPtr ,uint numSamples) { int i,llen,result; quint16 *tempBuf; if(!inopf.isOpen()) { addToLog("wavio not open during read",LOGALL); return -2; } if(numberOfSamples<=samplesRead) { closeFile(); return -1; } llen=numSamples*sizeof(quint16)*numberOfChannels; if(sizeof(SOUNDFRAME)/numberOfChannels==sizeof(quint16)) { //we do not need conversion result=inopf.read((char*)dPtr,llen); } else { tempBuf=new quint16[llen/2]; if(numberOfChannels==1) // if input is mono -> output in stereo { quint16 *tempBuf=new quint16[llen/2]; result=inopf.read((char*)tempBuf,llen); for(i=0;i<(result/2);i++) { dPtr[i]=tempBuf[i]+(tempBuf[i]<<16); } delete tempBuf; } else // if input is stereo -> output in mono (SOUNDFRAME is quint16) { result=inopf.read((char*)tempBuf,llen); for(i=0;i<(result/4);i++) { dPtr[i]=(tempBuf[2*i]+tempBuf[2*i+1])/2; } } } if(result==0) inopf.close(); samplesRead+=result/(sizeof(quint16)*numberOfChannels); return result/(sizeof(quint16)*numberOfChannels); } /** opens a wave file for writing \param fname the name of the file to open \param ask if ask==true, a filedialog will be opened \return true if the file is succcesfully opened, and the header written, false otherwise? \sa write */ bool wavIO::openFileForWrite(QString fname,bool ask,bool isStereo) { QFileInfo fin; if (ask) { dirDialog d((QWidget *)mainWindowPtr,"wave IO"); QString fn=d.saveFileName(audioPath,"*.wav","wav"); inopf.setFileName(fn); } else { inopf.setFileName(fname); } if(!inopf.open(QIODevice::WriteOnly|QIODevice::Truncate)) { return false; } numberOfSamples=0; if(isStereo) numberOfChannels=2; else numberOfChannels=1; initHeader(); if(!writeHeader()) return false; writing=true; numberOfSamples=0; return true; } /** \brief write data to wave file To signal the end, call this function with numSamples=0. The file will automatically be closed. \param dPtr pointer to buffer for 16 bit samples SOUNDFRAME indicates if samples are mono or stereo \param numSamples number of samples to read \return returns true the correct number of samples are written. false otherwise. */ bool wavIO::write(quint16 *dPtr, uint numSamples, bool isStereo) { uint i; int len; quint16 *tempBufPtr; len=numSamples*sizeof(SOUNDFRAME); tempBufPtr=0; quint16 *tmpPtr; tmpPtr=dPtr; if((!writing)&&(numSamples!=0)) { addToLog("wavio not open during write",LOGALL); return true; } if((!writing)&&(numSamples==0)) return true; if(numSamples==0) { addToLog(QString("wavio write close samples=%1").arg(numberOfSamples),LOGWAVIO); inopf.flush(); writeHeader(); closeFile(); return true; } if((sizeof(SOUNDFRAME)==2) && (isStereo)) // we need stereo output and input is mono { tempBufPtr=new quint16 [numSamples*2]; tmpPtr=tempBufPtr; for(i=0;i #include "qsstvdefs.h" /*! a WAVE format structure The canonical WAVE format starts with the RIFF header: \verbatim 0 4 ChunkID Contains the letters "RIFF" in ASCII form (0x52494646 big-endian form). 4 4 ChunkSize 36 + SubChunk2Size, or more precisely: 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size) This is the size of the rest of the chunk following this number. This is the size of the entire file in bytes minus 8 bytes for the two fields not included in this count: ChunkID and ChunkSize. 8 4 Format Contains the letters "WAVE" (0x57415645 big-endian form). The "WAVE" format consists of two subchunks: "fmt " and "data": The "fmt " subchunk describes the sound data's format: 12 4 Subchunk1ID Contains the letters "fmt " (0x666d7420 big-endian form). 16 4 Subchunk1Size 16 for PCM. This is the size of the rest of the Subchunk which follows this number. 20 2 AudioFormat PCM = 1 (i.e. Linear quantization) Values other than 1 indicate some form of compression. 22 2 NumChannels Mono = 1, Stereo = 2, etc. 24 4 SampleRate 8000, 44100, etc. 28 4 ByteRate == SampleRate * NumChannels * BitsPerSample/8 32 2 BlockAlign == NumChannels * BitsPerSample/8 The number of bytes for one sample including all channels. I wonder what happens when this number isn't an integer? 34 2 BitsPerSample 8 bits = 8, 16 bits = 16, etc. 2 ExtraParamSize if PCM, then doesn't exist X ExtraParams space for extra parameters The "data" subchunk contains the size of the data and the actual sound: 36 4 Subchunk2ID Contains the letters "data" (0x64617461 big-endian form). 40 4 Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data. You can also think of this as the size of the read of the subchunk following this number. 44 * Data The actual sound data. \endverbatim */ struct sWave { char chunkID[4]; //!< Contains the letters "RIFF" int chunkSize; //!< 36 + SubChunk2Size char format[4]; //!< Contains the letters "WAVE" char subChunk1ID[4]; //!< Contains the letters "fmt " int subChunk1Size; //!< 16 for PCM short int audioFormat; //!< PCM = 1 (i.e. Linear quantization) short int numChannels; //!< Mono = 1, Stereo = 2, etc. unsigned int sampleRate; //!< 8000, 44100, etc. unsigned int byteRate; //!< == SampleRate * NumChannels * BitsPerSample/8 short int blockAlign; //!< == NumChannels * BitsPerSample/8 short int bitsPerSample; //!< 8 bits = 8, 16 bits = 16, etc. char subChunk2ID[4]; //!< Contains the letters "data" int subChunk2Size; //!< NumSamples * NumChannels * BitsPerSample/8 }; //! class for accessing .wav files class wavIO { public: wavIO(unsigned int samplingR=BASESAMPLERATE); ~wavIO(); bool openFileForRead(QString fname,bool ask); bool openFileForWrite(QString fname, bool ask, bool isStereo); int read (quint32 *dPtr, uint len); bool write(quint16 *dPtr, uint len, bool isStereo); void setSamplingrate(int sr) {samplingrate=sr;} int getNumberOfChannels(){return numberOfChannels;} void closeFile(); /** return the number of samples in the opened file */ unsigned int getNumberOfSamples() { return numberOfSamples; } /** close all opened files */ void close() { if(inopf.isOpen()) { write(NULL,0,false); // flush everything in case we are writing closeFile(); } } private: sWave waveHeader; unsigned int numberOfSamples; unsigned int samplesRead; unsigned int samplingrate; int numberOfChannels; QFile inopf; void initHeader(); bool writeHeader(); bool checkString(char *str,const char *cstr); bool reading; bool writing; }; #endif qsstv_8.2.12/qsstv/sstv/cw.cpp000664 001750 001750 00000011273 12440612574 016273 0ustar00jomajoma000000 000000 /*************************************************************************** cw.cpp - QSSTV ------------------- begin : Tue Apr 17 22:27:58 CEST 2001 copyright : (C) 2001 by Johan Maes ON1MH email : on1mh@pandora.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "cw.h" #include #include "qsstvglobal.h" #include "configparams.h" enum eCWState {CWNEW,CWNEXTDOT,CWDOTSPACING,CWNEXTCHAR,CWCHARSPACING,CWWORDSPACING,CWEND,CWFINISHED}; enum eCWResult {CWIDLE,CWfalse,CWtrue}; static int dotIndex; static const char *dotPtr; static int charIndex; static float dotSpacing; static eCWState cwState; static eCWResult result; // const char *charLookupCW(char a); // bool sendChar(float &duration); // const char *s; static struct { char key; const char *cw; } charTable[] = { {'A', ".-" }, {'B',"-..." },{'C', "-.-." }, {'D', "-.." }, {'E',"." },{'F',"..-." }, {'G', "--." }, {'H',"...." },{'I',".." }, {'J', ".---" }, {'K',"-.-" },{'L',".-.." }, {'M', "--" }, {'N',"-." },{'O',"---" }, {'P', ".--." }, {'Q',"--.-" },{'R',".-." }, {'S', "..." }, {'T',"-" },{'U',"..-" }, {'V', "...-" }, {'W',".--" },{'X',"-..-" }, {'Y', "-.--" }, {'Z',"--.." }, {'0', "-----" }, {'1',".----" },{'2', "..---"}, {'3', "...--" }, {'4',"....-" },{'5',"....." }, {'6', "-...." }, {'7',"--..." },{'8',"---.." }, {'9', "----." }, {'"', ".-..-."}, {'\'', ".----." },{'$',"...-..-"}, {'(', "-.--." }, { ')', "-.--.-" },{'+',".-.-."}, {',', "--..--"}, {'-', "-....-" },{'.',".-.-.-"}, {'/', "-..-." }, { ':', "---..." },{';',"-.-.-."}, {'=', "-...-" }, { '?', "..--.." },{'_',"..--.-"}, {0, "" } }; static QString cwString; void initCW(QString cwTxt) { cwState=CWNEW; dotSpacing=1.2/(float)cwWPM; cwString=cwTxt; } const char *charLookupCW(const char a) { char b; int i=0;; b=toupper(a); dotIndex=0; while (charTable[i].key!=0) { if(charTable[i].key==b) { return (charTable[i].cw); } i++; } return NULL; } bool nextSymbolCW(float &duration) { if (dotPtr[dotIndex]==0) { return false; } else if(dotPtr[dotIndex]=='.') { duration=dotSpacing; } else { duration=3*dotSpacing; } dotIndex++; return true; } bool sendTextCW(float &tone,float &duration) { result=CWIDLE; do { switch (cwState) { case CWNEW: { charIndex=0; if (cwString[0]==0) { result=CWfalse; } cwState=CWNEXTCHAR; } break; case CWNEXTCHAR: { if(cwString[charIndex]==' ') { charIndex++; cwState=CWWORDSPACING; } else { dotPtr=charLookupCW(cwString[charIndex++].toLatin1()); if (dotPtr==NULL) { cwState=CWEND; } else { dotIndex=0; cwState=CWNEXTDOT; } } } break; case CWNEXTDOT: { if(nextSymbolCW(duration)) { tone=(float)cwTone; cwState=CWDOTSPACING; result=CWtrue; } else { cwState=CWCHARSPACING; } } break; case CWDOTSPACING: { tone=0; duration=dotSpacing; cwState=CWNEXTDOT; result=CWtrue; } break; case CWCHARSPACING: { tone=0; duration=2*dotSpacing; // we already had a dotspace cwState=CWNEXTCHAR; result=CWtrue; } break; case CWWORDSPACING: { tone=0; duration=4*dotSpacing; // we already had a charspace cwState=CWNEXTCHAR; result=CWtrue; } break; case CWEND: { tone=0; duration=7*dotSpacing; cwState=CWFINISHED; result=CWtrue; } break; case CWFINISHED: { result=CWfalse; } break; } } while(result==CWIDLE); return (result==CWtrue); } qsstv_8.2.12/qsstv/sstv/cw.h000664 001750 001750 00000002202 12440612574 015730 0ustar00jomajoma000000 000000 /*************************************************************************** cw.h - QSSTV ------------------- begin : Tue Apr 17 22:27:58 CEST 2001 copyright : (C) 2001 by Johan Maes ON1MH email : on1mh@pandora.be ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef CW_H #define CW_H #include void initCW(QString cwTxt); bool sendTextCW(float &tone,float &duration); #endif qsstv_8.2.12/qsstv/sstv/sstvparam.cpp000664 001750 001750 00000036273 12440612574 017711 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "sstvparam.h" #include "qsstvglobal.h" #include "utils/supportfunctions.h" #include "configparams.h" #include bool useVIS; bool autoSlantAdjust; bool autoSave; int squelch; int filterIndex; DSPFLOAT *lineTimeTableRX=NULL; DSPFLOAT *lineTimeTableTX=NULL; sSSTVParam rxSSTVParam; //sFAXParam rxFAXParam; sSSTVParam txSSTVParam; //sFAXParam txFAXParam; esstvMode sstvModeIndex; /** \brief setup the lineTable Setup a table containing the relative positions expressed in samples \param modeIndex index of the different modes: Martin1=0 , .... \param clock the adjusted samplingrate */ void setupSSTVLineTimeTable(esstvMode modeIndex,DSPFLOAT clock, bool transmit) { unsigned int i; if(transmit) { if (lineTimeTableTX!=NULL) delete [] lineTimeTableTX; lineTimeTableTX=new DSPFLOAT [SSTVTable[modeIndex].numberOfDataLines+1]; for (i=0;iname).arg(SSTVParam->shortName),LOGPARAM); addToLog(QString("imageTime=%1,numpix=%2,numDisplayLines=%3, numDataLines=%4,viscode=%5").arg(SSTVParam->imageTime) .arg(SSTVParam->numberOfPixels).arg(SSTVParam->numberOfDisplayLines).arg(SSTVParam->numberOfDataLines).arg(QString::number(SSTVParam->VISCode,16)),LOGPARAM); addToLog(QString("Samplecounters imageTime=%1 , lineTime=%2").arg(rint(SSTVParam->imageTime*clock)).arg(rint(SSTVParam->imageTime*11025./SSTVParam->numberOfDataLines)),LOGPARAM); } #else void printActiveSSTVParam(bool) {} #endif /** * setup parameters given the VIS code * @param vc VIS code of the mode to select * @return Returns the modeIndex if successful else NOTVALID */ esstvMode lookupVIS(unsigned int vc) { if(vc==0) return NOTVALID; esstvMode t=M1; do { if (SSTVTable[(int)t].VISCode==vc) { break; } t=(esstvMode)(t+1); } while (t=NUMSSTVMODES) return NOTVALID; return t; } /** \brief longname lookup Returns the long name of the mode \param[in] modeIndex selected mode \return short name of the mode or empty string if not a valid mode */ QString getSSTVModeNameLong(esstvMode modeIndex) { if(modeIndex==NOTVALID) return QString(""); return(SSTVTable[(int)modeIndex].name); } /** \brief shortname lookup Returns the short name of the mode \param[in] modeIndex selected mode \return short name of the mode or empty string if not a valid mode */ QString getSSTVModeNameShort(esstvMode modeIndex) { if(modeIndex==NOTVALID) return QString(""); return(SSTVTable[(int)modeIndex].shortName); } //QString getFAXModeNameLong(efaxMode modeIndex) //{ // if(modeIndex>=FAXNONE) return QString(""); // return(FAXTable[(int)modeIndex].name); //} //QString getFAXModeShort(efaxMode modeIndex) //{ // if(modeIndex>=FAXNONE) return QString(""); // return(FAXTable[(int)modeIndex].shortName); //} /** \brief lookup mode by line length Returns the closest match for a given line length \param[in] lineLength line length in samples \param clock the rx or tx clock to be used \return returns the modeIndex or NOTVALID if none found */ esstvMode modeLookup(unsigned int lineLength,DSPFLOAT clock) { int i; DSPFLOAT errLine, totalError; totalError=9999999; esstvMode lmode=NOTVALID; for (i=M1;ihighest) highest=length; } return highest; } // if slant \ raise image time /** \brief parameter table for all SSTV, FAX and CALIBRATION modes */ sSSTVParam SSTVTable[NUMSSTVMODES+1]= { // name shortName mode imagetime Pix Dis Txl VIS sync fp bp blank synctx fptx bptx blanktx {"Martin 1" ,"M1", M1, 114.29500,320,256,256,0x00AC,0.00500,0.00080,0.00050,0.00050,0.00500,0.00080,0.00000,0.00050,0.,1900,400 }, {"Martin 2" ,"M2", M2, 58.06300,320,256,256,0x0028,0.00500,0.00080,0.00050,0.00050,0.00500,0.00080,0.00000,0.00050,0.,1900,400 }, {"Scottie 1" ,"S1", S1, 109.62950,320,256,256,0x003c,0.00900,0.00080,0.00125,0.00125,0.00900,0.00080,0.00080,0.00125,0.,1900,400 }, {"Scottie 2" ,"S2", S2, 71.09250,320,256,256,0x00b8,0.00900,0.00080,0.00125,0.00125,0.00900,0.00000,0.00110,0.00125,0.,1900,400 }, {"Scottie DX","SDX", SDX, 268.89080,320,256,256,0x00cc,0.00900,0.00000,0.00000,0.00100,0.00900,0.00000,0.00000,0.00100,0.,1900,400 }, {"SC2 60", "SC2-60", SC2_60, 61.54150,320,256,256,0x00BB,0.00500,0.00100,0.00100,0.00100,0.00500,0.00000,0.00000,0.00000,0.,1900,400 }, {"SC2 120", "SC2-120",SC2_120, 121.74050,320,256,256,0x003F,0.00500,0.00100,0.00100,0.00100,0.00500,0.00000,0.00000,0.00000,0.,1900,400 }, {"SC2 180", "SC2-180",SC2_180, 182.03650,320,256,256,0x00B7,0.00500,0.00100,0.00100,0.00100,0.00500,0.00000,0.00000,0.00000,0.,1900,400 }, {"Robot 24", "R24", R24, 24.00150,160,120,120,0x0084,0.00600,0.00180,0.00125,0.00450,0.00600,0.00000,0.00120,0.00380,0.,1900,400 }, {"Robot 36" ,"R36", R36, 36.00200,320,240,240,0x0088,0.00900,0.00100,0.00340,0.00820,0.00900,0.00000,0.00300,0.00540,0.,1900,400 }, {"Robot 72" ,"R72", R72, 72.00375,320,240,240,0x000C,0.00900,0.00040,0.00250,0.00600,0.00900,0.00040,0.00250,0.00600,0.,1900,400 }, {"P3" ,"P3" , P3, 203.05960,640,496,496,0x0071,0.00520,0.00210,0.00080,0.00250,0.00520,0.00104,0.00104,0.00104,0.,1900,400 }, {"P5" ,"P5" , P5, 304.59050,640,496,496,0x0072,0.00780,0.00160,0.00160,0.00160,0.00780,0.00160,0.00160,0.00160,0.,1900,400 }, {"P7" ,"P7" , P7, 406.12000,640,496,496,0x00F3,0.01040,0.00210,0.00210,0.00210,0.01040,0.00210,0.00210,0.00210,0.,1900,400 }, {"B/W 8" ,"BW8" , BW8, 8.02850,160,120,120,0x0082,0.00600,0.00100,0.00100,0.00000,0.00600,0.00100,0.00100,0.00000,0.,1900,400 }, {"B/W 12" ,"BW12" , BW12, 12.00100,160,120,120,0x0086,0.00600,0.00100,0.00100,0.00000,0.00600,0.00100,0.00100,0.00000,0.,1900,400 }, {"PD50" ,"PD50", PD50, 49.68690,320,256,128,0x00DD,0.02000,0.00000,0.00208,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD90" ,"PD90", PD90, 89.99300,320,256,128,0x0063,0.02000,0.00000,0.00208,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD120" ,"PD120", PD120, 126.10930,640,496,248,0x005F,0.02000,0.00000,0.00208,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD160" ,"PD160", PD160, 160.89120,512,400,200,0x00E2,0.02000,0.00000,0.00200,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD180" ,"PD180", PD180, 187.06100,640,496,248,0x0060,0.02000,0.00000,0.00200,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD240" ,"PD240", PD240, 248.01300,640,496,248,0x00E1,0.02000,0.00000,0.00200,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"PD290" ,"PD290", PD290, 288.69524,800,616,308,0x00DE,0.02000,0.00000,0.00200,0.00000,0.02000,0.00000,0.00230,0.00000,0.,1900,400 }, {"MP73" ,"MP73", MP73, 72.96350,320,256,128,0x2523,0.00900,0.00000,0.00100,0.00000,0.00900,0.00000,0.00100,0.00000,0.,1900,400 }, {"MP115" ,"MP115", MP115, 115.46000,320,256,128,0x2923,0.00900,0.00000,0.00100,0.00000,0.00900,0.00000,0.00100,0.00000,0.,1900,400 }, {"MP140" ,"MP140", MP140, 139.54000,320,256,128,0x2A23,0.00900,0.00000,0.00100,0.00000,0.00900,0.00000,0.00100,0.00000,0.,1900,400 }, {"MP175" ,"MP175", MP175, 175.38011,320,256,128,0x2C23,0.00900,0.00000,0.00100,0.00000,0.00900,0.00000,0.00100,0.00000,0.,1900,400 }, {"FAX480" ,"FAX480", FAX480, 133.63300,512,500,500,0x0000,0.00512,0.00000,0.00000,0.00000,0.00512,0.00000,0.00000,0.00000,0.,1900,400 }, {"AVT24" ,"AVT24", AVT24, 22.50160,128,120,120,0x00c0,0.00500,0.00080,0.00050,0.00050,0.00500,0.00080,0.00000,0.00050,0.,1900,400 }, {"AVT90" ,"AVT90", AVT90, 90.00450,320,240,240,0x0044,0.00500,0.00080,0.00050,0.00050,0.00500,0.00080,0.00000,0.00050,0.,1900,400 }, {"AVT94" ,"AVT94", AVT94, 93.75000,320,200,200,0x0048,0.00500,0.00080,0.00050,0.00050,0.00500,0.00080,0.00000,0.00050,0.,1900,400 }, {"No Mode" ,"NOTVALID",NOTVALID ,0.00000,0,0,0,0x0000,0.00000,0.00000,0.000000,0.0000,0.00000,0.00000,0.000000,0.0000,0.,0,0} }; //sFAXParam FAXTable[NUMFAXMODES+1]= //{ //// name shortName mode modulation lpm ioc lines pixels carr dev start sFreq stop sFreq phL invert colorM // {"NOAA" ,"NOAA", NOAA ,DEMODAM, 120., 576, 800, 1810, 2400, 400, 0 , 300, 0, 450 , 0, false, 1}, // {"HFFAX" ,"HFFXAX", HFFAX ,DEMODFM, 120., 288, 800, 905, 1900, 400, 5 , 300, 5, 450 , 20, false, 1}, // {"Custom" ,"Custom", FAXCUSTOM ,DEMODAM, 121., 288, 180, 905, 1900, 400, 5 , 300, 5, 450 , 20, false, 1}, // {"No Mode" ,"NOTVALID",FAXNONE ,0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0 , 0, false, 0}, //}; //#ifndef QT_NO_DEBUG //void printActiveFAXParam(bool tx) //{ // sFAXParam * FAXParam; // if(tx) // { // FAXParam=&txFAXParam; // } // else // { // FAXParam=&rxFAXParam; // } // addToLog(QString("name=%1, shortname=%2\n").arg(FAXParam->name).arg(FAXParam->shortName),LOGPARAM); // addToLog(QString("modulation=%1,lpm=%2,ioc=%3,numDisplayLines=%4, subcarrier=%5,deviation=%6\n").arg(FAXParam->modulation) // .arg(FAXParam->lpm).arg(FAXParam->ioc).arg(FAXParam->numberOfDisplayLines).arg(FAXParam->subcarrier) // .arg(FAXParam->deviation),LOGPARAM); //} //#else //void printActiveFAXParam(bool ) {} //#endif ///** // * \brief setup active parameters // Setup active parameters given the modeIndex // * \param[in] modeIndex selected mode // * \return true if successful //*/ //bool initializeFAXParametersIndex(efaxMode modeIndex,bool tx) //{ // if (modeIndex < NUMFAXMODES) // { // if(tx) // { // txFAXParam=FAXTable[modeIndex]; // txFAXParam.numberOfPixels=(txFAXParam.ioc*31419+5000)/10000; // } // else // { // rxFAXParam=FAXTable[modeIndex]; // rxFAXParam.numberOfPixels=(rxFAXParam.ioc*31419+5000)/10000; // } // printActiveFAXParam(tx); // return true; // } // return false; //} //void copyCustomParam(bool tx) //{ //// memmove((char *)&FAXTable[FAXCUSTOM],(char *)&activeFAXParam,sizeof(sFAXParam)); // if(tx) FAXTable[FAXCUSTOM]=txFAXParam; // else FAXTable[FAXCUSTOM]=rxFAXParam;; //} /*** \brief setup the FAX lineTable Setup a table containing the relative positions expressed in samples \param clock the adjusted samplingrate */ //void setupFAXLineTimeTable(DSPFLOAT clock,bool tx) //{ // unsigned int i; // if(tx) // { // for (i=1;i<=txFAXParam.numberOfDisplayLines;i++) // { // // one lineTime= lpm/60 // lineTimeTableTX[i-1]=((60.*(DSPFLOAT)i)/txFAXParam.lpm)*clock; // } // } // else // { // for (i=1;i<=rxFAXParam.numberOfDisplayLines;i++) // { // // one lineTime= lpm/60 // lineTimeTableRX[i-1]=((60.*(DSPFLOAT)i)/rxFAXParam.lpm)*clock; // } // } //} qsstv_8.2.12/qsstv/sstv/sstvparam.h000664 001750 001750 00000007245 12440612574 017353 0ustar00jomajoma000000 000000 #ifndef SSTVPARAM_H #define SSTVPARAM_H #include #include "qsstvglobal.h" #include "qsstvdefs.h" /** \file */ /** SSTV Parameter functions @author Johan Maes - ON4QZ */ #define NUMSSTVMODES 31 //!< Number of SSTV Modes for RX and TX //#define NUMFAXMODES 3 //!< Number of FAX Modes for RX and TX #define GREENLINE 0 //!< index for green line buffer #define BLUELINE 1 //!< index for blue line buffer #define REDLINE 2 //!< index for red line buffer #define YLINEODD 3 //!< index for intensity line buffer 0 #define YLINEEVEN 4 //!< index for intensity line buffer 1 #define VIDEOBW 800 #define MAXLINES 800 #define DEMODAM 0 #define DEMODFM 1 #define MINSYNCWIDTH 0.004 #define MAXSYNCWIDTH 0.020 #define RETRACEWIDTH 0.29 /** \brief SSTV Modes M1 to FAX480 are using sync pulses, AVT modes do not use syncs. */ enum esstvMode { M1, M2, S1, S2, SDX, SC2_60, SC2_120, SC2_180, R24, R36, R72, P3, P5, P7, BW8, BW12, PD50, PD90, PD120, PD160, PD180, PD240, PD290, MP73, MP115, MP140, MP175, FAX480, AVT24, AVT90, AVT94, NOTVALID }; //enum efaxMode //{ // NOAA, // HFFAX, // FAXCUSTOM, // FAXNONE //}; /* // struc used in frequency detection struct sTimeFreq { DSPFLOAT t; // time in sec DSPFLOAT dt; // minimum duration in sec unsigned int f; // frequency to detect (freq=0 if any freq) }; */ /** \brief sstv parameter structure Structure containing all the mode depended parameters Some of the parameters are updated at run time */ struct sSSTVParam { QString name; QString shortName; enum esstvMode mode; DSPFLOAT imageTime; unsigned int numberOfPixels; // NumberOfPixels per Line unsigned int numberOfDisplayLines; unsigned int numberOfDataLines; // data lines unsigned short int VISCode; float sync; //used for rx float fp; float bp; float blank; float synct; // used for tx float fpt; float bpt; float blankt; DSPFLOAT pixelDuration; int subcarrier; int deviation; }; //struct sFAXParam //{ // ~sFAXParam(){} // QString name; // QString shortName; //// enum efaxMode mode; // uint modulation; // double lpm; // unsigned int ioc; // unsigned int numberOfDisplayLines; // unsigned int numberOfPixels; // int subcarrier; // int deviation; // int aptStartDuration; // int aptStartFreq; // int aptStopDuration; // int aptStopFreq; // unsigned int numberOfPhasingLines; // bool inverted; // unsigned int colorMode; //}; extern sSSTVParam SSTVTable[NUMSSTVMODES+1]; //extern sFAXParam FAXTable[NUMFAXMODES+1]; extern sSSTVParam rxSSTVParam; //extern sFAXParam rxFAXParam; extern sSSTVParam txSSTVParam; //extern sFAXParam txFAXParam; extern DSPFLOAT *lineTimeTableRX; extern DSPFLOAT *lineTimeTableTX; void setupSSTVLineTimeTable(esstvMode modeIndex,DSPFLOAT clock,bool transmit); DSPFLOAT lineLength(esstvMode modeIndex,DSPFLOAT clock); DSPFLOAT syncWidth(esstvMode modeIndex,DSPFLOAT clock); //void setupFAXLineTimeTable(DSPFLOAT clock); esstvMode initializeParametersVIS(unsigned int viscode,bool tx); bool initializeSSTVParametersIndex(esstvMode modeIndex,bool tx); //bool initializeFAXParametersIndex(efaxMode modeIndex,bool tx); esstvMode lookupVIS(unsigned int vc); QString getSSTVModeNameLong(esstvMode m); QString getSSTVModeNameShort(esstvMode m); //QString getFAXModeNameLong(efaxMode m); //QString getFAXModeShort(efaxMode m); esstvMode modeLookup(unsigned int lineLength,DSPFLOAT clock); DSPFLOAT longestLine(DSPFLOAT clock); bool lineIsValid(esstvMode mode,unsigned int lineLength,DSPFLOAT clock); void printActiveSSTVParam(bool tx); void copyCustomParam(bool tx); extern bool useVIS; extern bool autoSlantAdjust; extern bool autoSave; extern int squelch; extern int filterIndex; extern esstvMode sstvModeIndex; #endif qsstv_8.2.12/qsstv/sstv/syncprocessor.cpp000664 001750 001750 00000050732 12474635672 020614 0ustar00jomajoma000000 000000 #include "syncprocessor.h" #include "qsstvglobal.h" #ifndef QT_NO_DEBUG #include "scope/scopeview.h" #endif #include "dsp/filterparam.h" #include "configparams.h" #include "dispatcher.h" #include #include /*! \class syncProcessor Filters the incoming signal using a narrow bandpassfilter centered around 1200 Hz The basspand filter is wide enough to detect the 1100Hz-1300Hz used during retarce, carrying the VisCode. Event generated: verticalRetraceEvent
isInSync: test for sync status \sa getSyncPosition() */ const QString squelchStr[NUMSENSITIVITIES]= { "Strong", "Medium", "Weak", "DX" }; ssenitivity sensitivityArray[NUMSENSITIVITIES]= /**< TODO */ { {0.70, 0.45, 1000, 7}, {0.60, 0.45, 1000, 15}, {0.60, 0.45, 100, 20}, {0.60, 0.45, 100, 999} }; /** * @brief * * @param parent */ syncProcessor::syncProcessor(QObject *parent) : QObject(parent) { syncFilter=NULL; } /** * @brief * */ void syncProcessor::init() { freqPtr=syncFilter->filteredDataPtr(); syncVolumePtr=syncFilter->volumePtr(); rxVolumePtr=rxFilter->volumePtr(); sampleCounter=0; syncArrayIndex=0; shadowSyncArrayIndex=0; syncState=SYNCOFF; syncFound=false; slantAdjustLine=6; signalQuality=0; modifiedClock=rxClock/SUBSAMPLINGRATIO; newClock=false; idxStart=M1; idxEnd=FAX480; volumeOffCounter=0; syncDeviation=SYNCDEVIATION; retraceDetected=false; if(sstvModeIndex!=0) { idxEnd=idxStart=(esstvMode)(sstvModeIndex-1); } #ifndef QT_NO_DEBUG scopeViewerSync->setCurveName("SYNC VOL",SCDATA1); scopeViewerSync->setCurveName("Sync State",SCDATA2); scopeViewerSync->setCurveName("RX VOL",SCDATA3); scopeViewerSync->setCurveName("SYNC Freq",SCDATA4); scopeViewerSync->setAxisTitles("Samples","int","State"); #endif displaySyncEvent* ce; ce = new displaySyncEvent(0,0); QApplication::postEvent(dispatcherPtr, ce); } #ifndef QT_NO_DEBUG void syncProcessor::setOffset(unsigned int dataScopeOffset) { xOffset=dataScopeOffset; scopeViewerSync->setOffset(xOffset); } #endif /** * @brief * */ void syncProcessor::process() { if(!syncFound) syncQuality=0; // addToLog(QString("sync samplecounter:%1").arg(sampleCounter),LOGSYNC1); extractSync(); #ifndef QT_NO_DEBUG scopeViewerSync->addData(SCDATA1,syncVolumePtr,sampleCounter,RXSTRIPE); scopeViewerSync->addData(SCDATA2,syncStateBuffer,sampleCounter,RXSTRIPE); scopeViewerSync->addData(SCDATA3,rxVolumePtr,sampleCounter,RXSTRIPE); scopeViewerSync->addData(SCDATA4,freqPtr,sampleCounter,RXSTRIPE); #endif sampleCounter+=RXSTRIPE; } /** * @brief * */ void syncProcessor::extractSync() { int i; int syncDurationCount=0; DSPFLOAT syncAvgFreq=0; for(i=0;i0) volumeOffCounter--; if(syncState==SYNCOFF) { if(syncVolumePtr[i]>(sensitivityArray[squelch].switchOn*rxVolumePtr[i])) { // addToLog(QString("volume switch on %1").arg(rxVolumePtr[i]),LOGSYNC1); syncState=SYNCON; visCode=0; visCounter=0; visAvg=0.; syncDurationCount=0; syncAvgFreq=1200; syncArray[syncArrayIndex].start=sampleCounter+i; } } else { if(syncVolumePtr[i]<(sensitivityArray[squelch].switchOff*rxVolumePtr[i])) { // addToLog(QString("volume switch off %1").arg(rxVolumePtr[i]),LOGSYNC1); syncState=SYNCOFF; syncArray[syncArrayIndex].end=sampleCounter+i; syncArray[syncArrayIndex].width=syncArray[syncArrayIndex].end-syncArray[syncArrayIndex].start; syncArray[syncArrayIndex].freq=syncAvgFreq; if(syncArray[syncArrayIndex].width>(MINSYNCWIDTH*SAMPLERATE)) { if(syncArray[syncArrayIndex].width>(RETRACEWIDTH*SAMPLERATE)) { syncArray[syncArrayIndex].retrace=true; modeDetect(true); } else { visCode=0; syncArray[syncArrayIndex].retrace=false; modeDetect(false); } incrementSyncArray(); } } else // we are still detecting a sync { visCounter++; syncDurationCount++; if((syncDurationCount>10) && (syncDurationCount<50)) { syncAvgFreq=syncAvgFreq+0.1*(freqPtr[i]-syncAvgFreq); } if(visCounter>100) { visAvg+=freqPtr[i]; } if(visCounter==200) { visAvg/=100.; visCode=visCode>>1; if(visAvg<=1200.) visCode=visCode | 0X100; addToLog(QString("visfreq %1, counter %2, code=%3").arg(visAvg).arg(visCounter).arg(visCode),LOGSYNC2); } if(visCounter > (unsigned int)(0.030*SAMPLERATE)) //reset visCounter per bit { visCounter=0; visAvg=0.; } } } } syncStateBuffer[i]=(unsigned int)syncState*STATEMULTIPLIER; } if(syncFound) { if(volumeOffCounter>(samplesPerLine*sensitivityArray[squelch].syncLost)) { restart(); } } } /** * @brief * */ void syncProcessor::modeDetect(bool atRetrace) { // bool done; shadowSyncArray[shadowSyncArrayIndex]=syncArray[syncArrayIndex]; dumpSyncArray(false,syncArrayIndex); if(!atRetrace) modeDetectByLine(); else { if(syncFound==true) { // we have a retrace during image capturing // verticalRetraceEvent* ce; // ce = new verticalRetraceEvent(); // ce->waitFor(&done); // QApplication::postEvent(dispatcherPtr, ce); // addToLog("Vertical retrace while imagecapturing",LOGSYNC1); retraceDetected=true; return; } moveToTop(syncArrayIndex); if((mode=lookupVIS(visCode))!=NOTVALID) { syncFound=true; syncQuality=4; syncPosition=syncArray[0].end; /// this always indicates a valid retrace syncArrayIndex=0; addToLog(QString("modeDetect: after retrace syncpos:=%1").arg(syncPosition),LOGSYNC1); samplesPerLine=lineLength(mode,modifiedClock); syncWd=syncWidth(mode,modifiedClock); addToLog(QString("syncProcessor:modeDetect Viscode used: %1,mode=%2").arg(QString::number(visCode,16)).arg(mode),LOGSYNC1); // logfile->addToAux(QString("Index\tStart\tEnd\tClosestLine\tRetrace\t%1").arg(samplesPerLine)); return; } else if(visCode!=0) { syncFound=false; addToLog(QString("syncProcessor:modeDetect Viscode rejected: %1").arg(QString::number(visCode,16)),LOGSYNC1); } } } /** * @brief use sync interval to detect mode * * The syncArrayIndex is pointing to the last valid entry in the array (i.e. it is post incremented) * We need a minimal number of syncs to determine the mode. * */ void syncProcessor::modeDetectByLine() { int i; esstvMode selectedMode; unsigned int highest=0; selectedMode=NOTVALID; if(syncArrayIndex<3) return; // we need enough sync entries for(i=idxStart;ihighest) && (modeArray[i].match>=3)) { if(modeArray[i].consecutiveSyncs<3) continue; highest=modeArray[i].match; selectedMode=(esstvMode)i; } } if(syncFound==true) { trackSyncs(selectedMode); return; } if(selectedMode==NOTVALID) return; if(modeArray[selectedMode].consecutiveSyncs<3) return; // we have a good match //dumpSyncArray(); mode=selectedMode; samplesPerLine=lineLength(mode,modifiedClock); syncWd=syncWidth(mode,modifiedClock); //find first occurence moveToTop(modeArray[(int)selectedMode].firstSyncIndex); syncPosition=syncArray[0].end; // logfile->addToAux(QString("Index\tStart\tEnd\tClosestLine\tRetrace\t%1").arg(samplesPerLine)); cleanupSyncArray(selectedMode); syncFound=true; // must be after cleaunupSyncArray syncQuality=4;; addToLog(QString("syncFound at: %1 mode=%2").arg(syncPosition).arg(selectedMode),LOGSYNC1); } void syncProcessor::getMatchingSyncPulse(esstvMode idx) { int i; bool adjecent=true; DSPFLOAT ratio,length,syncW; unsigned int offset; unsigned int pos; int start,result; ssyncArray *ptr; int syncIndex; if(syncFound) { ptr=shadowSyncArray; syncIndex=shadowSyncArrayIndex; } else { ptr=syncArray; syncIndex=syncArrayIndex; } length=lineLength(idx,modifiedClock); syncW=syncWidth(idx,modifiedClock); offset=ptr[syncIndex].end- (int)rint(syncW/2); start=syncIndex-1; if(offset<=length) return; pos=offset-length; modeArray[idx].clear(); ratio=1000; for(i=0;i<=syncIndex;i++) { ptr[i].inUse=false; } while(1) { if((result=matchingSync(start,pos,syncW,syncFound))>=0) { pos=ptr[result].end-(int)rint(syncW/2); start=result-1; if(ptr[result].spurious<2) { modeArray[idx].match++; modeArray[idx].firstSyncIndex=result; ptr[result].inUse=1; if(adjecent==true) modeArray[idx].consecutiveSyncs++; } } else { adjecent=false; } modeArray[idx].lineNumber++; if(pos=3) { ratio=((double)(ptr[syncIndex].end-ptr[modeArray[idx].firstSyncIndex].end))/(length*(double) modeArray[idx].match); ratio*=(double) modeArray[idx].match/(double) modeArray[idx].consecutiveSyncs; } modeArray[idx].ratio=ratio; } /** * @brief check if we find a syncpulse at position pos * * @param start index of last position in syncArray * @param pos samplecounter value of the sync * @param syncWidth * @return int index of syncArray where we found the sync at position pos, -1 if not found */ int syncProcessor::matchingSync(int start, unsigned int pos, DSPFLOAT syncWidth, bool shadow) { int i; int spurious=0; DSPFLOAT sw; ssyncArray *ptr; if(shadow) ptr=shadowSyncArray; else ptr=syncArray; for(i=start;i>=0;i--) { if(i>=SYNCARRAYLENGTH) { // qDebug() << "index error"; } sw=(DSPFLOAT)(ptr[i].end-ptr[i].start); if(ptr[i].retrace==true) { if((pos>ptr[i].end-MAXSYNCWIDTH*modifiedClock) && (pos(1.2*sw))||(syncWidth<(0.8*sw))) { continue; } else if((pos>ptr[i].start) && (posptr[i].end) return -1; spurious++; } return -1; } /*! returns 0 if not in Sync returns 1 if in Sync without a retrace returns 2 if in Sync and retrace -- the syncPosition is at the end of the retrace */ int syncProcessor::isInSync() { int result=0; if(syncFound) { result++; if(syncArray[0].retrace==true) { result++; } } return result; } /** * @brief * */ void syncProcessor::incrementSyncArray() { if (syncArrayIndex==(SYNCARRAYLENGTH-1)) { memmove(syncArray,&syncArray[1],sizeof(ssyncArray)*(SYNCARRAYLENGTH-1)); } else syncArrayIndex++; //copy syncArray to shadowSyncArray { if (shadowSyncArrayIndex==(SYNCARRAYLENGTH-1)) { memmove(shadowSyncArray,&shadowSyncArray[1],sizeof(ssyncArray)*(SYNCARRAYLENGTH-1)); } else shadowSyncArrayIndex++; } } /*! shift up the syncArray so that syncArray[index] is at the top. */ void syncProcessor::moveToTop(int index) { if(index==0) return; memmove(syncArray,syncArray+index,sizeof(ssyncArray)*(syncArrayIndex+1-index)); syncArrayIndex-=index; shadowSyncArrayIndex=0; // reset shadowIndex } void syncProcessor::cleanupSyncArray(esstvMode modeIndex) { unsigned int i,stpos; getMatchingSyncPulse(modeIndex); for(i=0;i0) syncQuality--; } /*! The modeDetect tries to find the sstv mode based on the line length. If there are a number (based on the squelch) of consecutive correct lines the syncFound and the mode are set. The syncArray is the searched for the first valid line length and the pointer is set at the end of the sync pulse. */ void syncProcessor::dumpSyncArray(bool withShadow, int start) { int st=start; if(start==0) { addToLog(QString("index=%1 start=%2 end=%3 width=%4 linelength=n/a frequency=%5 volume=%6") .arg(0).arg(syncArray[0].start).arg(syncArray[0].end) .arg(syncArray[0].end-syncArray[0].start).arg(syncArray[0].freq).arg(rxVolumePtr[0]),LOGSYNC2); st=1; } for(uint i=st;i<=syncArrayIndex;i++) { addToLog(QString("index=%1 start=%2 end=%3 width=%4 linelength=%5 frequency=%6 volume=%7") .arg(i).arg(syncArray[i].start).arg(syncArray[i].end) .arg(syncArray[i].end-syncArray[i].start).arg(syncArray[i].end-syncArray[i-1].end) .arg(syncArray[i].freq).arg(rxVolumePtr[0]),LOGSYNC2); } if(withShadow) { if(start==0) { addToLog(QString("syncProcessor: shadowSyncArrayDump index=%1 start=%2 end=%3 width=%4 linelength=n/a frequency=%5 volume=%6") .arg(0).arg(shadowSyncArray[0].start).arg(shadowSyncArray[0].end) .arg(shadowSyncArray[0].end-shadowSyncArray[0].start).arg(shadowSyncArray[0].freq).arg(rxVolumePtr[0]),LOGSYNC2); st=1; } for(uint i=st;i<=shadowSyncArrayIndex;i++) { addToLog(QString("syncProcessor: shadowSyncArrayDump index=%1 start=%2 end=%3 width=%4 linelength=%5 frequency=%6 volume=%7") .arg(i).arg(shadowSyncArray[i].start).arg(shadowSyncArray[i].end) .arg(shadowSyncArray[i].end-shadowSyncArray[i].start).arg(shadowSyncArray[i].end-shadowSyncArray[i-1].end) .arg(shadowSyncArray[i].freq).arg(rxVolumePtr[0]),LOGSYNC2); } } } int syncProcessor::getSignalQuality() { if(!syncFound) { syncQuality=0; lostLines=0; return 0; } if(syncArrayIndex<7) { syncQuality=4; } // qDebug() << "diff" << sampleCounterIndexed-syncArray[syncArrayIndex-1].end << "index" << syncArrayIndex-1; // qDebug() << "samplesPerLine" << samplesPerLine << "lost" <(samplesPerLine*sensitivityArray[squelch].syncLost)) { syncQuality=0; } if(lostLines!=0) { if(lostLines>sensitivityArray[squelch].syncLost/3) syncQuality--; if(lostLines>sensitivityArray[squelch].syncLost/2) syncQuality--; if(syncQuality<0) syncQuality=0; addToLog(QString("lostLines %1, sq:=%2").arg(lostLines).arg(syncQuality),LOGSYNC1); lostLines=0; } else { addToLog(QString("sq:=%2").arg(syncQuality),LOGSYNC1); if(syncQuality<10) syncQuality++; } return syncQuality; } void syncProcessor::trackSyncs(esstvMode selectedMode) { double temp; double tempr; if((selectedMode!=mode)&&(selectedMode!=NOTVALID)) { // qDebug() << "new mode detected"; // dumpSyncArray(); } temp=(double)(syncArray[syncArrayIndex].end-syncArray[syncArrayIndex-1].end); tempr =round(temp/samplesPerLine)*samplesPerLine+0.00000001; // make it non-zero to avoid divide by zero temp=temp/tempr; if(fabs(1-temp)>SYNCDEVIATION) { // addToLog(QString("delete sync entry %1").arg(syncArrayIndex),LOGSYNC1); deleteSyncEntry(syncArrayIndex); return; } ssyncArray *ptr=&syncArray[syncArrayIndex]; addToLog(QString("SyncArrayIndex %1").arg(syncArrayIndex),LOGSYNC1); if(syncArrayIndex>0) { ptr->length=ptr->end-syncArray[syncArrayIndex-1].end; } else ptr->length=0; syncArray[syncArrayIndex].lineNumber=(int) round(((double)(syncArray[syncArrayIndex].end-syncArray[0].end))/samplesPerLine); lostLines=syncArray[syncArrayIndex].lineNumber-syncArray[syncArrayIndex-1].lineNumber-1; if(getSignalQuality()<3) { restart(); return; } if(!autoSlantAdjust) return; if ((mode>=AVT24) && (mode <= AVT94)) return; if (syncArray[syncArrayIndex].lineNumberwaitFor(&done); // QApplication::postEvent(dispatcherPtr, ce); // while(!done) { qApp->processEvents();} addToLog("sync lost",LOGSYNC1); syncFound=false; } bool syncProcessor::regression(DSPFLOAT &a,DSPFLOAT &b,int start, int end) { /* calculate linear regression formula x=a+by b=sum((x[i]-xm)*(y[i]-ym))/sum((y[i]-ym)*(y[i]-ym)) a=xm-b*ym */ int i,j; unsigned int tempCount=0; DSPFLOAT sum_x,sum_y,sum_xx,sum_xy; sum_x=sum_y=sum_xx=sum_xy=a=b=0; for(j=1,i=start;i<=end;i++,j++) { slantArray[j].y= (DSPFLOAT)(syncArray[i].end-syncArray[start-1].end); slantArray[j].x= round(slantArray[j].y/samplesPerLine)*samplesPerLine; // qDebug() << slantArray[j].x << slantArray[j].y << slantArray[j].x-slantArray[j].y; if(slantArray[j].x-slantArray[j].y<150) { sum_x+=slantArray[tempCount].x; sum_y+=slantArray[tempCount].y; sum_xx+=slantArray[tempCount].x*slantArray[tempCount].x; sum_xy+=slantArray[tempCount].x*slantArray[tempCount].y; tempCount++; } } if(tempCount < 5) return false; b=((tempCount)*sum_xy-(sum_x*sum_y))/((tempCount)*sum_xx-(sum_x*sum_x)); a=sum_y/(tempCount)-(b*sum_x)/(tempCount); return true; } void syncProcessor::slantAdjust() { DSPFLOAT a,b; if ((mode>=AVT24) && (mode <= AVT94)) return ; if(mode==NOTVALID) return ; // logfile->addToAux(QString("%1\t%2\t%3\t%4") // .arg(syncArrayIndex) // .arg(syncArray[syncArrayIndex].start) // .arg(syncArray[syncArrayIndex].end) // .arg(syncArray[syncArrayIndex].retrace) // ); if (((mode==S1)||(mode==S2)||(mode==SDX))&&(syncArray[0].retrace==true)) { if(!regression(a,b,2,syncArrayIndex)) return; } else { if(!regression(a,b,1,syncArrayIndex)) return; } addToLog(QString("step:%1 a=%2 b=%3, modified rxclock=%4").arg(syncArrayIndex).arg(a).arg(b).arg(modifiedClock*b),LOGSLANT); slantAdjustLine+=7; if((fabs(1.-b)>0.00001)||(fabs(a)>1)) { newClock=true; modifiedClock*=b; samplesPerLine=lineLength(mode,modifiedClock); //recalculate the samples per line addToLog("new clock accepted",LOGSLANT); syncPosition=syncArray[0].end+(long)round(a); addToLog(QString("slantAdjust: modified syncpos:=%1").arg(syncPosition),LOGSLANT); syncDeviation=SYNCDEVIATION/3.; } } qsstv_8.2.12/qsstv/sstv/syncprocessor.h000664 001750 001750 00000006507 12474612175 020253 0ustar00jomajoma000000 000000 #ifndef SYNCPROCESSOR_H #define SYNCPROCESSOR_H #include "qsstvdefs.h" #include "dsp/filter.h" #include "sstvparam.h" #define SYNCARRAYLENGTH 512 #define SYNCDEVIATION 0.008 #define STATEMULTIPLIER 1000 #define NUMSENSITIVITIES 4 extern const QString squelchStr[NUMSENSITIVITIES]; struct ssyncArray { ssyncArray() { init(); } void init() { start=end=length=width=0; retrace=false; keep=false; inUse=false; lineNumber=0; spurious=0; } unsigned int start; unsigned int end; unsigned int width; unsigned int length; unsigned int lineNumber; unsigned int spurious; DSPFLOAT freq; DSPFLOAT maxVol; bool retrace; bool keep; bool inUse; }; struct smodeArray { void clear() { match=0; lineNumber=0; consecutiveSyncs=0; firstSyncIndex=0; ratio=0; } unsigned int match; unsigned int lineNumber; unsigned int consecutiveSyncs; unsigned int firstSyncIndex; DSPFLOAT ratio; }; struct ssenitivity { DSPFLOAT switchOn; DSPFLOAT switchOff; DSPFLOAT minVolume; unsigned int syncLost; }; struct sslantArray { DSPFLOAT x; DSPFLOAT y; }; #include class syncProcessor : public QObject { enum esyncState {SYNCOFF,SYNCON,SYNCVALID}; Q_OBJECT public: explicit syncProcessor(QObject *parent = 0); void init(); void setFilters(filter *rx,filter *sync) {rxFilter=rx; syncFilter=sync;} void process(); int isInSync(); bool hasRetrace(){return retraceDetected;} bool hasNewClock() { bool nc=newClock; newClock=false; return nc; } unsigned long getSyncPosition() { return syncPosition;} esstvMode getMode() {return mode ;} // DSPFLOAT *getSyncBufferPtr() {return syncBufferPtr;} DSPFLOAT getNewClock() {return modifiedClock;} void setOffset(unsigned int dataScopeOffset); int syncQuality; signals: public slots: private: filter *rxFilter; filter *syncFilter; unsigned int sampleCounter; unsigned int sampleCounterIndexed; void extractSync(); void incrementSyncArray(); void modeDetect(bool atRetrace); void modeDetectByLine(); void getMatchingSyncPulse(esstvMode idx); int matchingSync(int start,unsigned int pos,DSPFLOAT syncWidth, bool shadow); void moveToTop(int index); void cleanupSyncArray(esstvMode modeIndex); void deleteSyncEntry(int index); void dumpSyncArray(bool withShadow,int start=0); int getSignalQuality(); void trackSyncs(esstvMode selectedMode); bool regression(DSPFLOAT &a,DSPFLOAT &b,int start, int end); void slantAdjust(); void restart(); int *syncVolumePtr; int *rxVolumePtr; int *freqPtr; unsigned int syncStateBuffer[RXSTRIPE]; esyncState syncState; ssyncArray syncArray[SYNCARRAYLENGTH]; unsigned int syncArrayIndex; ssyncArray shadowSyncArray[SYNCARRAYLENGTH]; unsigned int shadowSyncArrayIndex; smodeArray modeArray[AVT24]; int signalQuality; unsigned int visCode; unsigned int visCounter; DSPFLOAT visAvg; unsigned int volumeOffCounter; esstvMode mode; DSPFLOAT modifiedClock; DSPFLOAT samplesPerLine; DSPFLOAT syncWd; unsigned int syncPosition; bool syncFound; unsigned int slantAdjustLine; sslantArray slantArray [SYNCARRAYLENGTH]; bool newClock; DSPFLOAT syncDeviation; esstvMode idxStart; esstvMode idxEnd; unsigned int xOffset; unsigned int lostLines; bool retraceDetected; }; #endif // SYNCPROCESSOR_H qsstv_8.2.12/qsstv/utils/buffermanag.h000664 001750 001750 00000011544 12440612574 017746 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef BUFFERMANAG_H #define BUFFERMANAG_H #include #include #include "qsstvglobal.h" #include template class buffer { public: buffer() { reset(); } unsigned int count() { return ((writeIndex-readIndex)& ((1<count()) { mutex.unlock(); return false; } for(i=0;ispaceLeft()) { mutex.unlock(); return false; } // addToLog(QString("writing %1").arg(len),LOGSOUND); for(i=0;icount()) { mutex.unlock(); return false; } readIndex+=s; readIndex&= ((1<spaceLeft()) { mutex.unlock(); return false; } readIndex-=s; readIndex&= ((1< #include #include #include "configparams.h" #include #include "dispatcher.h" #define FTPTIMEOUTTIME 12000 ftpInterface::ftpInterface(QString id) { ftp=NULL; name=id; sourceFn=NULL; init(); } ftpInterface::~ftpInterface() { addToLog("FTP destroy in delete",LOGFTP); destroy(); if(ftp) delete ftp; } void ftpInterface::init() { if(ftp) { destroy(); delete ftp; } ftp = new QFtp( 0); connect( ftp, SIGNAL(commandStarted(int)),SLOT(ftp_commandStarted(int)) ); connect( ftp, SIGNAL(commandFinished(int,bool)),SLOT(ftp_commandFinished(int,bool)) ); connect( ftp, SIGNAL(done(bool)),SLOT(ftp_done(bool)) ); connect( ftp, SIGNAL(stateChanged(int)),SLOT(ftp_stateChanged(int)) ); connect( ftp, SIGNAL(listInfo(const QUrlInfo &)),SLOT(ftp_listInfo(const QUrlInfo &)) ); connect( ftp, SIGNAL(rawCommandReply(int, const QString &)),SLOT(ftp_rawCommandReply(int, const QString &)) ); connect( ftp, SIGNAL(dataTransferProgress(qint64,qint64)),SLOT(slotProgress(qint64,qint64)) ); // connect( progress, SIGNAL(canceled()), SLOT(slotAbort()) ); } void ftpInterface::destroy() { addToLog("FTP show state in destroy",LOGFTP); ftp_stateChanged(ftp->state()); if ( ftp->state() != QFtp::Unconnected ) { addToLog("FTP destroy",LOGFTP); ftp->close(); } } eftpError ftpInterface::doConnect() { ftpDone=true; aborting=false; addToLog(QString("FTP doConnect"),LOGFTP); dumpState(); if(isUnconnected()) { addToLog(QString("FTP connect to host %1").arg(host),LOGFTP); ftpDone=false; connectToHost(); } else { addToLog(QString("FTP already connected to host %1").arg(host),LOGFTP); } tim.setSingleShot(true); tim.start(FTPTIMEOUTTIME); while(!ftpDone) { if(aborting) { return FTPCANCELED; } qApp->processEvents(); if(!tim.isActive()) { slotAbort(); addToLog("ftp Timeout",LOGALL); return FTPTIMEOUT; } } tim.stop(); if(!ftpCommandSuccess) { addToLog("FTP not connected",LOGFTP); return FTPERROR; } addToLog(QString("FTP connected to %1").arg(host),LOGFTP); return FTPOK; } eftpError ftpInterface::uploadFile(QString fileName,QString targetFilename,bool reconnect) { int id; eftpError result; addToLog("FTP uploadFile",LOGFTP); if ( fileName.isNull() ) return FTPNAMEERROR; if(reconnect) { result=doConnect(); if(result!=FTPOK) return result; } sourceFn=new QFile(fileName); if ( !sourceFn->open( QIODevice::ReadOnly ) ) { // QMessageBox::critical( 0, tr("Upload error"), // tr("Can't open file '%1' for reading.").arg(fileName) ); sourceFn=NULL; return FTPNAMEERROR; } QFileInfo fi( fileName ); QFileInfo fin(targetFilename); addToLog(QString("FTP bytes: %1").arg(sourceFn->size()),LOGFTP); ftpDone=false; if(fin.fileName().isEmpty()) { id=ftp->put( sourceFn, fi.fileName(),QFtp::Binary); } else { id=ftp->put( sourceFn, fin.fileName(),QFtp::Binary); } addToLog(QString("FTP put file id: %1").arg(id),LOGFTP); while(!ftpDone) { if(aborting) return FTPCANCELED; qApp->processEvents(); } if(!ftpCommandSuccess) return FTPERROR; addToLog("FTP starting progress",LOGFTP); return FTPOK; } eftpError ftpInterface::downloadFile(QString sourceFileName,QString destinationFilename) { eftpError result; addToLog("FTP downloadFile",LOGFTP); QFile *destFn; destFn=new QFile(destinationFilename); if(!destFn->open(QIODevice::WriteOnly)) { addToLog(QString("FTP unable to open destinationFilename %1").arg(destinationFilename),LOGFTP); return FTPNAMEERROR; } if (sourceFileName.isNull() ) return FTPNAMEERROR; result=doConnect(); if(result!=FTPOK) return result; ftpDone=false; ftp->get( sourceFileName, destFn,QFtp::Binary); addToLog(QString("FTP get sourcefile %1 destination %2").arg(sourceFileName).arg(destFn->fileName()),LOGFTP); while(!ftpDone) { if(aborting) return FTPCANCELED; qApp->processEvents(); } if(!ftpCommandSuccess) return FTPERROR; addToLog(QString("FTP file: %1 bytes: %2").arg(destinationFilename).arg(QFile(destinationFilename).size()),LOGFTP); return FTPOK; } void ftpInterface::connectToHost() { destroy(); ftp->connectToHost(host,port); ftp->login( user, passwd ); if(!directory.isEmpty()) changePath(directory); // qDebug() << QString("connecting to host %1,%2,%3,%4").arg(host).arg(port).arg(user).arg(passwd); } // This slot is connected to the QComboBox::activated() signal of the // remotePath. void ftpInterface::changePath( const QString &newPath ) { ftp->cd( newPath ); } /**************************************************************************** ** ** Slots connected to signals of the QFtp class ** *****************************************************************************/ void ftpInterface::ftp_commandStarted(int id) { addToLog(QString("FTP commandStarted id:%1, %2").arg(id).arg(ftp->currentCommand()),LOGFTP); if ( ftp->currentCommand() == QFtp::List ) { } } void ftpInterface::ftp_commandFinished(int id,bool err) { QIODevice *p; slotProgress(0,0); addToLog(QString("FTP commandFinished id:%1, error:%2").arg(id).arg(err),LOGFTP); if(err) { addToLog(QString("FTP error:%1").arg(ftp->errorString()),LOGFTP); ftpCommandSuccess=false; } else { ftpCommandSuccess=true; } p=ftp->currentDevice(); if(p) { delete ftp->currentDevice(); } } void ftpInterface::ftp_done( bool error ) { if ( error ) { // QMessageBox::critical( 0, tr("FTP Error"), ftp->errorString() ); // If we are connected, but not logged in, it is not meaningful to stay // connected to the server since the error is a really fatal one (login // failed). if(!isLoggedIn()) { addToLog("FTP done: error and not logged in-> disconnecting",LOGFTP); destroy(); ftpDone=true; return; } addToLog("FTP done: error",LOGFTP); } else { addToLog("FTP done: no error",LOGFTP); } ftpDone=true; } bool ftpInterface::isLoggedIn() { return ftp->state() == QFtp::LoggedIn; } bool ftpInterface::isUnconnected() { return ftp->state() == QFtp::Unconnected; } void ftpInterface::ftp_stateChanged( int ) { dumpState(); } void ftpInterface::dumpState() { switch (ftp->state() ) { case QFtp::Unconnected: addToLog(QString("FTPss Unconnected name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; case QFtp::HostLookup: addToLog(QString("FTPss Host lookup name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; case QFtp::Connecting: addToLog(QString("FTPss Connecting name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; case QFtp::Connected: addToLog(QString("FTPss Connected name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; case QFtp::LoggedIn: addToLog(QString("FTPss Logged In name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; case QFtp::Closing: addToLog(QString("FTPss Closing name:=%1 :host=%2").arg(name).arg(host),LOGFTP); break; default: addToLog(QString("FTPss uknown %1 name:=%2 host=%3").arg(ftp->state()).arg(name).arg(host),LOGFTP); break; } } void ftpInterface::ftp_listInfo( const QUrlInfo &) { } void ftpInterface::ftp_rawCommandReply( int code, const QString &text ) { addToLog(QString("FTP Raw Command Reply: code=%1 , %2").arg(code).arg(text),LOGFTP); } void ftpInterface::slotAbort() { aborting=true; ftp->abort(); } void ftpInterface::slotProgress(qint64 bytes ,qint64 total) { displayProgressFTPEvent *stmb; stmb=new displayProgressFTPEvent(bytes,total); QApplication::postEvent( dispatcherPtr, stmb ); // Qt will delete it when done } eftpError ftpInterface::uploadToRXServer(QString fn) { int i; eftpError result; addToLog("FTP show state",LOGFTP); ftp_stateChanged(ftp->state()); result=doConnect(); if(result!=FTPOK) return result; if(ftpSaveFormat==FTPIM) { ftpDone=false; ftp->remove(QString("image%1").arg(ftpNumImages)); while(!ftpDone) { qApp->processEvents(); } for(i=0;irename(QString("image%1").arg(ftpNumImages-1-i),QString("image%1").arg(ftpNumImages-i)); while(!ftpDone) { qApp->processEvents(); } addToLog("FTP done: in rename",LOGFTP); } ftpDone=false; return uploadFile(fn,"image1",false); } else { ftpDone=false; return uploadFile(fn,"",false); } } qsstv_8.2.12/qsstv/utils/ftp.h000664 001750 001750 00000005754 12440612574 016270 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2004 by Johan Maes * * on4qz@telenet.be * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef FTPINTERFACE_H #define FTPINTERFACE_H #include "qglobal.h" # if(QT_VERSION > QT_VERSION_CHECK(5, 0, 0)) #include "qftp.h" # else #include #endif #include #include #include enum eftpError {FTPOK,FTPERROR,FTPNAMEERROR,FTPCANCELED,FTPTIMEOUT}; class ftpInterface: public QObject { Q_OBJECT public: ftpInterface(QString id); ~ftpInterface(); void setupConnection(QString tHost,int tPort,QString tUser,QString tPasswd,QString tDirectory) { host=tHost; user=tUser; passwd=tPasswd; directory=tDirectory; port=tPort; } eftpError uploadFile(QString fileName, QString fixFilename, bool reconnect); eftpError downloadFile(QString sourceFileName,QString destinationFilename); bool isUnconnected(); bool isLoggedIn(); eftpError uploadToRXServer(QString fn); QString getLastError() {return ftp->errorString();} private slots: void ftp_commandStarted(int); void ftp_commandFinished(int,bool); void ftp_done(bool); void ftp_stateChanged(int); void ftp_listInfo(const QUrlInfo &); void ftp_rawCommandReply(int, const QString &); void slotAbort(); void slotProgress(qint64 total, qint64 bytes); private: void connectToHost(); void changePath( const QString &newPath ); eftpError doConnect(); void destroy(); void init(); QFtp *ftp; QFile *sourceFn; bool ftpDone; bool aborting; QString host; QString user; QString passwd; QString directory; int port; bool ftpCommandSuccess; QTimer tim; void dumpState(); QString name; }; extern ftpInterface *ftpIntf; #endif qsstv_8.2.12/qsstv/utils/hybridcrypt.cpp000664 001750 001750 00000013574 12440612574 020374 0ustar00jomajoma000000 000000 #include "hybridcrypt.h" #include #include "configparams.h" #include "QResource" hybridCrypt::hybridCrypt() { const uchar *d; QByteArray ba; QResource qrc(":/icons/mgc.raw"); QResource qrc2(":/icons/mgc2.raw"); d=qrc.data(); key1=d[32]-0x36; key2=d[33]-0x72; key3=d[34]-0xd8; key4=d[35]-0xFE; ba.clear(); ba.append((const char *)qrc2.data()); deCrypt(&ba); vhcFtpRemoteHost=hcFtpRemoteHost; vhcFtpLogin=hcFtpLogin; vhcFtpPassword=hcFtpPassword; vhcFtpRemoteDirectory=hcFtpRemoteDirectory; vhcFtpRemoteDirectory=""; vhcFtpPort=21; // at this moment no port can by specified hcFtpPort=vhcFtpPort; if((enableSpecialServer) && (!hybridFtpRemoteHost.isEmpty())) { hcFtpRemoteHost=hybridFtpRemoteHost; hcFtpLogin=hybridFtpLogin; hcFtpPassword=hybridFtpPassword; hcFtpRemoteDirectory=hybridFtpRemoteDirectory; //always relatif to hybridFtpHybridFilesDirectory } else { hcFtpRemoteHost=vhcFtpRemoteHost; hcFtpLogin=vhcFtpLogin; hcFtpPassword=vhcFtpPassword; hcFtpRemoteDirectory=vhcFtpRemoteDirectory; } } bool hybridCrypt::enCrypt(QByteArray *ba) { int i; QString string,hstr; hstr=QChar(63)+hcFtpRemoteHost+QChar(34)+hcFtpLogin+QChar(60)+hcFtpPassword+QChar(62)+hcFtpRemoteDirectory+QChar(58); hcFtpRemoteHost.clear(); hcFtpLogin.clear(); hcFtpPassword.clear(); hcFtpRemoteDirectory.clear(); reverseString(hstr); for(i=0;iclear(); while(string.length()%4!=0) { string.append(QChar(0)); } do { num1=string.at(sc++).toLatin1(); num2=string.at(sc++).toLatin1(); num3=string.at(sc++).toLatin1(); num4=string.at(sc++).toLatin1(); res1=num1*key1; bufI=num2*key3; res1=res1+bufI; res2= num1 * key2; bufI= num2 * key4; res2= res2 + bufI; res3= num3 * key1; bufI= num4 * key3; res3= res3 + bufI; res4= num3 * key2; bufI= num4 * key4; res4= res4 + bufI; for(bufI=0;bufI<4;bufI++) { switch(bufI) { case 0: r1=res1>>8; r2=res1&0xff; break; case 1: r1=res2>>8; r2=res2&0xff; break; case 2: r1=res3>>8; r2=res3&0xff; break; case 3: r1=res4>>8; r2=res4&0xff; break; } if((r1==0) &&(r2==0)) { r1=0xFF; r2=0xFF; } if(r1==0xFF) r1=0xFE; if(r2==0) { r2=r1; r1=0xFD; } encStr.append(r1); encStr.append(r2); } } while(scappend(encStr); ba->append("\r\n"); // QFile tf("mgc2.raw"); // if(!tf.open(QIODevice::WriteOnly)) // { // return false; // } // tf.write(*ba); // tf.close(); return true; } bool hybridCrypt::deCrypt(QByteArray *ba) { QString result; int baSize; bool ok; int charCount=0; QString tempStr="0x00"; short int bufI, bufI2, divzr, num1, num2, num3, num4, res1, res2, res3, res4; unsigned char r1,r2; result=""; res1=res2=res3=res4=0; divzr=key1*key4; bufI2=key3*key2; divzr-=bufI2; if(divzr==0) return false; baSize=ba->size(); if(baSize!=3) { baSize=ba->size()-2; //drop /r/n if(baSize%2!=0) return false; } if(baSize<20) { hcFtpRemoteHost=vhcFtpRemoteHost; hcFtpLogin=vhcFtpLogin; hcFtpPassword=vhcFtpPassword; hcFtpRemoteDirectory=vhcFtpRemoteDirectory; return true; } do { for(bufI=0;bufI<4;bufI++,charCount+=2) { r1=ba->at(charCount); r2=ba->at(charCount+1); if(r1==0xFF) { r1=r2=0; } if(r1==0xFE) { r1=0; } if(r1==0xFD) { r1=r2; r2=0; } switch(bufI) { case 0: res1=r1*256+r2; break; case 1: res2=r1*256+r2; break; case 2: res3=r1*256+r2; break; case 3: res4=r1*256+r2; break; } } bufI= res1 * key4; bufI2= res2 * key3; num1= bufI - bufI2; num1= num1 / divzr; bufI= res2 * key1; bufI2= res1 * key2; num2= bufI - bufI2; num2 = num2 / divzr; bufI= res3 * key4; bufI2= res4 * key3; num3= bufI - bufI2; num3= num3 / divzr; bufI= res4 * key1; bufI2= res3 * key2; num4= bufI - bufI2; num4= num4 / divzr; tempStr[2]=QChar(num1); tempStr[3]=QChar(num2); result.append(QChar(tempStr.toInt(&ok,16))); tempStr[2]=QChar(num3); tempStr[3]=QChar(num4); result.append(QChar(tempStr.toInt(&ok,16))); } while(charCount #include class hybridCrypt { public: hybridCrypt(); bool enCrypt(QByteArray *ba); bool deCrypt(QByteArray *ba); QString host() {return hcFtpRemoteHost;} QString user() {return hcFtpLogin;} QString passwd(){return hcFtpPassword;} QString dir() {return hcFtpRemoteDirectory;} int port() {return hcFtpPort;} private: QString hcFtpRemoteHost; QString hcFtpLogin; QString hcFtpPassword; QString hcFtpRemoteDirectory; int hcFtpPort; QString vhcFtpRemoteHost; QString vhcFtpLogin; QString vhcFtpPassword; QString vhcFtpRemoteDirectory; int vhcFtpPort; short int key1,key2,key3,key4; void reverseString(QString & s); bool getParam(QString result); QString charToHex(QChar c); }; #endif // HYBRIDCRYPT_H qsstv_8.2.12/qsstv/utils/logging.cpp000664 001750 001750 00000016021 12440612574 017445 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "logging.h" #include #include #include #include #include #include "ui_loggingform.h" #include "qsstvdefs.h" /*! class logFile \brief utility class to enable logging facilities Create an instance of this class giving the basename of the logfile. By default the log is disabled. call setEnabled(true) to enable logging */ //logFile logfile; logFile::logFile() { #ifndef QT_NO_DEBUG lf=new QFile; auxFile=new QFile; #endif logCount=0; savedLogEntry=""; savedPosMask=0; mask.set(); //all masks set:this will enable all logfile messages } /*! creates logfile with name=logname, and opens it for writing */ #ifndef QT_NO_DEBUG bool logFile::open(QString logname) { lf->setFileName(QDir::homePath()+"/"+logname); auxFile->setFileName(QDir::homePath()+"/aux_"+logname); return reopen(); } #else bool logFile::open(QString ) { return true;} #endif /*! closes the logfile */ logFile::~logFile() { close(); } void logFile::close() { #ifndef QT_NO_DEBUG qDebug() << "closing logfile"; add("End of logfile",LOGALL); add("....,",LOGALL); delete ts; delete auxTs; lf->close(); auxFile->close(); #endif } void logFile::reset() { close(); reopen(); } bool logFile::reopen() { #ifndef QT_NO_DEBUG setEnabled(false); QFileInfo finf(*lf); QFileInfo finfaux(*auxFile); qDebug() << "opening logfile--: " << finf.absoluteFilePath(); if(!lf->open(QIODevice::WriteOnly)) { qDebug() << "logfile creation failed"; return false; } qDebug() << "opening logfile: " << finfaux.absoluteFilePath(); if(!auxFile->open(QIODevice::WriteOnly)) { qDebug() << "auxillary file creation failed"; lf->close(); return false; } setEnabled(true); ts= new QTextStream( lf ); auxTs= new QTextStream( auxFile); savedLogEntry=""; logCount=0; timer.start(); *ts<< "Time \tElapsed \t Level \t Count\t Info\n"; ts->flush(); #endif return true; } /*! \brief Writes to the logfile The output is flushed after every access.Identical messages are only logged once. The count indicates the number of duplicate messages. */ #ifndef QT_NO_DEBUG void logFile::add(QString t,short unsigned int posMask) { if(!(posMask==LOGALL)) // always show messages with DBALL { if (!mask.test(posMask)) return; } if (!enabled) return; mutex.lock(); if(logCount==0) { logCount=1; savedLogEntry=t; timer.restart(); tmp=QString("%1 ").arg(timer.elapsed(),5); tmp2=timer.currentTime().toString("HH:mm:ss:zzz "); savedPosMask=posMask; } if ((t==savedLogEntry) &&(deduplicate)) logCount++; else { if(!deduplicate) { savedLogEntry=t; tmp=QString("%1 ").arg(timer.elapsed(),5); tmp2 = timer.currentTime().toString("HH:mm:ss:zzz "); savedPosMask=posMask; } if(savedPosMask==LOGALL) { *ts << tmp2<< "\t" << tmp << "\tALL \t" << logCount << "\t" << savedLogEntry <<"\n"; } else { *ts << tmp2<< "\t" << tmp << "\t" << levelStr[savedPosMask] <<"\t" << logCount << "\t" << savedLogEntry <<"\n"; } tmp=QString("%1 ").arg(timer.elapsed(),5); tmp2 = timer.currentTime().toString("HH:mm:ss:zzz "); timer.restart();; savedLogEntry=t; savedPosMask=posMask; logCount=1; } ts->flush(); lf->flush(); mutex.unlock(); } #else void logFile::add(QString ,short unsigned int) {} #endif void logFile::add(const char *fileName,const char *functionName, int line, QString t,short unsigned int posMask) { QString s; s=QString(fileName)+":"+QString(functionName)+":"+QString::number(line)+" "+ t; add(s,posMask); } #ifndef QT_NO_DEBUG void logFile::addToAux(QString t) { if (!enabled) return; mutex.lock(); *auxTs << t << "\n"; auxTs->flush(); auxFile->flush(); mutex.unlock(); } #else void logFile::addToAux(QString ){} #endif /*! if enable=true logging wil be performed \return previous logging state (true if logging was enabled) */ bool logFile::setEnabled(bool enable) { bool t=enabled; enabled=enable; return t; } void logFile::setLogMask(std::bitset logMask) { mask=logMask; } void logFile::maskSelect(QWidget *wPtr) { int i,j; QDialog lf(wPtr); QCheckBox *cb; // QTableWidgetItem *item; Ui::loggingForm ui; ui.setupUi(&lf); ui.maskTableWidget->setRowCount((NUMDEBUGLEVELS+1)/2); for(i=0;irowCount();i++) { for(j=0;(j<2)&(i*2+jsetChecked(mask.test(i*2+j)); ui.maskTableWidget->setCellWidget(i,j,cb); } } ui.deduplicateCheckBox->setChecked(deduplicate); if(lf.exec()==QDialog::Accepted) { for(i=0;irowCount();i++) { for(j=0;(j<2)&(i*2+jcellWidget(i,j); mask.set(i*2+j,cb->isChecked()); } } deduplicate=ui.deduplicateCheckBox->isChecked(); } } void logFile::readSettings(QSettings &qSettings) { qSettings.beginGroup ("logging"); mask=qSettings.value("mask",1).toUInt(); deduplicate=qSettings.value("deduplicate",true).toBool(); qSettings.endGroup(); } void logFile::writeSettings(QSettings &qSettings) { qSettings.beginGroup ("logging"); qSettings.setValue ( "mask", (uint)mask.to_ulong()); qSettings.setValue ( "deduplicate", deduplicate); qSettings.endGroup(); } qsstv_8.2.12/qsstv/utils/logging.h000664 001750 001750 00000002451 12440612574 017114 0ustar00jomajoma000000 000000 #ifndef LOGGING_H #define LOGGING_H #include #include #include #include #include #include #include "loggingparams.h" #ifndef QT_NO_DEBUG #define addToLog(x,y) logfile->add(__FILE__,__func__,__LINE__,x,y) #else #define addToLog(x,y) logfile->dummyAdd(x,y) // to avoid parameter not used warnings #endif class QTextStream; class logFile { public: logFile(); logFile(QString logname); ~logFile(); bool open(QString logname); void add(QString t,short unsigned int posMask); void add(const char *fileName,const char *functionName, int line, QString t,short unsigned int posMask); void dummyAdd(QString,int) {} void addToAux(QString t); bool setEnabled(bool e); void setLogMask(std::bitset logMask); void maskSelect(QWidget *wPtr=0); void readSettings(QSettings &qSettings); void writeSettings(QSettings &qSettings); void close(); void reset(); bool reopen(); private: QString tmp; QString tmp2; QFile *lf; QTextStream *ts; QFile *auxFile; QTextStream *auxTs; bool enabled; QMutex mutex; QTime timer; std::bitset mask; QString savedLogEntry; int logCount; int savedPosMask; bool deduplicate; }; #endif qsstv_8.2.12/qsstv/utils/loggingform.ui000664 001750 001750 00000005011 12440612574 020161 0ustar00jomajoma000000 000000 loggingForm Qt::WindowModal 0 0 449 459 Logging Selector 10 2 false 200 false 200 false Deduplicate Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() loggingForm accept() 248 254 157 274 buttonBox rejected() loggingForm reject() 316 260 286 274 qsstv_8.2.12/qsstv/utils/loggingparams.cpp000664 001750 001750 00000003730 12450753733 020660 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "loggingparams.h" QString levelStr[NUMDEBUGLEVELS]= { "GALLERY ", "PARAMS ", "FFT ", "WAVIO ", "SYNTHES ", "DISPATC ", "SOUNDIO ", "RXFUNC ", "TXFUNC ", "SYNCPRC1", "SYNCPRC2", "SLANTAD ", "MODES ", "FTP ", "IMAGE ", "SCOPE ", "CAM ", "RX MAIN ", "TX MAIN ", "EDITOR ", "RIGCTRL ", "DRMDEMOD", "DRMRXSRC", "DRMMOT ", "DRMTX ", "DRMTXMOT", "DRMTXCOD", "DRMTXAAA", "XMLRPC ", "PERFORM " }; qsstv_8.2.12/qsstv/utils/loggingparams.h000664 001750 001750 00000001632 12450753733 020324 0ustar00jomajoma000000 000000 #ifndef LOGGINGPARAMS_H #define LOGGINGPARAMS_H #include //debuglevels #define LOGALL 99 #define LOGGALLERY 0 #define LOGPARAM 1 #define LOGFFT 2 #define LOGWAVIO 3 #define LOGSYNTHES 4 #define LOGDISPAT 5 #define LOGSOUND 6 #define LOGRXFUNC 7 #define LOGTXFUNC 8 #define LOGSYNC1 9 #define LOGSYNC2 10 #define LOGSLANT 11 #define LOGMODES 12 #define LOGFTP 13 #define LOGIMAG 14 #define LOGSCOPE 15 #define LOGCAM 16 #define LOGRXMAIN 17 #define LOGTXMAIN 18 #define LOGEDIT 19 #define LOGRIGCTRL 20 #define LOGDRMDEMOD 21 #define LOGDRMSRC 22 #define LOGDRMMOT 23 #define LOGDRMTX 24 #define LOGDRMTXMOT 25 #define LOGDRMTXCOD 26 #define LOGDRMTXAAA 27 #define LOGXML 28 #define LOGPERFORM 29 #define NUMDEBUGLEVELS (LOGPERFORM+1) extern QString levelStr[NUMDEBUGLEVELS]; #endif // LOGGINGPARAMS_H qsstv_8.2.12/qsstv/utils/macroexpansion.cpp000664 001750 001750 00000001713 12440612574 021047 0ustar00jomajoma000000 000000 #include "macroexpansion.h" macroExpansion::macroExpansion() { convertList.clear(); } QString macroExpansion::convert(QString txt) { int i,j; bool special=false; QChar c; QString convertedText; { for (i=0;i #include struct sconvert { QChar tag; QString replacement; }; class macroExpansion { public: macroExpansion(); QString convert(QString txt); void addConversion(QChar tag,QString value); void clear() {convertList.clear();} private: QList convertList; }; #endif // MACROEXPANSION_H qsstv_8.2.12/qsstv/utils/qftp.h000664 001750 001750 00000011234 12440612574 016437 0ustar00jomajoma000000 000000 /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QFTP_H #define QFTP_H #include #include "qurlinfo.h" #include QT_BEGIN_HEADER class QFtpPrivate; class QFtp : public QObject { Q_OBJECT public: explicit QFtp(QObject *parent = 0); virtual ~QFtp(); enum State { Unconnected, HostLookup, Connecting, Connected, LoggedIn, Closing }; enum Error { NoError, UnknownError, HostNotFound, ConnectionRefused, NotConnected }; enum Command { None, SetTransferMode, SetProxy, ConnectToHost, Login, Close, List, Cd, Get, Put, Remove, Mkdir, Rmdir, Rename, RawCommand }; enum TransferMode { Active, Passive }; enum TransferType { Binary, Ascii }; int setProxy(const QString &host, quint16 port); int connectToHost(const QString &host, quint16 port=21); int login(const QString &user = QString(), const QString &password = QString()); int close(); int setTransferMode(TransferMode mode); int list(const QString &dir = QString()); int cd(const QString &dir); int get(const QString &file, QIODevice *dev=0, TransferType type = Binary); int put(const QByteArray &data, const QString &file, TransferType type = Binary); int put(QIODevice *dev, const QString &file, TransferType type = Binary); int remove(const QString &file); int mkdir(const QString &dir); int rmdir(const QString &dir); int rename(const QString &oldname, const QString &newname); int rawCommand(const QString &command); qint64 bytesAvailable() const; qint64 read(char *data, qint64 maxlen); QByteArray readAll(); int currentId() const; QIODevice* currentDevice() const; Command currentCommand() const; bool hasPendingCommands() const; void clearPendingCommands(); State state() const; Error error() const; QString errorString() const; public Q_SLOTS: void abort(); Q_SIGNALS: void stateChanged(int); void listInfo(const QUrlInfo&); void readyRead(); void dataTransferProgress(qint64, qint64); void rawCommandReply(int, const QString&); void commandStarted(int); void commandFinished(int, bool); void done(bool); private: Q_DISABLE_COPY(QFtp) QScopedPointer d; Q_PRIVATE_SLOT(d, void _q_startNextCommand()) Q_PRIVATE_SLOT(d, void _q_piFinished(const QString&)) Q_PRIVATE_SLOT(d, void _q_piError(int, const QString&)) Q_PRIVATE_SLOT(d, void _q_piConnectState(int)) Q_PRIVATE_SLOT(d, void _q_piFtpReply(int, const QString&)) }; QT_END_HEADER #endif // QFTP_H qsstv_8.2.12/qsstv/utils/qjp2io.cpp000664 001750 001750 00000027655 12440612574 017242 0ustar00jomajoma000000 000000 /***************************************************************************** JPEG 2000 support for Qt based on JasPer lib Copyright (c) 2003 by Dmitry V. Fedorov This wrapper is in it's initial state, it's quite slow now because of something, so soon will fix this performance probs... IMPLEMENTATION Programmer: Dima V. Fedorov History: 13/06/2003 17:02 - First creation Ver : 1 *****************************************************************************/ #include "qsstvdefs.h" #include #include #include #include #include #include #include #include "qjp2io.h" QImage readJP2Image(QString fileName) { // pass on file name if known QFile f(fileName); long y; jas_image_t *jp2_image; jas_matrix_t *pixels[4]; jas_stream_t *jp2_stream; int format; register unsigned long i, x; int components[4]; unsigned long number_components; unsigned int channel_scale[4], maximum_component_depth=8; int_fast32_t height = 0; int_fast32_t width = 0; uchar *px; uchar pixel[4]; // Initialize JPEG 2000 API. jas_init(); // always returns 0 QByteArray ba = fileName.toLocal8Bit(); const char *fn = ba.data(); // qDebug() << "fn:" << fn; if ( !(jp2_stream = jas_stream_fopen(fn, "rb")) ) return QImage(); if ((format = jas_image_getfmt(jp2_stream)) < 0) { return QImage(); // Unknown format } jp2_image = jas_image_decode(jp2_stream, format, 0); if (jp2_image == (jas_image_t *) NULL) { (void) jas_stream_close(jp2_stream); return QImage(); //UnableToDecodeImageFile } switch (jas_clrspc_fam(jas_image_clrspc(jp2_image))) { case JAS_CLRSPC_FAM_RGB: { components[0]=jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); components[1]=jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); components[2]=jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0)) { (void) jas_stream_close(jp2_stream); jas_image_destroy(jp2_image); return QImage(); //MissingImageChannel } number_components=3; components[3]=jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); if (components[3] > 0) { //image->matte=True; // dima - what a hell is this??? number_components++; } break; } case JAS_CLRSPC_FAM_GRAY: { components[0]=jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); if (components[0] < 0) { (void) jas_stream_close(jp2_stream); jas_image_destroy(jp2_image); return QImage(); //MissingImageChannel } number_components=1; break; } case JAS_CLRSPC_FAM_YCBCR: default: { (void) jas_stream_close(jp2_stream); jas_image_destroy(jp2_image); return QImage(); //ColorspaceModelIsNotSupported } } //------------------------------------------------------------------- // Now create the QImage //------------------------------------------------------------------- height = jas_image_height(jp2_image); width = jas_image_width(jp2_image); // test for components geometry for (i=0; i < (ulong) number_components; i++) { if ((jas_image_cmptwidth(jp2_image,components[i]) != width) || (jas_image_cmptheight(jp2_image,components[i]) != height) || (jas_image_cmpttlx(jp2_image,components[i]) != 0) || (jas_image_cmpttly(jp2_image,components[i]) != 0) || (jas_image_cmpthstep(jp2_image,components[i]) != 1) || (jas_image_cmptvstep(jp2_image,components[i]) != 1) || (jas_image_cmptsgnd(jp2_image,components[i]) != false)) { (void) jas_stream_close(jp2_stream); jas_image_destroy(jp2_image); return QImage(); // IrregularChannelGeometryNotSupported } } // now get the max component depth for (i=0; i < (ulong) number_components; i++) { maximum_component_depth = max((unsigned int) jas_image_cmptprec(jp2_image,components[i]), maximum_component_depth); pixels[i] = jas_matrix_create(1, (unsigned int) width); if (pixels[i] == (jas_matrix_t *) NULL) { jas_image_destroy(jp2_image); return QImage(); //MemoryAllocationFailed } } // we should set it here, since QT works with only 8bit channels, done for now /* if (maximum_component_depth <= 8) image->depth=Min(QuantumDepth,8); else image->depth=Min(QuantumDepth,16); */ if (number_components == 1) { return QImage(); } QImage image(width, height, QImage::Format_RGB32); if(image.isNull()) return QImage(); for (i=0; i < (ulong) number_components; i++) { channel_scale[i]=1; if (jas_image_cmptprec(jp2_image,components[i]) < 16) channel_scale[i]= (1 << (16-jas_image_cmptprec(jp2_image,components[i])))+1; } //------------------------------------------------------------------- // Now copy image data //------------------------------------------------------------------- for (y=0; y < (long) height; y++) { for (i=0; i < number_components; i++) jas_image_readcmpt(jp2_image, components[i], 0, y, width, 1, pixels[i]); px = image.scanLine(y); switch (number_components) { case 1: // GRAY SCALE IMAGE { for (x=0; x < (ulong) width; x++) { px[x] = (unsigned char) jas_matrix_getv(pixels[0],x)*channel_scale[0]; } break; } case 3: // RGB { for (x=0; x < (ulong) width; x++) { QRgb *row = (QRgb*) px; pixel[0] = (jas_matrix_getv(pixels[0],x)*channel_scale[0]); pixel[1] = (jas_matrix_getv(pixels[1],x)*channel_scale[1]); pixel[2] = (jas_matrix_getv(pixels[2],x)*channel_scale[2]); row[x] = qRgb(pixel[0], pixel[1], pixel[2] ); } break; } case 4: // RGBA { for (x=0; x < (ulong) width; x++) { QRgb *row = (QRgb*) px; pixel[0] = (jas_matrix_getv(pixels[0],x)*channel_scale[0]); pixel[1] = (jas_matrix_getv(pixels[1],x)*channel_scale[1]); pixel[2] = (jas_matrix_getv(pixels[2],x)*channel_scale[2]); pixel[3] = (jas_matrix_getv(pixels[3],x)*channel_scale[3]); row[x] = qRgba(pixel[0], pixel[1], pixel[2], pixel[3]); } break; } } } // clean up all mess in memory (void) jas_stream_close(jp2_stream); jas_image_destroy(jp2_image); for (i=0; i < (ulong) number_components; i++) jas_matrix_destroy(pixels[i]); jas_init(); return image; } //! QImageIO write handler for TIFF files. // bool writeJP2Image(QImage img, QString fileName,double ratio) { QFile f(fileName); char options[MaxTextExtent]; double rate; int format; ulong y; jas_image_cmptparm_t component_info; jas_image_t *jp2_image; jas_matrix_t *pixels[4]; jas_stream_t *jp2_stream; register unsigned long i, x; int status; unsigned long number_components; uchar *px; // Intialize JasPer JPEG 2000 API jas_init(); QByteArray ba = fileName.toLocal8Bit(); const char *fn = ba.data(); // qDebug() << "fn:" << fn; if ( !(jp2_stream = jas_stream_fopen(fn, "wb")) ) return false; if (img.depth() == 8) number_components = 1; else number_components = 4; jp2_image=jas_image_create0(); if (jp2_image == (jas_image_t *) NULL) return false; //UnableToCreateImage for (i=0; i < (ulong) number_components; i++) { (void) memset((void *) &component_info,0,sizeof(jas_image_cmptparm_t)); component_info.tlx=0; component_info.tly=0; component_info.hstep=1; component_info.vstep=1; component_info.width=(unsigned int) img.width(); component_info.height=(unsigned int) img.height(); component_info.prec=(unsigned int) 8;//img.depth() <= 8 ? 8 : 16; component_info.sgnd=false; if (jas_image_addcmpt(jp2_image,i,&component_info)) { jas_image_destroy(jp2_image); return false; //UnableToCreateImageComponent } } if (number_components == 1) { // sRGB Grayscale jas_image_setclrspc(jp2_image, JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jp2_image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else { // sRGB jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jp2_image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jp2_image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jp2_image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); if (number_components == 4 ) jas_image_setcmpttype(jp2_image, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } // Convert to JPEG 2000 pixels. for (i=0; i < (ulong) number_components; i++) { pixels[i] = jas_matrix_create(1, (unsigned int) img.width()); if (pixels[i] == (jas_matrix_t *) NULL) { for (x=0; x < i; x++) jas_matrix_destroy(pixels[x]); jas_image_destroy(jp2_image); return false; //MemoryAllocationFailed } } // now copy the data itself for (y=0; y < (ulong) img.height(); y++) { px = img.scanLine(y); for (x=0; x < (ulong) img.width(); x++) { if (number_components == 1) jas_matrix_setv(pixels[0], x, px[x] ); else { QRgb *row = (QRgb*) px; jas_matrix_setv(pixels[0], x, qRed(row[x]) ); jas_matrix_setv(pixels[1], x, qGreen(row[x]) ); jas_matrix_setv(pixels[2], x, qBlue(row[x]) ); if (number_components > 3) jas_matrix_setv(pixels[3], x, qAlpha(*(row+x)) ); } } for (i=0; i < (ulong) number_components; i++) jas_image_writecmpt(jp2_image, i, 0, y, img.width(), 1, pixels[i]); } // end of byte data copy rate=1; format = jas_image_fmtfromname(fileName.toLatin1().data()); double qrate=ratio; if (img.width()*img.height() > 2500) { double alpha, header_size, number_pixels, target_size; alpha=115-100; rate=100.0/(alpha*alpha); header_size=550.0; header_size+=(number_components-1)*142; number_pixels=(double) img.width()*img.height()*(img.depth()/8)*number_components; target_size=(number_pixels*rate)+header_size; rate=target_size/number_pixels; } if(rate>qrate) { rate=qrate; } sprintf(options, "rate=%g", rate); status = jas_image_encode(jp2_image, jp2_stream, format, options); // clean up our mess (void) jas_stream_close(jp2_stream); for (i=0; i < (ulong) number_components; i++) jas_matrix_destroy(pixels[i]); jas_image_destroy(jp2_image); if (status == -1) return false; //UnableToEncodeImageFile return true; } qsstv_8.2.12/qsstv/utils/qjp2io.h000664 001750 001750 00000002237 12440612574 016674 0ustar00jomajoma000000 000000 /***************************************************************************** JPEG 2000 support for Qt based on JasPer lib Copyright (c) 2003 by Dmitry V. Fedorov DEFINES Programmer: Dima V. Fedorov History: 13/06/2003 17:02 - First creation 17/12/2013 // changed by ON4QZ Ver : 1 *****************************************************************************/ #ifndef QJP2_H #define QJP2_H #include /* we better use jasper defined types #ifndef int8 typedef char int8; #endif #ifndef uint8 typedef unsigned char uint8; #endif #ifndef int16 typedef short int16; #endif #ifndef uint16 typedef unsigned short uint16; #endif #ifndef int32 typedef long int32; #endif #ifndef uint32 typedef unsigned long uint32; // sizeof (uint32) must == 4 #endif */ #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #define MaxTextExtent 2053 QImage readJP2Image(QString fileName); bool writeJP2Image(QImage im, QString fileName, double ratio); #endif qsstv_8.2.12/qsstv/utils/qurlinfo.cpp000664 001750 001750 00000040433 12440612574 017662 0ustar00jomajoma000000 000000 /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qurlinfo.h" #include "qurl.h" #include "qdir.h" #include QT_BEGIN_NAMESPACE class QUrlInfoPrivate { public: QUrlInfoPrivate() : permissions(0), size(0), isDir(false), isFile(true), isSymLink(false), isWritable(true), isReadable(true), isExecutable(false) {} QString name; int permissions; QString owner; QString group; qint64 size; QDateTime lastModified; QDateTime lastRead; bool isDir; bool isFile; bool isSymLink; bool isWritable; bool isReadable; bool isExecutable; }; /*! \class QUrlInfo \brief The QUrlInfo class stores information about URLs. \ingroup io \ingroup network \inmodule QtNetwork The information about a URL that can be retrieved includes name(), permissions(), owner(), group(), size(), lastModified(), lastRead(), isDir(), isFile(), isSymLink(), isWritable(), isReadable() and isExecutable(). You can create your own QUrlInfo objects passing in all the relevant information in the constructor, and you can modify a QUrlInfo; for each getter mentioned above there is an equivalent setter. Note that setting values does not affect the underlying resource that the QUrlInfo provides information about; for example if you call setWritable(true) on a read-only resource the only thing changed is the QUrlInfo object, not the resource. \sa QUrl, {FTP Example} */ /*! \enum QUrlInfo::PermissionSpec This enum is used by the permissions() function to report the permissions of a file. \value ReadOwner The file is readable by the owner of the file. \value WriteOwner The file is writable by the owner of the file. \value ExeOwner The file is executable by the owner of the file. \value ReadGroup The file is readable by the group. \value WriteGroup The file is writable by the group. \value ExeGroup The file is executable by the group. \value ReadOther The file is readable by anyone. \value WriteOther The file is writable by anyone. \value ExeOther The file is executable by anyone. */ /*! Constructs an invalid QUrlInfo object with default values. \sa isValid() */ QUrlInfo::QUrlInfo() { d = 0; } /*! Copy constructor, copies \a ui to this URL info object. */ QUrlInfo::QUrlInfo(const QUrlInfo &ui) { if (ui.d) { d = new QUrlInfoPrivate; *d = *ui.d; } else { d = 0; } } /*! Constructs a QUrlInfo object by specifying all the URL's information. The information that is passed is the \a name, file \a permissions, \a owner and \a group and the file's \a size. Also passed is the \a lastModified date/time and the \a lastRead date/time. Flags are also passed, specifically, \a isDir, \a isFile, \a isSymLink, \a isWritable, \a isReadable and \a isExecutable. */ QUrlInfo::QUrlInfo(const QString &name, int permissions, const QString &owner, const QString &group, qint64 size, const QDateTime &lastModified, const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, bool isWritable, bool isReadable, bool isExecutable) { d = new QUrlInfoPrivate; d->name = name; d->permissions = permissions; d->owner = owner; d->group = group; d->size = size; d->lastModified = lastModified; d->lastRead = lastRead; d->isDir = isDir; d->isFile = isFile; d->isSymLink = isSymLink; d->isWritable = isWritable; d->isReadable = isReadable; d->isExecutable = isExecutable; } /*! Constructs a QUrlInfo object by specifying all the URL's information. The information that is passed is the \a url, file \a permissions, \a owner and \a group and the file's \a size. Also passed is the \a lastModified date/time and the \a lastRead date/time. Flags are also passed, specifically, \a isDir, \a isFile, \a isSymLink, \a isWritable, \a isReadable and \a isExecutable. */ QUrlInfo::QUrlInfo(const QUrl &url, int permissions, const QString &owner, const QString &group, qint64 size, const QDateTime &lastModified, const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, bool isWritable, bool isReadable, bool isExecutable) { d = new QUrlInfoPrivate; d->name = QFileInfo(url.path()).fileName(); d->permissions = permissions; d->owner = owner; d->group = group; d->size = size; d->lastModified = lastModified; d->lastRead = lastRead; d->isDir = isDir; d->isFile = isFile; d->isSymLink = isSymLink; d->isWritable = isWritable; d->isReadable = isReadable; d->isExecutable = isExecutable; } /*! Sets the name of the URL to \a name. The name is the full text, for example, "http://qt.nokia.com/doc/qurlinfo.html". If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setName(const QString &name) { if (!d) d = new QUrlInfoPrivate; d->name = name; } /*! If \a b is true then the URL is set to be a directory; if \a b is false then the URL is set not to be a directory (which normally means it is a file). (Note that a URL can refer to both a file and a directory even though most file systems do not support this.) If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setDir(bool b) { if (!d) d = new QUrlInfoPrivate; d->isDir = b; } /*! If \a b is true then the URL is set to be a file; if \b is false then the URL is set not to be a file (which normally means it is a directory). (Note that a URL can refer to both a file and a directory even though most file systems do not support this.) If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setFile(bool b) { if (!d) d = new QUrlInfoPrivate; d->isFile = b; } /*! Specifies that the URL refers to a symbolic link if \a b is true and that it does not if \a b is false. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setSymLink(bool b) { if (!d) d = new QUrlInfoPrivate; d->isSymLink = b; } /*! Specifies that the URL is writable if \a b is true and not writable if \a b is false. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setWritable(bool b) { if (!d) d = new QUrlInfoPrivate; d->isWritable = b; } /*! Specifies that the URL is readable if \a b is true and not readable if \a b is false. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setReadable(bool b) { if (!d) d = new QUrlInfoPrivate; d->isReadable = b; } /*! Specifies that the owner of the URL is called \a s. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setOwner(const QString &s) { if (!d) d = new QUrlInfoPrivate; d->owner = s; } /*! Specifies that the owning group of the URL is called \a s. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setGroup(const QString &s) { if (!d) d = new QUrlInfoPrivate; d->group = s; } /*! Specifies the \a size of the URL. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setSize(qint64 size) { if (!d) d = new QUrlInfoPrivate; d->size = size; } /*! Specifies that the URL has access permissions \a p. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setPermissions(int p) { if (!d) d = new QUrlInfoPrivate; d->permissions = p; } /*! Specifies that the object the URL refers to was last modified at \a dt. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setLastModified(const QDateTime &dt) { if (!d) d = new QUrlInfoPrivate; d->lastModified = dt; } /*! \since 4.4 Specifies that the object the URL refers to was last read at \a dt. If you call this function for an invalid URL info, this function turns it into a valid one. \sa isValid() */ void QUrlInfo::setLastRead(const QDateTime &dt) { if (!d) d = new QUrlInfoPrivate; d->lastRead = dt; } /*! Destroys the URL info object. */ QUrlInfo::~QUrlInfo() { delete d; } /*! Assigns the values of \a ui to this QUrlInfo object. */ QUrlInfo &QUrlInfo::operator=(const QUrlInfo &ui) { if (ui.d) { if (!d) d= new QUrlInfoPrivate; *d = *ui.d; } else { delete d; d = 0; } return *this; } /*! Returns the file name of the URL. \sa isValid() */ QString QUrlInfo::name() const { if (!d) return QString(); return d->name; } /*! Returns the permissions of the URL. You can use the \c PermissionSpec flags to test for certain permissions. \sa isValid() */ int QUrlInfo::permissions() const { if (!d) return 0; return d->permissions; } /*! Returns the owner of the URL. \sa isValid() */ QString QUrlInfo::owner() const { if (!d) return QString(); return d->owner; } /*! Returns the group of the URL. \sa isValid() */ QString QUrlInfo::group() const { if (!d) return QString(); return d->group; } /*! Returns the size of the URL. \sa isValid() */ qint64 QUrlInfo::size() const { if (!d) return 0; return d->size; } /*! Returns the last modification date of the URL. \sa isValid() */ QDateTime QUrlInfo::lastModified() const { if (!d) return QDateTime(); return d->lastModified; } /*! Returns the date when the URL was last read. \sa isValid() */ QDateTime QUrlInfo::lastRead() const { if (!d) return QDateTime(); return d->lastRead; } /*! Returns true if the URL is a directory; otherwise returns false. \sa isValid() */ bool QUrlInfo::isDir() const { if (!d) return false; return d->isDir; } /*! Returns true if the URL is a file; otherwise returns false. \sa isValid() */ bool QUrlInfo::isFile() const { if (!d) return false; return d->isFile; } /*! Returns true if the URL is a symbolic link; otherwise returns false. \sa isValid() */ bool QUrlInfo::isSymLink() const { if (!d) return false; return d->isSymLink; } /*! Returns true if the URL is writable; otherwise returns false. \sa isValid() */ bool QUrlInfo::isWritable() const { if (!d) return false; return d->isWritable; } /*! Returns true if the URL is readable; otherwise returns false. \sa isValid() */ bool QUrlInfo::isReadable() const { if (!d) return false; return d->isReadable; } /*! Returns true if the URL is executable; otherwise returns false. \sa isValid() */ bool QUrlInfo::isExecutable() const { if (!d) return false; return d->isExecutable; } /*! Returns true if \a i1 is greater than \a i2; otherwise returns false. The objects are compared by the value, which is specified by \a sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size. */ bool QUrlInfo::greaterThan(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy) { switch (sortBy) { case QDir::Name: return i1.name() > i2.name(); case QDir::Time: return i1.lastModified() > i2.lastModified(); case QDir::Size: return i1.size() > i2.size(); default: return false; } } /*! Returns true if \a i1 is less than \a i2; otherwise returns false. The objects are compared by the value, which is specified by \a sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size. */ bool QUrlInfo::lessThan(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy) { return !greaterThan(i1, i2, sortBy); } /*! Returns true if \a i1 equals to \a i2; otherwise returns false. The objects are compared by the value, which is specified by \a sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size. */ bool QUrlInfo::equal(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy) { switch (sortBy) { case QDir::Name: return i1.name() == i2.name(); case QDir::Time: return i1.lastModified() == i2.lastModified(); case QDir::Size: return i1.size() == i2.size(); default: return false; } } /*! Returns true if this QUrlInfo is equal to \a other; otherwise returns false. \sa lessThan(), equal() */ bool QUrlInfo::operator==(const QUrlInfo &other) const { if (!d) return other.d == 0; if (!other.d) return false; return (d->name == other.d->name && d->permissions == other.d->permissions && d->owner == other.d->owner && d->group == other.d->group && d->size == other.d->size && d->lastModified == other.d->lastModified && d->lastRead == other.d->lastRead && d->isDir == other.d->isDir && d->isFile == other.d->isFile && d->isSymLink == other.d->isSymLink && d->isWritable == other.d->isWritable && d->isReadable == other.d->isReadable && d->isExecutable == other.d->isExecutable); } /*! \fn bool QUrlInfo::operator!=(const QUrlInfo &other) const \since 4.2 Returns true if this QUrlInfo is not equal to \a other; otherwise returns false. \sa lessThan(), equal() */ /*! Returns true if the URL info is valid; otherwise returns false. Valid means that the QUrlInfo contains real information. You should always check if the URL info is valid before relying on the values. */ bool QUrlInfo::isValid() const { return d != 0; } QT_END_NAMESPACE qsstv_8.2.12/qsstv/utils/qurlinfo.h000664 001750 001750 00000010725 12440612574 017330 0ustar00jomajoma000000 000000 /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QURLINFO_H #define QURLINFO_H #include #include #include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class QUrl; class QUrlInfoPrivate; class QUrlInfo { public: enum PermissionSpec { ReadOwner = 00400, WriteOwner = 00200, ExeOwner = 00100, ReadGroup = 00040, WriteGroup = 00020, ExeGroup = 00010, ReadOther = 00004, WriteOther = 00002, ExeOther = 00001 }; QUrlInfo(); QUrlInfo(const QUrlInfo &ui); QUrlInfo(const QString &name, int permissions, const QString &owner, const QString &group, qint64 size, const QDateTime &lastModified, const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, bool isWritable, bool isReadable, bool isExecutable); QUrlInfo(const QUrl &url, int permissions, const QString &owner, const QString &group, qint64 size, const QDateTime &lastModified, const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, bool isWritable, bool isReadable, bool isExecutable); QUrlInfo &operator=(const QUrlInfo &ui); virtual ~QUrlInfo(); virtual void setName(const QString &name); virtual void setDir(bool b); virtual void setFile(bool b); virtual void setSymLink(bool b); virtual void setOwner(const QString &s); virtual void setGroup(const QString &s); virtual void setSize(qint64 size); virtual void setWritable(bool b); virtual void setReadable(bool b); virtual void setPermissions(int p); virtual void setLastModified(const QDateTime &dt); void setLastRead(const QDateTime &dt); bool isValid() const; QString name() const; int permissions() const; QString owner() const; QString group() const; qint64 size() const; QDateTime lastModified() const; QDateTime lastRead() const; bool isDir() const; bool isFile() const; bool isSymLink() const; bool isWritable() const; bool isReadable() const; bool isExecutable() const; static bool greaterThan(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy); static bool lessThan(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy); static bool equal(const QUrlInfo &i1, const QUrlInfo &i2, int sortBy); bool operator==(const QUrlInfo &i) const; inline bool operator!=(const QUrlInfo &i) const { return !operator==(i); } private: QUrlInfoPrivate *d; }; QT_END_NAMESPACE QT_END_HEADER #endif // QURLINFO_H qsstv_8.2.12/qsstv/utils/reedsolomoncoder.cpp000664 001750 001750 00000022156 12437307434 021372 0ustar00jomajoma000000 000000 #include "reedsolomoncoder.h" #include #include #include "rs.h" #include "configparams.h" #define RSBSIZE 255 #define rse32 encode_rs #define rsd32 eras_dec_rs #define ENCODE 0 #define DECODE 1 QString rsTypeStr[RST4+1]= { "", "rs1", "rs2", "rs3", "rs4" }; reedSolomonCoder::reedSolomonCoder() { zeroPositions=NULL; newZeroPositions=NULL; } reedSolomonCoder::~reedSolomonCoder() { if(zeroPositions!=NULL) delete zeroPositions; if(newZeroPositions!=NULL) delete newZeroPositions; } void reedSolomonCoder::init() { ec_buf.clear(); /* pointer to encoding/decoding buffer */ tr_buf.clear(); /* pointer to transmit-buffer (fread/fwrite) */ bk_buf.clear(); /* pointer to backup-buffer for resync */ rs_bsize=0; rs_dsize=0; bep_size=0; sumOfFailures=0; uncorrectableFailures=0; if(zeroPositions!=NULL) delete zeroPositions; if(newZeroPositions!=NULL) delete newZeroPositions; } // if the extension is not rs1,rs2 or rs3 then newFilename is set to fn and return value is true bool reedSolomonCoder::decode(QByteArray &ba,QString fn,QString &newFileName,QByteArray &baFile,QString extension,QList &erasuresArray) { int i,j; int startOfSegment,row; // QByteArray *t; init(); // qDebug() << "size of ba" << ba.size(); origFileName=fn; fpin.setFileName(fn); if(extension=="rs1") fileType=RST1; else if(extension=="rs2") fileType=RST2; else if(extension=="rs3") fileType=RST3; else if(extension=="rs4") fileType=RST4; else { return false; } tr_buf=ba; got=tr_buf.size(); bep_size = got/RSBSIZE; if (got % RSBSIZE) { bep_size++ ; tr_buf=tr_buf.leftJustified(bep_size*RSBSIZE,'\0'); } // qDebug() << "got" << got << "bep_size" << bep_size; int rest=tr_buf.count()%64; if(rest!=0) { tr_buf=tr_buf.leftJustified(bep_size*RSBSIZE+(64-rest),'\0'); // qDebug() << "size of tr_buf extended" << tr_buf.count(); } ec_buf.resize(bep_size*RSBSIZE); bk_buf.resize(bep_size*RSBSIZE); rs_bsize=RSBSIZE; switch (fileType) { case RST1: rs_dsize=RSDSIZERS1; break; case RST2: rs_dsize=RSDSIZERS2; break; case RST3: rs_dsize=RSDSIZERS3; break; case RST4: rs_dsize=RSDSIZERS4; break; case RSTNONE: return false; } init_rs(rs_dsize); // setup erasure info numMissing=0; if(erasuresArray.count()>2) // we have erasure positions { totalSegments=erasuresArray.at(0); segmentLength=erasuresArray.at(1); numMissing=erasuresArray.count()-2; // qDebug() << "numMissing" << numMissing; if(zeroPositions) delete zeroPositions; if(newZeroPositions) delete newZeroPositions; zeroPositions=new int[segmentLength*(totalSegments+1)]; newZeroPositions=new int[256*bep_size]; // qDebug() << "newZeroPositions len" << (segmentLength*(totalSegments+1)); for(i=0;i<(segmentLength*totalSegments);i++) zeroPositions[i]=-1; } else { qDebug() << "no erasure info"; return false; } /* now label the erasures positions */ for (i= 0 ; i < numMissing; i++) { startOfSegment = erasuresArray.at(i+2)*segmentLength ; // +2 because of header in array for (j=0; j < segmentLength ; j++) { row = (startOfSegment +j ) / bep_size; /* if ( row < rs_dsize) */ zeroPositions[startOfSegment+j] = row; } } /* distribute version pa0mbo for the indexes */ int *pointzero=newZeroPositions; for (i=0; i < bep_size ; i++) { for (j=0; j < 255 ; j++) { *(pointzero++) = *(zeroPositions + j*bep_size + i); } } distribute((byte *)tr_buf.data(),(byte *)ec_buf.data(),bep_size,rs_bsize,DECODE); if(!decode_and_write()) { // fpout.close(); return false; } // fpin.close(); // fpout.close(); // tr_buf=ec_buf; if(uncorrectableFailures>0) return false; // if(fpout.open(QIODevice::ReadOnly)<=0) return false; // tr_buf=fpout.readAll(); if (bep_size != (((unsigned char) tr_buf[1]) + ((unsigned char) tr_buf[2])*256 )) { qDebug()<< "problems with bep_size coded in file"; qDebug() << "bep_size: " << bep_size <<" coded size: " << (((unsigned char) tr_buf[1]) + ((unsigned char) tr_buf[2])*256 ) ; qDebug() << "bep_sizeaa: " << bep_size <<" coded size: " << (((unsigned char) ba[1]) + ((unsigned char)ba[2])*256 ) ; return false; } coded_file_size = bep_size*rs_dsize - (int)tr_buf[0]; strncpy(coded_file_ext, tr_buf.data()+3,3); coded_file_ext[3]=0; QFileInfo fileInfo(origFileName); QString baseName=rxImagesPath+"/"+fileInfo.completeBaseName(); baseName.append("."); baseName.append(coded_file_ext); // qDebug() <<" new filename: " << baseName; // qDebug() << "tr_buf count before truncation: " << tr_buf.count(); tr_buf=tr_buf.right(tr_buf.count()-7); tr_buf=tr_buf.left(coded_file_size); // qDebug() << "coded_file_size: " << coded_file_size << "tr_buf count: " << tr_buf.count(); newFileName=baseName; // t=&tr_buf; baFile=tr_buf; // fpout.close(); if(uncorrectableFailures>0) { // qDebug() <<"uncorrectable failures:" << uncorrectableFailures; return false; } return true; } void reedSolomonCoder::distribute(byte *src, byte *dst, int rows, int cols, int reverse) { unsigned int i,j,rc,ri,rl; rc=rows*cols; ri=0; rl = reverse ? cols : rows; for(i=0;i using union gives problems with allignement { for(j=0;j<64 && i+j=rc) { ri-=rc-1; /* go around and add one. */ } } } } /* decode buffer and write to fpout */ bool reedSolomonCoder::decode_and_write() { register int i, j; int nr_erasures; int eras_pos[255]; tr_buf.clear(); for(i=0;i(rs_bsize-rs_dsize)) { // uncorrectableFailures++; // qDebug() << "ersasures too high" << nr_erasures; return false; } } } // qDebug()<< "block: " << i << "nr_erasures" << nr_erasures; if(nr_erasures>(rs_bsize-rs_dsize)) nr_erasures=rs_bsize-rs_dsize-1; int failure=rsd32(((byte *)ec_buf.data()+(i*rs_bsize)),eras_pos, nr_erasures); if (failure>0) { sumOfFailures+=failure; } else if (failure==-1) { uncorrectableFailures++; return false; } // qDebug() <<"block: " << i << "nr_erasures:" << nr_erasures << "failure corrected:" << failure << "uncorrectable failure" << uncorrectableFailures; // qDebug() << "ec_buf len" << ec_buf.count(); tr_buf.append(ec_buf.data()+i*rs_bsize,rs_dsize); // fpout.write(ec_buf.data()+i*rs_bsize,rs_dsize); // if(i==0) qDebug() << "rs write" <<((unsigned char) ec_buf[1]) << ((unsigned char)ec_buf[2]); } // qDebug() << "trsize" << tr_buf.count() << "bepsize" << bep_size << "rs_bsize" << rs_bsize << "rs_dsize" << rs_dsize; return true; } bool reedSolomonCoder::encode(QByteArray &ba,QString extension,eRSType rsType) { int i,j; unsigned char dataByte; QByteArray temp; tr_buf=ba; fileType=rsType; rs_bsize=RSBSIZE; switch (fileType) { case RST1: rs_dsize=RSDSIZERS1; break; case RST2: rs_dsize=RSDSIZERS2; break; case RST3: rs_dsize=RSDSIZERS3; break; case RST4: rs_dsize=RSDSIZERS4; break; case RSTNONE: return false; } init_rs(rs_dsize); got = tr_buf.size(); chunks = (got+7) / rs_dsize ; if (((got+7) % rs_dsize ) > 0) chunks++ ; bep_size=chunks; // ec_buf.resize(bep_size*RSBSIZE); ec_buf.clear(); bk_buf.resize(bep_size*RSBSIZE); dataByte = (unsigned char) ( rs_dsize - ( got % rs_dsize)) ; /* surplus in filelength */ ec_buf.append(dataByte); dataByte = (unsigned char) ( chunks % 256) ; ec_buf.append(dataByte); dataByte = (unsigned char) (chunks/256) ; ec_buf.append(dataByte); ec_buf.append(extension.toLatin1().at(0));newZeroPositions=NULL; ec_buf.append(extension.toLatin1().at(1)); ec_buf.append(extension.toLatin1().at(2)); dataByte=0; ec_buf.append(dataByte); ec_buf.append(tr_buf.left(rs_dsize-7)); ec_buf.resize(ec_buf.count()+RSBSIZE-rs_dsize); rse32(((byte *)ec_buf.data()),((byte *)ec_buf.data()+(rs_dsize))); for (i=1;i #include enum eRSType {RSTNONE,RST1,RST2,RST3,RST4}; extern QString rsTypeStr[RST4+1]; union long_byte_union { quint64 i; unsigned char b[8]; }; class reedSolomonCoder { public: reedSolomonCoder(); ~reedSolomonCoder(); void init(); bool decode(QByteArray &ba, QString fn, QString &newFileName, QByteArray &baFile, QString extension, QList &erasuresArray); bool encode(QByteArray &ba, QString extension, eRSType rsType); private: void distribute(byte *src, byte *dst, int rows, int cols, int reverse); bool decode_and_write(); QByteArray ec_buf; /* pointer to encoding/decoding buffer */ QByteArray tr_buf; /* pointer to transmit-buffer (fread/fwrite) */ QByteArray bk_buf; /* pointer to backup-buffer for resync */ int rs_bsize; int rs_dsize; int bep_size; unsigned long sumOfFailures; unsigned long uncorrectableFailures; int k; QFile fpin, fpout; long got,chunks; int coded_file_size ; char coded_file_ext[4] ; QString origFileName; char *p ; eRSType fileType; int totalSegments; int segmentLength; int *zeroPositions; int *newZeroPositions; int numMissing; }; #endif // REEDSOLOMONCODER_H qsstv_8.2.12/qsstv/utils/rs.cpp000664 001750 001750 00000032412 12437307434 016447 0ustar00jomajoma000000 000000 /* * Reed-Solomon coding and decoding * Phil Karn (karn@ka9q.ampr.org) September 1996 * Separate CCSDS version create Dec 1998, merged into this version May 1999 * * This file is derived from my generic RS encoder/decoder, which is * in turn based on the program "new_rs_erasures.c" by Robert * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy * (harit@spectra.eng.hawaii.edu), Aug 1995 * Copyright 1999 Phil Karn, KA9Q * May be used under the terms of the GNU public license */ #include #include "rs.h" static int KK; /* MM, KK, B0, PRIM are user-defined in rs.h */ /* Primitive polynomials - see Lin & Costello, Appendix A, * and Lee & Messerschmitt, p. 453. */ /* 1+x^2+x^3+x^4+x^8 */ int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 }; /* This defines the type used to store an element of the Galois Field * used by the code. Make sure this is something larger than a char if * if anything larger than GF(256) is used. * * Note: unsigned char will work up to GF(256) but int seems to run * faster on the Pentium. */ typedef int gf; /* index->polynomial form conversion table */ static gf Alpha_to[NN + 1]; /* Polynomial->index form conversion table */ static gf Index_of[NN + 1]; /* No legal value in index form represents zero, so * we need a special value for this purpose */ #define A0 (NN) /* Generator polynomial g(x) in index form */ //static gf Gg[NN - KK + 1]; static gf Gg[NN-RSDSIZERS4+1]; //worst case static int RS_init=0; /* Initialization flag */ /* Compute x % NN, where NN is 2**MM - 1, * without a slow divide */ static gf modnn(int x) { while (x >= NN) { x -= NN; x = (x >> MM) + (x & NN); } return x; } #define min(a,b) ((a) < (b) ? (a) : (b)) #define CLEAR(a,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = 0;\ } #define COPY(a,b,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = (b)[ci];\ } #define COPYDOWN(a,b,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = (b)[ci];\ } #define Ldec 1 /* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m] lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; polynomial form -> index form index_of[j=alpha**i] = i alpha=2 is the primitive element of GF(2**m) HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: Let @ represent the primitive element commonly called "alpha" that is the root of the primitive polynomial p(x). Then in GF(2^m), for any 0 <= i <= 2^m-2, @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for example the polynomial representation of @^5 would be given by the binary representation of the integer "alpha_to[5]". Similarily, index_of[] can be used as follows: As above, let @ represent the primitive element of GF(2^m) that is the root of the primitive polynomial p(x). In order to find the power of @ (alpha) that has the polynomial representation a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) we consider the integer "i" whose binary representation with a(0) being LSB and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry "index_of[i]". Now, @^index_of[i] is that element whose polynomial representation is (a(0),a(1),a(2),...,a(m-1)). NOTE: The element alpha_to[2^m-1] = 0 always signifying that the representation of "@^infinity" = 0 is (0,0,0,...,0). Similarily, the element index_of[0] = A0 always signifying that the power of alpha which has the polynomial representation (0,0,...,0) is "infinity". */ static void generate_gf(void) { register int i, mask; mask = 1; Alpha_to[MM] = 0; for (i = 0; i < MM; i++) { Alpha_to[i] = mask; Index_of[Alpha_to[i]] = i; /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ if (Pp[i] != 0) Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ mask <<= 1; /* single left-shift */ } Index_of[Alpha_to[MM]] = MM; /* * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by * poly-repr of @^i shifted left one-bit and accounting for any @^MM * term that may occur when poly-repr of @^i is shifted. */ mask >>= 1; for (i = MM + 1; i < NN; i++) { if (Alpha_to[i - 1] >= mask) Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); else Alpha_to[i] = Alpha_to[i - 1] << 1; Index_of[Alpha_to[i]] = i; } Index_of[0] = A0; Alpha_to[NN] = 0; } /* * Obtain the generator polynomial of the TT-error correcting, length * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, * ... ,(2*TT-1) * * Examples: * * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. * g(x) = (x+@) (x+@**2) * * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) */ static void gen_poly(void) { register int i, j; Gg[0] = 1; for (i = 0; i < NN - KK; i++) { Gg[i+1] = 1; /* * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by * (@**(B0+i)*PRIM + x) */ for (j = i; j > 0; j--) if (Gg[j] != 0) Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + (B0 + i) *PRIM)]; else Gg[j] = Gg[j - 1]; /* Gg[0] can never be zero */ Gg[0] = Alpha_to[modnn(Index_of[Gg[0]] + (B0 + i) * PRIM)]; } /* convert Gg[] to index form for quicker encoding */ for (i = 0; i <= NN - KK; i++) Gg[i] = Index_of[Gg[i]]; } /* * take the string of symbols in data[i], i=0..(k-1) and encode * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] * is input and bb[] is output in polynomial form. Encoding is done by using * a feedback shift register with appropriate connections specified by the * elements of Gg[], which was generated above. Codeword is c(X) = * data(X)*X**(NN-KK)+ b(X) */ int encode_rs(dtype data[], dtype bb[]) { register int i, j; gf feedback; CLEAR(bb,NN-KK); for(i = KK - 1; i >= 0; i--) { feedback = Index_of[data[i] ^ bb[NN - KK - 1]]; if (feedback != A0) { /* feedback term is non-zero */ for (j = NN - KK - 1; j > 0; j--) if (Gg[j] != A0) bb[j] = bb[j - 1] ^ Alpha_to[modnn(Gg[j] + feedback)]; else bb[j] = bb[j - 1]; bb[0] = Alpha_to[modnn(Gg[0] + feedback)]; } else { /* feedback term is zero. encoder becomes a * single-byte shifter */ for (j = NN - KK - 1; j > 0; j--) bb[j] = bb[j - 1]; bb[0] = 0; } } return 0; } /* * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, * writes the codeword into data[] itself. Otherwise data[] is unaltered. * * Return number of symbols corrected, or -1 if codeword is illegal * or uncorrectable. If eras_pos is non-null, the detected error locations * are written back. NOTE! This array must be at least NN-KK elements long. * * First "no_eras" erasures are declared by the calling program. Then, the * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). * If the number of channel errors is not greater than "t_after_eras" the * transmitted codeword will be recovered. Details of algorithm can be found * in R. Blahut's "Theory ... of Error-Correcting Codes". * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure * will result. The decoder *could* check for this condition, but it would involve * extra time on every decoding operation. */ int eras_dec_rs(dtype data[], int eras_pos[], int no_eras) { int deg_lambda, el, deg_omega; int i, j, r,k; gf u,q,tmp,num1,num2,den,discr_r; gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly * and syndrome poly */ gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK]; int syn_error, count; /* form the syndromes; i.e., evaluate data(x) at roots of g(x) * namely @**(B0+i)*PRIM, i = 0, ... ,(NN-KK-1) */ for(i=1;i<=NN-KK;i++) { s[i] = data[0]; } for(j=1;j 0) { /* Init lambda to be the erasure locator polynomial */ lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])]; for (i = 1; i < no_eras; i++) { u = modnn(PRIM*eras_pos[i]); for (j = i+1; j > 0; j--) { tmp = Index_of[lambda[j - 1]]; if(tmp != A0) { lambda[j] ^= Alpha_to[modnn(u + tmp)]; } } } } for(i=0;i 0; j--){ if (reg[j] != A0) { reg[j] = modnn(reg[j] + j); q ^= Alpha_to[reg[j]]; } } if (q != 0) continue; /* store root (index-form) and error location number */ root[count] = i; loc[count] = k; /* If we've already found max possible roots, * abort the search to save time */ if(++count == deg_lambda) break; } if (deg_lambda != count) { /* * deg(lambda) unequal to number of roots => uncorrectable * error detected */ count = -1; goto finish; } /* * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo * x**(NN-KK)). in index form. Also find deg(omega). */ deg_omega = 0; for (i = 0; i < NN-KK;i++){ tmp = 0; j = (deg_lambda < i) ? deg_lambda : i; for(;j >= 0; j--){ if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; } if(tmp != 0) deg_omega = i; omega[i] = Index_of[tmp]; } omega[NN-KK] = A0; /* * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form */ for (j = count-1; j >=0; j--) { num1 = 0; for (i = deg_omega; i >= 0; i--) { if (omega[i] != A0) num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; } num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; den = 0; /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { if(lambda[i+1] != A0) den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; } if (den == 0) { /* Convert to dual- basis */ count = -1; goto finish; } /* Apply error to data */ if (num1 != 0) { data[loc[j]] ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; } } finish: if(eras_pos != NULL){ for(i=0;i #include #include #include "qsstvglobal.h" QString lastPath(""); bool getValue(int &val, QLineEdit* input) { bool ok; QString s; s=input->text(); val=s.toInt(&ok,0); // allow ayutomatic conversion from hex to decimal in the classic C++ way : 0x is hex other are decimal return ok; } bool getValue(double &val, QLineEdit* input) { bool ok; QString s; s=input->text(); val=s.toDouble(&ok); return ok; } bool getValue(int &val, QString input) { bool ok; val=input.toInt(&ok); return ok; } bool getValue(double &val, QString input) { bool ok; val=input.toDouble(&ok); return ok; } void getValue(bool &val, QCheckBox *input) { val=input->isChecked(); } void getValue(int &val, QSpinBox *input) { val=input->value(); } void getValue(uint &val, QSpinBox *input) { val=input->value(); } void getValue(double &val, QDoubleSpinBox *input) { val=input->value(); } void getValue(QString &s, QLineEdit *input) { s=input->text(); } void getValue(QString &s, QPlainTextEdit *input) { s=input->toPlainText(); } void getValue(int &s, QComboBox *input) { s=input->currentText().toInt(); } void getIndex(int &s, QComboBox *input) { s=input->currentIndex(); } void getValue(QString &s, QComboBox *input) { s=input->currentText(); } void getValue(int &s, QButtonGroup *input) { s=input->checkedId(); } void getValue(bool &s, QRadioButton *input) { s=input->isChecked(); } void getValue(int &val, QSlider *input) { val=input->value(); } void setValue(int val, QLineEdit* output) { output->setText(QString::number(val)); } void setValue(double val, QLineEdit* output) { output->setText(QString::number(val)); } /** \brief sets double number in a QlineEdit \param val the value to set \param output pointer to QLineEdit \param prec the required precision */ void setValue(double val, QLineEdit* output,int prec) { output->setText(QString::number(val,'g',prec)); } void setValue(bool val, QCheckBox *input) { input->setChecked(val); } void setValue(int val, QSpinBox *input) { input->setValue(val); } void setValue(uint val, QSpinBox *input) { input->setValue(val); } void setValue(double val, QDoubleSpinBox *input) { input->setValue(val); } void setValue(QString s, QLineEdit *input) { input->setText(s); } void setValue(QString s, QPlainTextEdit *input) { input->setPlainText(s); } void setValue(int s, QComboBox *input) { int i; for(i=0;icount();i++) { if(input->itemText(i).toInt()==s) { input->setCurrentIndex(i); return; } } input->setCurrentIndex(0); } void setIndex(int s, QComboBox *input) { input->setCurrentIndex(s); } void setValue(QString s, QComboBox *input) { int i; for(i=0;icount();i++) { if(input->itemText(i)==s) { input->setCurrentIndex(i); return; } } input->setCurrentIndex(0); } void setValue(int s, QButtonGroup *input) { input->button(s)->setChecked(true); } void setValue(bool s, QRadioButton *input) { input->setChecked(s); } void setValue(int val, QSlider *input) { input->setValue(val); } bool browseGetFile(QLineEdit *le,QString deflt, const QString &filter) { dirDialog d((QWidget *)le,"Browse"); QString s=d.openFileName(deflt,filter); if (s==QString::null) return false; if (s.isEmpty()) return false; le->setText(s); return true; } bool browseSaveFile(QLineEdit *le,QString deflt,const QString &filter) { dirDialog d((QWidget *)le,"Browse"); QString s=d.saveFileName(deflt,filter,""); if (s==QString::null) return false; if (s.isEmpty()) return false; le->setText(s); return true; } bool browseDir(QLineEdit *le,QString deflt) { dirDialog d((QWidget *)le,"Browse"); QString s=d.openDirName(deflt); if (s==QString::null) return false; if (s.isEmpty()) return false; le->setText(s); return true; } dirDialog::dirDialog(QWidget * parent,QString title) { parentPtr=parent; dialogTitle=title; } dirDialog::~dirDialog() { } /*! \fn dirDialog::openFileName(const QString &path, const QString &filter, bool single) \brief selection of a file \param path directory to open (preselected) if empty, the last accessed directory will be used \param filter types to select from (e.g. mydirs*) \param single allows selection of more than one file if true \return if canceled or no selection then returns an empty string else return string containing absolute filename */ QString dirDialog::openFileName(const QString &path, const QString &filter) { QString fn; if (path.isEmpty() && lastPath.isEmpty()) { lastPath=QDir::homePath(); } else if (!path.isEmpty()) { lastPath=path; } fn=QFileDialog::getOpenFileName(parentPtr,dialogTitle,lastPath,filter); if(!fn.isEmpty()) { QFileInfo fi(fn); lastPath=fi.absolutePath(); } return fn; } /*! \fn dirDialog::openDirName(const QString &path, const QString &filter) \brief selection of a directory \param path directory to open (preselected) \param filter types to select from (e.g. mydirs*) \return if canceled or no selection then return an empty string else return string containing absolute dirname */ QString dirDialog::openDirName(const QString &path) { QString fn; if ((path.isEmpty()) && lastPath.isEmpty()) { lastPath=QDir::homePath(); } else if (!path.isEmpty()) { lastPath=path; } fn=QFileDialog::getExistingDirectory(parentPtr,dialogTitle,lastPath); if(!fn.isEmpty()) { lastPath=fn; } return fn; } /*! \fn dirDialog::saveFileName(const QString &path, const QString &filter,QString extension) \brief Save a file to disk Saves a file to disk. A dialogbox is opened with \a startWith directory (or /dir/subdir/..../filename) preselected \param path directory to open (can include filename to preselect) \param filter file types to select from (e.g. *.txt *.doc) \param extension if extension is not empty or NULL, thenn this string will be appended to the filename. A dot will automatically be insterted (i.e specify "txt" not ".txt"). \return if canceled or no selection then return an empty string else return string containing absolute filename. */ QString dirDialog::saveFileName(const QString &path, const QString &filter, QString extension) { QString fn; if ((path.isEmpty()) && lastPath.isEmpty()) { lastPath=QDir::currentPath(); } else if (!path.isEmpty()) { lastPath=path; } QString exten(extension); fn=QFileDialog::getSaveFileName(parentPtr,dialogTitle,lastPath,filter); if(fn.isEmpty()) return fn; QFileInfo fi(fn); if(!exten.isEmpty()) { if(fi.suffix()=="") { fi.setFile(fi.absoluteFilePath()+"."+exten); } } lastPath=fi.absolutePath(); return fi.absoluteFilePath(); } void deleteFiles(QString dirPath,QString extension) { int i; QDir dir(dirPath); QStringList filters; QFile fi; filters << extension; dir.setNameFilters(filters); QFileInfoList entries = dir.entryInfoList(filters,QDir::Files|QDir::NoSymLinks); for(i=0;i data,unsigned int len,bool toAux) { CVectorEx<_COMPLEX> vct=data; _COMPLEX c; unsigned int i,j; // unsigned int len; // len=vct.Size()/8; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } void arrayBinDump(QString label,CVector<_BINARY> data,unsigned int len,bool toAux) { CVector<_BINARY> vct=data; unsigned int i,j; // unsigned int len; // len=vct.Size()/8; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } void arrayDump(QString label,short int *data, unsigned int len,bool toAux) { unsigned int i,j; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } void arrayDump(QString label,int *data, unsigned int len,bool toAux) { unsigned int i,j; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } void arrayDump(QString label, float *data, unsigned int len, bool toAux) { unsigned int i,j; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } void arrayDump(QString label, quint32* data, unsigned int len, bool toAux) { unsigned int i,j; QString dumpStr,tmp; for( i=0;iaddToAux(dumpStr); } else { addToLog(dumpStr,LOGALL); } } } timingAnalyser::timingAnalyser() { } timingAnalyser::~timingAnalyser() { } void timingAnalyser::start() { tm.start(); } unsigned long timingAnalyser::result() { return tm.elapsed(); } qsstv_8.2.12/qsstv/utils/supportfunctions.h000664 001750 001750 00000006116 12450753733 021141 0ustar00jomajoma000000 000000 #ifndef SUPPORTFUNCTIONS_H #define SUPPORTFUNCTIONS_H #include #include #include #include #include #include #include #include #include #include #include #include "vector.h" /** \file */ #define OK true #define NOK false /** get int value from a QLinedit */ bool getValue(int &val, QLineEdit *input); /** get double value from a QLinedit */ bool getValue(double &val, QLineEdit *input); /** get int value from a QString */ bool getValue(int &val, QString input); bool getValue(double &val, QString input); void getValue(bool &val, QCheckBox *input); void getValue(int &val, QSpinBox *input); void getValue(uint &val, QSpinBox *input); void getValue(double &val, QDoubleSpinBox *input); void getValue(QString &s, QLineEdit *input); void getValue(QString &s, QPlainTextEdit *input); void getValue(int &s, QComboBox *input); void getIndex(int &s, QComboBox *input); void getValue(QString &s, QComboBox *input); void getValue(int &s, QButtonGroup *input); void getValue(bool &val, QRadioButton *input); void getValue(int &val, QSlider *input); void setValue(int val, QLineEdit* output); void setValue(double val, QLineEdit* output); void setValue(double val, QLineEdit* output,int prec); void setValue(bool val, QCheckBox *input); void setValue(int val, QSpinBox *input); void setValue(uint val, QSpinBox *input); void setValue(double val, QDoubleSpinBox *input); void setValue(QString s, QLineEdit *input); void setValue(QString s, QPlainTextEdit *input); void setValue(int s, QComboBox *input); void setIndex(int s, QComboBox *input); void setValue(QString s, QComboBox *input); void setValue(int s, QButtonGroup *input); void setValue(bool val, QRadioButton *input); void setValue(int val, QSlider *input); bool browseGetFile(QLineEdit *le,QString deflt,const QString &filter="*"); bool browseSaveFile(QLineEdit *le,QString deflt,const QString &filter="*"); bool browseDir(QLineEdit *le, QString deflt); void deleteFiles(QString dirPath,QString extension); bool trash(QString filename,bool forceDelete); void arrayDump(QString label, short int *data, unsigned int len, bool toAux); void arrayDump(QString label, int *data, unsigned int len, bool toAux); void arrayDump(QString label,float *data, unsigned int len,bool toAux); void arrayDump(QString label, quint32 *data, unsigned int len, bool toAux); void arrayBinDump(QString label, CVector<_BINARY> data, unsigned int len, bool toAux); void arrayComplexDump(QString label,CVectorEx<_COMPLEX> data,unsigned int len,bool toAux); class dirDialog { public: dirDialog(QWidget *parent,QString title=""); ~dirDialog(); QString openFileName(const QString &startWith, const QString &filter="*"); QString openDirName(const QString &path); QString saveFileName(const QString &path, const QString &filter,QString extension); private: QWidget * parentPtr; QString dialogTitle; }; class timingAnalyser { public: timingAnalyser(); ~timingAnalyser(); void start(); unsigned long result(); private: QTime tm; }; #endif qsstv_8.2.12/qsstv/utils/vector.h000664 001750 001750 00000035021 12440612574 016767 0ustar00jomajoma000000 000000 /******************************************************************************\ * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik * Copyright (c) 2001 * * Author(s): * Volker Fischer * * Description: * * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #if !defined(VECTOR_H__3B0BA660_CA6LIUBEFIB2B_23E7A0D31912__INCLUDED_) #define VECTOR_H__3B0BA660_CA6LIUBEFIB2B_23E7A0D31912__INCLUDED_ //#include "drmtx/common/GlobalDefinitions.h" #include "qsstvdefs.h" using namespace std; /* Because of the library: "complex" */ #include #include #include #include /******************************************************************************\ * CVector base class * \******************************************************************************/ template class CVector : public vector { public: CVector() : iBitArrayCounter(0), iVectorSize(0) {pData = this->begin();} CVector(const int iNeSi) {Init(iNeSi);} CVector(const int iNeSi, const TData tInVa) {Init(iNeSi, tInVa);} virtual ~CVector() {} /* Copy constructor: The order of the initialization list must not be changed. First, the base class must be initialized, then the pData pointer must be set to the new data source. The bit access is, by default, reset */ CVector(const CVector& vecI) : vector(static_cast&>(vecI)), iBitArrayCounter(0), iVectorSize(vecI.Size()) {pData = this->begin();} virtual void Init(const int iNewSize); /* Use this init to give all elements a defined value */ virtual void Init(const int iNewSize, const TData tIniVal); void Reset(const TData tResetVal); void Enlarge(const int iAddedSize); void Add(const TData& tI) {Enlarge(1); pData[iVectorSize - 1] = tI;} inline int Size() const {return iVectorSize;} /* This operator allows for a l-value assignment of this object: CVector[x] = y is possible */ inline TData& operator[](const int iPos) { #ifdef _DEBUG_ if ((iPos < 0) || (iPos > iVectorSize - 1)) { DebugError("Writing vector out of bounds", "Vector size", iVectorSize, "New parameter", iPos); } #endif return pData[iPos];} inline TData operator[](const int iPos) const { #ifdef _DEBUG_ if ((iPos < 0) || (iPos > iVectorSize - 1)) { DebugError("Reading vector out of bounds", "Vector size", iVectorSize, "New parameter", iPos); } #endif return pData[iPos];} inline CVector& operator=(const CVector& vecI) { #ifdef _DEBUG_ /* Vectors which shall be copied MUST have same size! (If this is satisfied, the parameter "iVectorSize" must not be adjusted as a side effect) */ if (vecI.Size() != iVectorSize) { DebugError("Vector operator=() different size", "Vector size", iVectorSize, "New parameter", vecI.Size()); } #endif vector::operator=(vecI); /* Reset my data pointer in case, the operator=() of the base class did change the actual memory */ pData = this->begin(); return *this; } /* Bit operation functions */ void Enqueue(uint32_t iInformation, const int iNumOfBits); uint32_t Separate(const int iNumOfBits); void ResetBitAccess() {iBitArrayCounter = 0;} protected: typename vector::iterator pData; int iBitArrayCounter; int iVectorSize; }; /* Implementation *************************************************************/ template void CVector::Init(const int iNewSize) { iVectorSize = iNewSize; /* Clear old buffer and reserve memory for new buffer, get iterator for pointer operations */ this->clear(); this->resize(iNewSize); pData = this->begin(); } template void CVector::Init(const int iNewSize, const TData tIniVal) { /* Call actual init routine */ Init(iNewSize); /* Set values */ Reset(tIniVal); } template void CVector::Enlarge(const int iAddedSize) { iVectorSize += iAddedSize; this->resize(iVectorSize); /* We have to reset the pointer since it could be that the vector size was zero before enlarging the vector */ pData = this->begin(); } template void CVector::Reset(const TData tResetVal) { /* Set all values to reset value */ for (int i = 0; i < iVectorSize; i++) pData[i] = tResetVal; } template void CVector::Enqueue(uint32_t iInformation, const int iNumOfBits) { /* Enqueue bits in bit array */ for (int i = 0; i < iNumOfBits; i++) { /* We want to put the bits on the array with the MSB first */ operator[](iBitArrayCounter + iNumOfBits - i - 1) = _BINARY(iInformation & 1); /* Shift one bit to mask next bit at LSB-position */ iInformation >>= 1; } iBitArrayCounter += iNumOfBits; } template uint32_t CVector::Separate(const int iNumOfBits) { uint32_t iInformation; /* Check, if current position plus new bit-size is smaller than the maximum length of the bit vector. Error code: return a "0" */ if (iBitArrayCounter + iNumOfBits > iVectorSize) return 0; /* Separate out bits from bit-array */ iInformation = 0; for (int i = 0; i < iNumOfBits; i++) { /* MSB comes first, therefore shift left */ iInformation <<= 1; iInformation |= pData[iBitArrayCounter + i] & 1; } iBitArrayCounter += iNumOfBits; return iInformation; } /******************************************************************************\ * CShiftRegister class * \******************************************************************************/ template class CShiftRegister : public CVector { public: CShiftRegister() : CVector() {} CShiftRegister(const int iNeSi) : CVector(iNeSi) {} CShiftRegister(const int iNeSi, const TData tInVa) : CVector(iNeSi, tInVa) {} /* Add one value at the beginning, shift the others to the right */ void AddBegin(const TData tNewD); /* Add one value at the end, shift the others to the left */ void AddEnd(const TData tNewD); /* Add a vector at the end, shift others to the left */ void AddEnd(const CVector& vectNewD, const int iLen); }; /* Implementation *************************************************************/ template void CShiftRegister::AddBegin(const TData tNewD) { /* Shift old values */ for (int i = this->iVectorSize - 1; i > 0; i--) this->pData[i] = this->pData[i - 1]; /* Add new value */ this->pData[0] = tNewD; } template void CShiftRegister::AddEnd(const TData tNewD) { /* Shift old values */ for (int i = 0; i < this->iVectorSize - 1; i++) this->pData[i] = this->pData[i + 1]; /* Add new value */ this->pData[this->iVectorSize - 1] = tNewD; } template void CShiftRegister::AddEnd(const CVector& vectNewD, const int iLen) { int i, iBlockEnd, iMovLen; iBlockEnd = this->iVectorSize - iLen; iMovLen = iLen; /* Shift old values */ for (i = 0; i < iBlockEnd; i++) this->pData[i] = this->pData[iMovLen++]; /* Add new block of data */ for (i = 0; i < iLen; i++) this->pData[iBlockEnd++] = vectNewD[i]; } /******************************************************************************\ * CFIFO class (first in, first out) * \******************************************************************************/ template class CFIFO : public CVector { public: CFIFO() : CVector(), iCurIdx(0) {} CFIFO(const int iNeSi) : CVector(iNeSi), iCurIdx(0) {} CFIFO(const int iNeSi, const TData tInVa) : CVector(iNeSi, tInVa), iCurIdx(0) {} void Add(const TData tNewD); inline TData Get() {return this->pData[iCurIdx];} virtual void Init(const int iNewSize); virtual void Init(const int iNewSize, const TData tIniVal); protected: int iCurIdx; }; template void CFIFO::Init(const int iNewSize) { iCurIdx = 0; CVector::Init(iNewSize); } template void CFIFO::Init(const int iNewSize, const TData tIniVal) { iCurIdx = 0; CVector::Init(iNewSize, tIniVal); } template void CFIFO::Add(const TData tNewD) { this->pData[iCurIdx] = tNewD; /* Increment index */ iCurIdx++; if (iCurIdx >= this->iVectorSize) iCurIdx = 0; } /******************************************************************************\ * CMovingAv class (moving average) * \******************************************************************************/ template class CMovingAv : public CVector { public: CMovingAv() : CVector(), iCurIdx(0) {} CMovingAv(const int iNeSi) : CVector(iNeSi), iCurIdx(0) {} CMovingAv(const int iNeSi, const TData tInVa) : CVector(iNeSi, tInVa), iCurIdx(0) {} void Add(const TData tNewD); inline TData GetAverage() {return tCurAvResult;} virtual void Init(const int iNewSize); void InitVec(const int iNewSize, const int iNewVecSize); protected: int iCurIdx; TData tCurAvResult; }; template void CMovingAv::InitVec(const int iNewSize, const int iNewVecSize) { iCurIdx = 0; CVector::Init(iNewSize); /* Init each vector in vector */ for (int i = 0; i < iNewSize; i++) this->pData[i].Init(iNewVecSize, 0); /* Init current average result */ tCurAvResult.Init(iNewVecSize, 0); } template void CMovingAv::Init(const int iNewSize) { iCurIdx = 0; tCurAvResult = TData(0); /* Only for scalars! */ CVector::Init(iNewSize); } template void CMovingAv::Add(const TData tNewD) { /* Optimized calculation of the moving average. We only add a new value and subtract the old value from the result. We only need one addition and a history buffer */ /* Subtract oldest value */ tCurAvResult -= this->pData[iCurIdx]; /* Add new value and write in memory */ tCurAvResult += tNewD; this->pData[iCurIdx] = tNewD; /* Increase position pointer and test if wrap */ iCurIdx++; if (iCurIdx >= this->iVectorSize) iCurIdx = 0; } /******************************************************************************\ * CVectorEx class (Extended vector with additional information) * \******************************************************************************/ class CExtendedVecData { public: /* Symbol ID of the current block. This number only identyfies the position in a frame, NOT in a super-frame */ int iSymbolID; /* This flag indicates that the symbol ID has changed */ _BOOLEAN bSymbolIDHasChanged; /* The channel estimation needs information about timing corrections, because it is using information from the symbol memory */ int iCurTimeCorr; }; template class CVectorEx : public CVector { public: CVectorEx() {} virtual ~CVectorEx() {} CExtendedVecData& GetExData() {return ExtendedData;} void SetExData(CExtendedVecData& NewExData) {ExtendedData = NewExData;} protected: CExtendedVecData ExtendedData; }; /******************************************************************************\ * CMatrix base class * \******************************************************************************/ template class CMatrix { public: CMatrix() : ppData(NULL), iRow(0), iCol(0) {} CMatrix(const int iNewR, const int iNewC) {Init(iNewR, iNewC);} CMatrix(const int iNewR, const int iNewC, const TData tInVa) {Init(iNewR, iNewC, tInVa);} CMatrix(const CMatrix& m): ppData(NULL) { Init(m.iRow,m.iCol); for (int i=0; i& operator[](const int iPos) const { #ifdef _DEBUG_ if ((iPos < 0) || (iPos > iRow - 1)) { DebugError("Matrix: Writing vector out of bounds", "Row size", iRow, "New parameter", iPos); } #endif return ppData[iPos];} inline CMatrix& operator=(const CMatrix& m) { this->Init(m.NumRows(), m.NumColumns()); for (int i=0; ippData[i] = m[i]; return *this; } #ifdef _DEBUG_ inline CVector operator[](const int iPos) const { if ((iPos < 0) || (iPos > iRow - 1)) { DebugError("Matrix: Reading vector out of bounds", "Row size", iRow, "New parameter", iPos); } return ppData[iPos];} #endif inline int NumRows(void) const { return iRow;} inline int NumColumns(void) const { return iCol;} protected: CVector* ppData; int iRow; int iCol; }; /* Implementation *************************************************************/ template void CMatrix::Init(const int iNewRow, const int iNewColumn) { iRow = iNewRow; iCol = iNewColumn; if (iRow > 0) { /* Delete resources from previous init */ if (ppData != NULL) delete[] ppData; /* Allocate new memory for history buffer */ ppData = new CVector[iRow]; for (int i = 0; i < iRow; i++) ppData[i].Init(iNewColumn); } } template void CMatrix::Init(const int iNewRow, const int iNewColumn, const TData tIniVal) { /* Call actual init routine */ Init(iNewRow, iNewColumn); /* Set values */ Reset(tIniVal); } template void CMatrix::Reset(const TData tResetVal) { /* Set all values to reset value */ for (int i = 0; i < iRow; i++) for (int j = 0; j < ppData[i].Size(); j++) ppData[i][j] = tResetVal; } template CMatrix::~CMatrix() { /* Delete buffer */ if (ppData != NULL) delete[] ppData; } #endif // !defined(VECTOR_H__3B0BA660_CA6LIUBEFIB2B_23E7A0D31912__INCLUDED_) qsstv_8.2.12/qsstv/utils/qftp.cpp000664 001750 001750 00000226227 12522714503 017000 0ustar00jomajoma000000 000000 /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qglobal.h" #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include "qftp.h" #include "qabstractsocket.h" #ifndef QT_NO_FTP #include "qcoreapplication.h" #include "qtcpsocket.h" #include "qurlinfo.h" #include "qstringlist.h" #include "qregexp.h" #include "qtimer.h" #include "qfileinfo.h" #include "qhash.h" #include "qtcpserver.h" #include "qlocale.h" QT_BEGIN_NAMESPACE class QFtpPI; /* The QFtpDTP (DTP = Data Transfer Process) controls all client side data transfer between the client and server. */ class QFtpDTP : public QObject { Q_OBJECT public: enum ConnectState { CsHostFound, CsConnected, CsClosed, CsHostNotFound, CsConnectionRefused }; QFtpDTP(QFtpPI *p, QObject *parent = 0); void setData(QByteArray *); void setDevice(QIODevice *); void writeData(); void setBytesTotal(qint64 bytes); bool hasError() const; QString errorMessage() const; void clearError(); void connectToHost(const QString & host, quint16 port); int setupListener(const QHostAddress &address); void waitForConnection(); QTcpSocket::SocketState state() const; qint64 bytesAvailable() const; qint64 read(char *data, qint64 maxlen); QByteArray readAll(); void abortConnection(); static bool parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info); signals: void listInfo(const QUrlInfo&); void readyRead(); void dataTransferProgress(qint64, qint64); void connectState(int); private slots: void socketConnected(); void socketReadyRead(); void socketError(QAbstractSocket::SocketError); void socketConnectionClosed(); void socketBytesWritten(qint64); void setupSocket(); void dataReadyRead(); private: void clearData(); QTcpSocket *socket; QTcpServer listener; QFtpPI *pi; QString err; qint64 bytesDone; qint64 bytesTotal; bool callWriteData; // If is_ba is true, ba is used; ba is never 0. // Otherwise dev is used; dev can be 0 or not. union { QByteArray *ba; QIODevice *dev; } data; bool is_ba; QByteArray bytesFromSocket; }; /********************************************************************** * * QFtpPI - Protocol Interpreter * *********************************************************************/ class QFtpPI : public QObject { Q_OBJECT public: QFtpPI(QObject *parent = 0); void connectToHost(const QString &host, quint16 port); bool sendCommands(const QStringList &cmds); bool sendCommand(const QString &cmd) { return sendCommands(QStringList(cmd)); } void clearPendingCommands(); void abort(); QString currentCommand() const { return currentCmd; } bool rawCommand; bool transferConnectionExtended; QFtpDTP dtp; // the PI has a DTP which is not the design of RFC 959, but it // makes the design simpler this way signals: void connectState(int); void finished(const QString&); void error(int, const QString&); void rawFtpReply(int, const QString&); private slots: void hostFound(); void connected(); void connectionClosed(); void delayedCloseFinished(); void readyRead(); void error(QAbstractSocket::SocketError); void dtpConnectState(int); private: // the states are modelled after the generalized state diagram of RFC 959, // page 58 enum State { Begin, Idle, Waiting, Success, Failure }; enum AbortState { None, AbortStarted, WaitForAbortToFinish }; bool processReply(); bool startNextCmd(); QTcpSocket commandSocket; QString replyText; char replyCode[3]; State state; AbortState abortState; QStringList pendingCommands; QString currentCmd; bool waitForDtpToConnect; bool waitForDtpToClose; QByteArray bytesFromSocket; friend class QFtpDTP; }; /********************************************************************** * * QFtpCommand implemenatation * *********************************************************************/ class QFtpCommand { public: QFtpCommand(QFtp::Command cmd, QStringList raw, const QByteArray &ba); QFtpCommand(QFtp::Command cmd, QStringList raw, QIODevice *dev = 0); ~QFtpCommand(); int id; QFtp::Command command; QStringList rawCmds; // If is_ba is true, ba is used; ba is never 0. // Otherwise dev is used; dev can be 0 or not. union { QByteArray *ba; QIODevice *dev; } data; bool is_ba; static QBasicAtomicInt idCounter; }; QBasicAtomicInt QFtpCommand::idCounter = Q_BASIC_ATOMIC_INITIALIZER(1); QFtpCommand::QFtpCommand(QFtp::Command cmd, QStringList raw, const QByteArray &ba) : command(cmd), rawCmds(raw), is_ba(true) { id = idCounter.fetchAndAddRelaxed(1); data.ba = new QByteArray(ba); } QFtpCommand::QFtpCommand(QFtp::Command cmd, QStringList raw, QIODevice *dev) : command(cmd), rawCmds(raw), is_ba(false) { id = idCounter.fetchAndAddRelaxed(1); data.dev = dev; } QFtpCommand::~QFtpCommand() { if (is_ba) delete data.ba; } /********************************************************************** * * QFtpDTP implemenatation * *********************************************************************/ QFtpDTP::QFtpDTP(QFtpPI *p, QObject *parent) : QObject(parent), socket(0), listener(this), pi(p), callWriteData(false) { clearData(); listener.setObjectName(QLatin1String("QFtpDTP active state server")); connect(&listener, SIGNAL(newConnection()), SLOT(setupSocket())); } void QFtpDTP::setData(QByteArray *ba) { is_ba = true; data.ba = ba; } void QFtpDTP::setDevice(QIODevice *dev) { is_ba = false; data.dev = dev; } void QFtpDTP::setBytesTotal(qint64 bytes) { bytesTotal = bytes; bytesDone = 0; emit dataTransferProgress(bytesDone, bytesTotal); } void QFtpDTP::connectToHost(const QString & host, quint16 port) { bytesFromSocket.clear(); if (socket) { delete socket; socket = 0; } socket = new QTcpSocket(this); #ifndef QT_NO_BEARERMANAGEMENT //copy network session down to the socket socket->setProperty("_q_networksession", property("_q_networksession")); #endif socket->setObjectName(QLatin1String("QFtpDTP Passive state socket")); connect(socket, SIGNAL(connected()), SLOT(socketConnected())); connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed())); connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); socket->connectToHost(host, port); } int QFtpDTP::setupListener(const QHostAddress &address) { #ifndef QT_NO_BEARERMANAGEMENT //copy network session down to the socket listener.setProperty("_q_networksession", property("_q_networksession")); #endif if (!listener.isListening() && !listener.listen(address, 0)) return -1; return listener.serverPort(); } void QFtpDTP::waitForConnection() { // This function is only interesting in Active transfer mode; it works // around a limitation in QFtp's design by blocking, waiting for an // incoming connection. For the default Passive mode, it does nothing. if (listener.isListening()) listener.waitForNewConnection(); } QTcpSocket::SocketState QFtpDTP::state() const { return socket ? socket->state() : QTcpSocket::UnconnectedState; } qint64 QFtpDTP::bytesAvailable() const { if (!socket || socket->state() != QTcpSocket::ConnectedState) return (qint64) bytesFromSocket.size(); return socket->bytesAvailable(); } qint64 QFtpDTP::read(char *data, qint64 maxlen) { qint64 read; if (socket && socket->state() == QTcpSocket::ConnectedState) { read = socket->read(data, maxlen); } else { read = qMin(maxlen, qint64(bytesFromSocket.size())); memcpy(data, bytesFromSocket.data(), read); bytesFromSocket.remove(0, read); } bytesDone += read; return read; } QByteArray QFtpDTP::readAll() { QByteArray tmp; if (socket && socket->state() == QTcpSocket::ConnectedState) { tmp = socket->readAll(); bytesDone += tmp.size(); } else { tmp = bytesFromSocket; bytesFromSocket.clear(); } return tmp; } void QFtpDTP::writeData() { if (!socket) return; if (is_ba) { #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::writeData: write %d bytes", data.ba->size()); #endif if (data.ba->size() == 0) emit dataTransferProgress(0, bytesTotal); else socket->write(data.ba->data(), data.ba->size()); socket->close(); clearData(); } else if (data.dev) { callWriteData = false; const qint64 blockSize = 16*1024; char buf[16*1024]; qint64 read = data.dev->read(buf, blockSize); #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::writeData: write() of size %lli bytes", read); #endif if (read > 0) { socket->write(buf, read); } else if (read == -1 || (!data.dev->isSequential() && data.dev->atEnd())) { // error or EOF if (bytesDone == 0 && socket->bytesToWrite() == 0) emit dataTransferProgress(0, bytesTotal); socket->close(); clearData(); } // do we continue uploading? callWriteData = data.dev != 0; } } void QFtpDTP::dataReadyRead() { writeData(); } inline bool QFtpDTP::hasError() const { return !err.isNull(); } inline QString QFtpDTP::errorMessage() const { return err; } inline void QFtpDTP::clearError() { err.clear(); } void QFtpDTP::abortConnection() { #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::abortConnection, bytesAvailable == %lli", socket ? socket->bytesAvailable() : (qint64) 0); #endif callWriteData = false; clearData(); if (socket) socket->abort(); } static void _q_fixupDateTime(QDateTime *dateTime) { // Adjust for future tolerance. const int futureTolerance = 86400; if (dateTime->secsTo(QDateTime::currentDateTime()) < -futureTolerance) { QDate d = dateTime->date(); d.setDate(d.year() - 1, d.month(), d.day()); dateTime->setDate(d); } } static void _q_parseUnixDir(const QStringList &tokens, const QString &userName, QUrlInfo *info) { // Unix style, 7 + 1 entries // -rw-r--r-- 1 ftp ftp 17358091 Aug 10 2004 qt-x11-free-3.3.3.tar.gz // drwxr-xr-x 3 ftp ftp 4096 Apr 14 2000 compiled-examples // lrwxrwxrwx 1 ftp ftp 9 Oct 29 2005 qtscape -> qtmozilla if (tokens.size() != 8) return; char first = tokens.at(1).at(0).toLatin1(); if (first == 'd') { info->setDir(true); info->setFile(false); info->setSymLink(false); } else if (first == '-') { info->setDir(false); info->setFile(true); info->setSymLink(false); } else if (first == 'l') { info->setDir(true); info->setFile(false); info->setSymLink(true); } // Resolve filename QString name = tokens.at(7); if (info->isSymLink()) { int linkPos = name.indexOf(QLatin1String(" ->")); if (linkPos != -1) name.resize(linkPos); } info->setName(name); // Resolve owner & group info->setOwner(tokens.at(3)); info->setGroup(tokens.at(4)); // Resolve size info->setSize(tokens.at(5).toLongLong()); QStringList formats; formats << QLatin1String("MMM dd yyyy") << QLatin1String("MMM dd hh:mm") << QLatin1String("MMM d yyyy") << QLatin1String("MMM d hh:mm") << QLatin1String("MMM d yyyy") << QLatin1String("MMM dd yyyy"); QString dateString = tokens.at(6); dateString[0] = dateString[0].toUpper(); // Resolve the modification date by parsing all possible formats QDateTime dateTime; int n = 0; #ifndef QT_NO_DATESTRING do { dateTime = QLocale::c().toDateTime(dateString, formats.at(n++)); } while (n < formats.size() && (!dateTime.isValid())); #endif if (n == 2 || n == 4) { // Guess the year. dateTime.setDate(QDate(QDate::currentDate().year(), dateTime.date().month(), dateTime.date().day())); _q_fixupDateTime(&dateTime); } if (dateTime.isValid()) info->setLastModified(dateTime); // Resolve permissions int permissions = 0; QString p = tokens.at(2); permissions |= (p[0] == QLatin1Char('r') ? QUrlInfo::ReadOwner : 0); permissions |= (p[1] == QLatin1Char('w') ? QUrlInfo::WriteOwner : 0); permissions |= (p[2] == QLatin1Char('x') ? QUrlInfo::ExeOwner : 0); permissions |= (p[3] == QLatin1Char('r') ? QUrlInfo::ReadGroup : 0); permissions |= (p[4] == QLatin1Char('w') ? QUrlInfo::WriteGroup : 0); permissions |= (p[5] == QLatin1Char('x') ? QUrlInfo::ExeGroup : 0); permissions |= (p[6] == QLatin1Char('r') ? QUrlInfo::ReadOther : 0); permissions |= (p[7] == QLatin1Char('w') ? QUrlInfo::WriteOther : 0); permissions |= (p[8] == QLatin1Char('x') ? QUrlInfo::ExeOther : 0); info->setPermissions(permissions); bool isOwner = info->owner() == userName; info->setReadable((permissions & QUrlInfo::ReadOther) || ((permissions & QUrlInfo::ReadOwner) && isOwner)); info->setWritable((permissions & QUrlInfo::WriteOther) || ((permissions & QUrlInfo::WriteOwner) && isOwner)); } static void _q_parseDosDir(const QStringList &tokens, const QString &userName, QUrlInfo *info) { // DOS style, 3 + 1 entries // 01-16-02 11:14AM epsgroup // 06-05-03 03:19PM 1973 readme.txt if (tokens.size() != 4) return; Q_UNUSED(userName); QString name = tokens.at(3); info->setName(name); info->setSymLink(name.toLower().endsWith(QLatin1String(".lnk"))); if (tokens.at(2) == QLatin1String("")) { info->setFile(false); info->setDir(true); } else { info->setFile(true); info->setDir(false); info->setSize(tokens.at(2).toLongLong()); } // Note: We cannot use QFileInfo; permissions are for the server-side // machine, and QFileInfo's behavior depends on the local platform. int permissions = QUrlInfo::ReadOwner | QUrlInfo::WriteOwner | QUrlInfo::ReadGroup | QUrlInfo::WriteGroup | QUrlInfo::ReadOther | QUrlInfo::WriteOther; QString ext; int extIndex = name.lastIndexOf(QLatin1Char('.')); if (extIndex != -1) ext = name.mid(extIndex + 1); if (ext == QLatin1String("exe") || ext == QLatin1String("bat") || ext == QLatin1String("com")) permissions |= QUrlInfo::ExeOwner | QUrlInfo::ExeGroup | QUrlInfo::ExeOther; info->setPermissions(permissions); info->setReadable(true); info->setWritable(info->isFile()); QDateTime dateTime; #ifndef QT_NO_DATESTRING dateTime = QLocale::c().toDateTime(tokens.at(1), QLatin1String("MM-dd-yy hh:mmAP")); if (dateTime.date().year() < 1971) { dateTime.setDate(QDate(dateTime.date().year() + 100, dateTime.date().month(), dateTime.date().day())); } #endif info->setLastModified(dateTime); } bool QFtpDTP::parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info) { if (buffer.isEmpty()) return false; QString bufferStr = QString::fromLatin1(buffer).trimmed(); // Unix style FTP servers QRegExp unixPattern(QLatin1String("^([\\-dl])([a-zA-Z\\-]{9,9})\\s+\\d+\\s+(\\S*)\\s+" "(\\S*)\\s+(\\d+)\\s+(\\S+\\s+\\S+\\s+\\S+)\\s+(\\S.*)")); if (unixPattern.indexIn(bufferStr) == 0) { _q_parseUnixDir(unixPattern.capturedTexts(), userName, info); return true; } // DOS style FTP servers QRegExp dosPattern(QLatin1String("^(\\d\\d-\\d\\d-\\d\\d\\d?\\d?\\ \\ \\d\\d:\\d\\d[AP]M)\\s+" "(|\\d+)\\s+(\\S.*)$")); if (dosPattern.indexIn(bufferStr) == 0) { _q_parseDosDir(dosPattern.capturedTexts(), userName, info); return true; } // Unsupported return false; } void QFtpDTP::socketConnected() { bytesDone = 0; #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsConnected)"); #endif emit connectState(QFtpDTP::CsConnected); } void QFtpDTP::socketReadyRead() { if (!socket) return; if (pi->currentCommand().isEmpty()) { socket->close(); #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsClosed)"); #endif emit connectState(QFtpDTP::CsClosed); return; } if (pi->abortState == QFtpPI::AbortStarted) { // discard data socket->readAll(); return; } if (pi->currentCommand().startsWith(QLatin1String("LIST"))) { while (socket->canReadLine()) { QUrlInfo i; QByteArray line = socket->readLine(); #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP read (list): '%s'", line.constData()); #endif if (parseDir(line, QLatin1String(""), &i)) { emit listInfo(i); } else { // some FTP servers don't return a 550 if the file or directory // does not exist, but rather write a text to the data socket // -- try to catch these cases if (line.endsWith("No such file or directory\r\n")) err = QString::fromLatin1(line); } } } else { if (!is_ba && data.dev) { do { QByteArray ba; ba.resize(socket->bytesAvailable()); qint64 bytesRead = socket->read(ba.data(), ba.size()); if (bytesRead < 0) { // a read following a readyRead() signal will // never fail. return; } ba.resize(bytesRead); bytesDone += bytesRead; #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone); #endif if (data.dev) // make sure it wasn't deleted in the slot data.dev->write(ba); emit dataTransferProgress(bytesDone, bytesTotal); // Need to loop; dataTransferProgress is often connected to // slots that update the GUI (e.g., progress bar values), and // if events are processed, more data may have arrived. } while (socket->bytesAvailable()); } else { #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP readyRead: %lli bytes available (total %lli bytes read)", bytesAvailable(), bytesDone); #endif emit dataTransferProgress(bytesDone+socket->bytesAvailable(), bytesTotal); emit readyRead(); } } } void QFtpDTP::socketError(QAbstractSocket::SocketError e) { if (e == QTcpSocket::HostNotFoundError) { #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsHostNotFound)"); #endif emit connectState(QFtpDTP::CsHostNotFound); } else if (e == QTcpSocket::ConnectionRefusedError) { #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsConnectionRefused)"); #endif emit connectState(QFtpDTP::CsConnectionRefused); } } void QFtpDTP::socketConnectionClosed() { if (!is_ba && data.dev) { clearData(); } // bytesFromSocket = socket->readAll(); #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsClosed)"); #endif emit connectState(QFtpDTP::CsClosed); } void QFtpDTP::socketBytesWritten(qint64 bytes) { bytesDone += bytes; #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::bytesWritten(%lli)", bytesDone); #endif emit dataTransferProgress(bytesDone, bytesTotal); if (callWriteData) writeData(); } void QFtpDTP::setupSocket() { socket = listener.nextPendingConnection(); socket->setObjectName(QLatin1String("QFtpDTP Active state socket")); connect(socket, SIGNAL(connected()), SLOT(socketConnected())); connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed())); connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); listener.close(); } void QFtpDTP::clearData() { is_ba = false; data.dev = 0; } /********************************************************************** * * QFtpPI implemenatation * *********************************************************************/ QFtpPI::QFtpPI(QObject *parent) : QObject(parent), rawCommand(false), transferConnectionExtended(true), dtp(this), commandSocket(0), state(Begin), abortState(None), currentCmd(QString()), waitForDtpToConnect(false), waitForDtpToClose(false) { commandSocket.setObjectName(QLatin1String("QFtpPI_socket")); connect(&commandSocket, SIGNAL(hostFound()), SLOT(hostFound())); connect(&commandSocket, SIGNAL(connected()), SLOT(connected())); connect(&commandSocket, SIGNAL(disconnected()), SLOT(connectionClosed())); connect(&commandSocket, SIGNAL(readyRead()), SLOT(readyRead())); connect(&commandSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(error(QAbstractSocket::SocketError))); connect(&dtp, SIGNAL(connectState(int)), SLOT(dtpConnectState(int))); } void QFtpPI::connectToHost(const QString &host, quint16 port) { emit connectState(QFtp::HostLookup); #ifndef QT_NO_BEARERMANAGEMENT //copy network session down to the socket & DTP commandSocket.setProperty("_q_networksession", property("_q_networksession")); dtp.setProperty("_q_networksession", property("_q_networksession")); #endif commandSocket.connectToHost(host, port); } /* Sends the sequence of commands \a cmds to the FTP server. When the commands are all done the finished() signal is emitted. When an error occurs, the error() signal is emitted. If there are pending commands in the queue this functions returns false and the \a cmds are not added to the queue; otherwise it returns true. */ bool QFtpPI::sendCommands(const QStringList &cmds) { if (!pendingCommands.isEmpty()) return false; if (commandSocket.state() != QTcpSocket::ConnectedState || state!=Idle) { emit error(QFtp::NotConnected, QFtp::tr("Not connected")); return true; // there are no pending commands } pendingCommands = cmds; startNextCmd(); return true; } void QFtpPI::clearPendingCommands() { pendingCommands.clear(); dtp.abortConnection(); currentCmd.clear(); state = Idle; } void QFtpPI::abort() { pendingCommands.clear(); if (abortState != None) // ABOR already sent return; abortState = AbortStarted; #if defined(QFTPPI_DEBUG) qDebug("QFtpPI send: ABOR"); #endif commandSocket.write("ABOR\r\n", 6); if (currentCmd.startsWith(QLatin1String("STOR "))) dtp.abortConnection(); } void QFtpPI::hostFound() { emit connectState(QFtp::Connecting); } void QFtpPI::connected() { state = Begin; #if defined(QFTPPI_DEBUG) // qDebug("QFtpPI state: %d [connected()]", state); #endif // try to improve performance by setting TCP_NODELAY commandSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1); emit connectState(QFtp::Connected); } void QFtpPI::connectionClosed() { commandSocket.close(); emit connectState(QFtp::Unconnected); } void QFtpPI::delayedCloseFinished() { emit connectState(QFtp::Unconnected); } void QFtpPI::error(QAbstractSocket::SocketError e) { if (e == QTcpSocket::HostNotFoundError) { emit connectState(QFtp::Unconnected); emit error(QFtp::HostNotFound, QFtp::tr("Host %1 not found").arg(commandSocket.peerName())); } else if (e == QTcpSocket::ConnectionRefusedError) { emit connectState(QFtp::Unconnected); emit error(QFtp::ConnectionRefused, QFtp::tr("Connection refused to host %1").arg(commandSocket.peerName())); } else if (e == QTcpSocket::SocketTimeoutError) { emit connectState(QFtp::Unconnected); emit error(QFtp::ConnectionRefused, QFtp::tr("Connection timed out to host %1").arg(commandSocket.peerName())); } } void QFtpPI::readyRead() { if (waitForDtpToClose) return; while (commandSocket.canReadLine()) { // read line with respect to line continuation QString line = QString::fromLatin1(commandSocket.readLine()); if (replyText.isEmpty()) { if (line.length() < 3) { // protocol error return; } const int lowerLimit[3] = {1,0,0}; const int upperLimit[3] = {5,5,9}; for (int i=0; i<3; i++) { replyCode[i] = line[i].digitValue(); if (replyCode[i]upperLimit[i]) { // protocol error return; } } } QString endOfMultiLine; endOfMultiLine[0] = '0' + replyCode[0]; endOfMultiLine[1] = '0' + replyCode[1]; endOfMultiLine[2] = '0' + replyCode[2]; endOfMultiLine[3] = QLatin1Char(' '); QString lineCont(endOfMultiLine); lineCont[3] = QLatin1Char('-'); QString lineLeft4 = line.left(4); while (lineLeft4 != endOfMultiLine) { if (lineLeft4 == lineCont) replyText += line.mid(4); // strip 'xyz-' else replyText += line; if (!commandSocket.canReadLine()) return; line = QString::fromLatin1(commandSocket.readLine()); lineLeft4 = line.left(4); } replyText += line.mid(4); // strip reply code 'xyz ' if (replyText.endsWith(QLatin1String("\r\n"))) replyText.chop(2); if (processReply()) replyText = QLatin1String(""); } } /* Process a reply from the FTP server. Returns true if the reply was processed or false if the reply has to be processed at a later point. */ bool QFtpPI::processReply() { #if defined(QFTPPI_DEBUG) // qDebug("QFtpPI state: %d [processReply() begin]", state); if (replyText.length() < 400) qDebug("QFtpPI recv: %d %s", 100*replyCode[0]+10*replyCode[1]+replyCode[2], replyText.toLatin1().constData()); else qDebug("QFtpPI recv: %d (text skipped)", 100*replyCode[0]+10*replyCode[1]+replyCode[2]); #endif int replyCodeInt = 100*replyCode[0] + 10*replyCode[1] + replyCode[2]; // process 226 replies ("Closing Data Connection") only when the data // connection is really closed to avoid short reads of the DTP if (replyCodeInt == 226 || (replyCodeInt == 250 && currentCmd.startsWith(QLatin1String("RETR")))) { if (dtp.state() != QTcpSocket::UnconnectedState) { waitForDtpToClose = true; return false; } } switch (abortState) { case AbortStarted: abortState = WaitForAbortToFinish; break; case WaitForAbortToFinish: abortState = None; return true; default: break; } // get new state static const State table[5] = { /* 1yz 2yz 3yz 4yz 5yz */ Waiting, Success, Idle, Failure, Failure }; switch (state) { case Begin: if (replyCode[0] == 1) { return true; } else if (replyCode[0] == 2) { state = Idle; emit finished(QFtp::tr("Connected to host %1").arg(commandSocket.peerName())); break; } // reply codes not starting with 1 or 2 are not handled. return true; case Waiting: if (static_cast(replyCode[0]) < 0 || replyCode[0] > 5) state = Failure; else #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) { // work around a crash on 64 bit gcc IRIX State *t = (State *) table; state = t[replyCode[0] - 1]; } #else if (replyCodeInt == 202) state = Failure; else state = table[replyCode[0] - 1]; #endif break; default: // ignore unrequested message return true; } #if defined(QFTPPI_DEBUG) // qDebug("QFtpPI state: %d [processReply() intermediate]", state); #endif // special actions on certain replies emit rawFtpReply(replyCodeInt, replyText); if (rawCommand) { rawCommand = false; } else if (replyCodeInt == 227) { // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2) // rfc959 does not define this response precisely, and gives // both examples where the parenthesis are used, and where // they are missing. We need to scan for the address and host // info. QRegExp addrPortPattern(QLatin1String("(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)")); if (addrPortPattern.indexIn(replyText) == -1) { #if defined(QFTPPI_DEBUG) qDebug("QFtp: bad 227 response -- address and port information missing"); #endif // this error should be reported } else { QStringList lst = addrPortPattern.capturedTexts(); QString host = lst[1] + QLatin1Char('.') + lst[2] + QLatin1Char('.') + lst[3] + QLatin1Char('.') + lst[4]; quint16 port = (lst[5].toUInt() << 8) + lst[6].toUInt(); waitForDtpToConnect = true; dtp.connectToHost(host, port); } } else if (replyCodeInt == 229) { // 229 Extended Passive mode OK (|||10982|) int portPos = replyText.indexOf(QLatin1Char('(')); if (portPos == -1) { #if defined(QFTPPI_DEBUG) qDebug("QFtp: bad 229 response -- port information missing"); #endif // this error should be reported } else { ++portPos; QChar delimiter = replyText.at(portPos); QStringList epsvParameters = replyText.mid(portPos).split(delimiter); waitForDtpToConnect = true; dtp.connectToHost(commandSocket.peerAddress().toString(), epsvParameters.at(3).toInt()); } } else if (replyCodeInt == 230) { if (currentCmd.startsWith(QLatin1String("USER ")) && pendingCommands.count()>0 && pendingCommands.first().startsWith(QLatin1String("PASS "))) { // no need to send the PASS -- we are already logged in pendingCommands.pop_front(); } // 230 User logged in, proceed. emit connectState(QFtp::LoggedIn); } else if (replyCodeInt == 213) { // 213 File status. if (currentCmd.startsWith(QLatin1String("SIZE "))) dtp.setBytesTotal(replyText.simplified().toLongLong()); } else if (replyCode[0]==1 && currentCmd.startsWith(QLatin1String("STOR "))) { dtp.waitForConnection(); dtp.writeData(); } // react on new state switch (state) { case Begin: // should never happen break; case Success: // success handling state = Idle; // no break! case Idle: if (dtp.hasError()) { emit error(QFtp::UnknownError, dtp.errorMessage()); dtp.clearError(); } startNextCmd(); break; case Waiting: // do nothing break; case Failure: // If the EPSV or EPRT commands fail, replace them with // the old PASV and PORT instead and try again. if (currentCmd.startsWith(QLatin1String("EPSV"))) { transferConnectionExtended = false; pendingCommands.prepend(QLatin1String("PASV\r\n")); } else if (currentCmd.startsWith(QLatin1String("EPRT"))) { transferConnectionExtended = false; pendingCommands.prepend(QLatin1String("PORT\r\n")); } else { emit error(QFtp::UnknownError, replyText); } if (state != Waiting) { state = Idle; startNextCmd(); } break; } #if defined(QFTPPI_DEBUG) // qDebug("QFtpPI state: %d [processReply() end]", state); #endif return true; } /* Starts next pending command. Returns false if there are no pending commands, otherwise it returns true. */ bool QFtpPI::startNextCmd() { if (waitForDtpToConnect) // don't process any new commands until we are connected return true; #if defined(QFTPPI_DEBUG) if (state != Idle) qDebug("QFtpPI startNextCmd: Internal error! QFtpPI called in non-Idle state %d", state); #endif if (pendingCommands.isEmpty()) { currentCmd.clear(); emit finished(replyText); return false; } currentCmd = pendingCommands.first(); // PORT and PASV are edited in-place, depending on whether we // should try the extended transfer connection commands EPRT and // EPSV. The PORT command also triggers setting up a listener, and // the address/port arguments are edited in. QHostAddress address = commandSocket.localAddress(); if (currentCmd.startsWith(QLatin1String("PORT"))) { if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) { int port = dtp.setupListener(address); currentCmd = QLatin1String("EPRT |"); currentCmd += (address.protocol() == QTcpSocket::IPv4Protocol) ? QLatin1Char('1') : QLatin1Char('2'); currentCmd += QLatin1Char('|') + address.toString() + QLatin1Char('|') + QString::number(port); currentCmd += QLatin1Char('|'); } else if (address.protocol() == QTcpSocket::IPv4Protocol) { int port = dtp.setupListener(address); QString portArg; quint32 ip = address.toIPv4Address(); portArg += QString::number((ip & 0xff000000) >> 24); portArg += QLatin1Char(',') + QString::number((ip & 0xff0000) >> 16); portArg += QLatin1Char(',') + QString::number((ip & 0xff00) >> 8); portArg += QLatin1Char(',') + QString::number(ip & 0xff); portArg += QLatin1Char(',') + QString::number((port & 0xff00) >> 8); portArg += QLatin1Char(',') + QString::number(port & 0xff); currentCmd = QLatin1String("PORT "); currentCmd += portArg; } else { // No IPv6 connection can be set up with the PORT // command. return false; } currentCmd += QLatin1String("\r\n"); } else if (currentCmd.startsWith(QLatin1String("PASV"))) { if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) currentCmd = QLatin1String("EPSV\r\n"); } pendingCommands.pop_front(); #if defined(QFTPPI_DEBUG) qDebug("QFtpPI send: %s", currentCmd.left(currentCmd.length()-2).toLatin1().constData()); #endif state = Waiting; commandSocket.write(currentCmd.toLatin1()); return true; } void QFtpPI::dtpConnectState(int s) { switch (s) { case QFtpDTP::CsClosed: if (waitForDtpToClose) { // there is an unprocessed reply if (processReply()) replyText = QLatin1String(""); else return; } waitForDtpToClose = false; readyRead(); return; case QFtpDTP::CsConnected: waitForDtpToConnect = false; startNextCmd(); return; case QFtpDTP::CsHostNotFound: case QFtpDTP::CsConnectionRefused: emit error(QFtp::ConnectionRefused, QFtp::tr("Connection refused for data connection")); startNextCmd(); return; default: return; } } /********************************************************************** * * QFtpPrivate * *********************************************************************/ class QFtpPrivate { Q_DECLARE_PUBLIC(QFtp) public: inline QFtpPrivate(QFtp *owner) : close_waitForStateChange(false), state(QFtp::Unconnected), transferMode(QFtp::Passive), error(QFtp::NoError), q_ptr(owner) { } ~QFtpPrivate() { while (!pending.isEmpty()) delete pending.takeFirst(); } // private slots void _q_startNextCommand(); void _q_piFinished(const QString&); void _q_piError(int, const QString&); void _q_piConnectState(int); void _q_piFtpReply(int, const QString&); int addCommand(QFtpCommand *cmd); QFtpPI pi; QList pending; bool close_waitForStateChange; QFtp::State state; QFtp::TransferMode transferMode; QFtp::Error error; QString errorString; QString host; quint16 port; QString proxyHost; quint16 proxyPort; QFtp *q_ptr; }; int QFtpPrivate::addCommand(QFtpCommand *cmd) { pending.append(cmd); if (pending.count() == 1) { // don't emit the commandStarted() signal before the ID is returned QTimer::singleShot(0, q_func(), SLOT(_q_startNextCommand())); } return cmd->id; } /********************************************************************** * * QFtp implementation * *********************************************************************/ /*! \class QFtp \brief The QFtp class provides an implementation of the client side of FTP protocol. \ingroup network \inmodule QtNetwork This class provides a direct interface to FTP that allows you to have more control over the requests. However, for new applications, it is recommended to use QNetworkAccessManager and QNetworkReply, as those classes possess a simpler, yet more powerful API. The class works asynchronously, so there are no blocking functions. If an operation cannot be executed immediately, the function will still return straight away and the operation will be scheduled for later execution. The results of scheduled operations are reported via signals. This approach depends on the event loop being in operation. The operations that can be scheduled (they are called "commands" in the rest of the documentation) are the following: connectToHost(), login(), close(), list(), cd(), get(), put(), remove(), mkdir(), rmdir(), rename() and rawCommand(). All of these commands return a unique identifier that allows you to keep track of the command that is currently being executed. When the execution of a command starts, the commandStarted() signal with the command's identifier is emitted. When the command is finished, the commandFinished() signal is emitted with the command's identifier and a bool that indicates whether the command finished with an error. In some cases, you might want to execute a sequence of commands, e.g. if you want to connect and login to a FTP server. This is simply achieved: \snippet doc/src/snippets/code/src_network_access_qftp.cpp 0 In this case two FTP commands have been scheduled. When the last scheduled command has finished, a done() signal is emitted with a bool argument that tells you whether the sequence finished with an error. If an error occurs during the execution of one of the commands in a sequence of commands, all the pending commands (i.e. scheduled, but not yet executed commands) are cleared and no signals are emitted for them. Some commands, e.g. list(), emit additional signals to report their results. Example: If you want to download the INSTALL file from the Qt FTP server, you would write this: \snippet doc/src/snippets/code/src_network_access_qftp.cpp 1 For this example the following sequence of signals is emitted (with small variations, depending on network traffic, etc.): \snippet doc/src/snippets/code/src_network_access_qftp.cpp 2 The dataTransferProgress() signal in the above example is useful if you want to show a \link QProgressBar progress bar \endlink to inform the user about the progress of the download. The readyRead() signal tells you that there is data ready to be read. The amount of data can be queried then with the bytesAvailable() function and it can be read with the read() or readAll() function. If the login fails for the above example, the signals would look like this: \snippet doc/src/snippets/code/src_network_access_qftp.cpp 3 You can then get details about the error with the error() and errorString() functions. For file transfer, QFtp can use both active or passive mode, and it uses passive file transfer mode by default; see the documentation for setTransferMode() for more details about this. Call setProxy() to make QFtp connect via an FTP proxy server. The functions currentId() and currentCommand() provide more information about the currently executing command. The functions hasPendingCommands() and clearPendingCommands() allow you to query and clear the list of pending commands. If you are an experienced network programmer and want to have complete control you can use rawCommand() to execute arbitrary FTP commands. \warning The current version of QFtp doesn't fully support non-Unix FTP servers. \sa QNetworkAccessManager, QNetworkRequest, QNetworkReply, {FTP Example} */ /*! Constructs a QFtp object with the given \a parent. */ QFtp::QFtp(QObject *parent) : QObject(parent), d(new QFtpPrivate(this)) { d->errorString = tr("Unknown error"); connect(&d->pi, SIGNAL(connectState(int)), SLOT(_q_piConnectState(int))); connect(&d->pi, SIGNAL(finished(QString)), SLOT(_q_piFinished(QString))); connect(&d->pi, SIGNAL(error(int,QString)), SLOT(_q_piError(int,QString))); connect(&d->pi, SIGNAL(rawFtpReply(int,QString)), SLOT(_q_piFtpReply(int,QString))); connect(&d->pi.dtp, SIGNAL(readyRead()), SIGNAL(readyRead())); connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)), SIGNAL(dataTransferProgress(qint64,qint64))); connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)), SIGNAL(listInfo(QUrlInfo))); } /*! \enum QFtp::State This enum defines the connection state: \value Unconnected There is no connection to the host. \value HostLookup A host name lookup is in progress. \value Connecting An attempt to connect to the host is in progress. \value Connected Connection to the host has been achieved. \value LoggedIn Connection and user login have been achieved. \value Closing The connection is closing down, but it is not yet closed. (The state will be \c Unconnected when the connection is closed.) \sa stateChanged() state() */ /*! \enum QFtp::TransferMode FTP works with two socket connections; one for commands and another for transmitting data. While the command connection is always initiated by the client, the second connection can be initiated by either the client or the server. This enum defines whether the client (Passive mode) or the server (Active mode) should set up the data connection. \value Passive The client connects to the server to transmit its data. \value Active The server connects to the client to transmit its data. */ /*! \enum QFtp::TransferType This enum identifies the data transfer type used with get and put commands. \value Binary The data will be transferred in Binary mode. \value Ascii The data will be transferred in Ascii mode and new line characters will be converted to the local format. */ /*! \enum QFtp::Error This enum identifies the error that occurred. \value NoError No error occurred. \value HostNotFound The host name lookup failed. \value ConnectionRefused The server refused the connection. \value NotConnected Tried to send a command, but there is no connection to a server. \value UnknownError An error other than those specified above occurred. \sa error() */ /*! \enum QFtp::Command This enum is used as the return value for the currentCommand() function. This allows you to perform specific actions for particular commands, e.g. in a FTP client, you might want to clear the directory view when a list() command is started; in this case you can simply check in the slot connected to the start() signal if the currentCommand() is \c List. \value None No command is being executed. \value SetTransferMode set the \link TransferMode transfer\endlink mode. \value SetProxy switch proxying on or off. \value ConnectToHost connectToHost() is being executed. \value Login login() is being executed. \value Close close() is being executed. \value List list() is being executed. \value Cd cd() is being executed. \value Get get() is being executed. \value Put put() is being executed. \value Remove remove() is being executed. \value Mkdir mkdir() is being executed. \value Rmdir rmdir() is being executed. \value Rename rename() is being executed. \value RawCommand rawCommand() is being executed. \sa currentCommand() */ /*! \fn void QFtp::stateChanged(int state) This signal is emitted when the state of the connection changes. The argument \a state is the new state of the connection; it is one of the \l State values. It is usually emitted in response to a connectToHost() or close() command, but it can also be emitted "spontaneously", e.g. when the server closes the connection unexpectedly. \sa connectToHost() close() state() State */ /*! \fn void QFtp::listInfo(const QUrlInfo &i); This signal is emitted for each directory entry the list() command finds. The details of the entry are stored in \a i. \sa list() */ /*! \fn void QFtp::commandStarted(int id) This signal is emitted when processing the command identified by \a id starts. \sa commandFinished() done() */ /*! \fn void QFtp::commandFinished(int id, bool error) This signal is emitted when processing the command identified by \a id has finished. \a error is true if an error occurred during the processing; otherwise \a error is false. \sa commandStarted() done() error() errorString() */ /*! \fn void QFtp::done(bool error) This signal is emitted when the last pending command has finished; (it is emitted after the last command's commandFinished() signal). \a error is true if an error occurred during the processing; otherwise \a error is false. \sa commandFinished() error() errorString() */ /*! \fn void QFtp::readyRead() This signal is emitted in response to a get() command when there is new data to read. If you specify a device as the second argument in the get() command, this signal is \e not emitted; instead the data is written directly to the device. You can read the data with the readAll() or read() functions. This signal is useful if you want to process the data in chunks as soon as it becomes available. If you are only interested in the complete data, just connect to the commandFinished() signal and read the data then instead. \sa get() read() readAll() bytesAvailable() */ /*! \fn void QFtp::dataTransferProgress(qint64 done, qint64 total) This signal is emitted in response to a get() or put() request to indicate the current progress of the download or upload. \a done is the amount of data that has already been transferred and \a total is the total amount of data to be read or written. It is possible that the QFtp class is not able to determine the total amount of data that should be transferred, in which case \a total is 0. (If you connect this signal to a QProgressBar, the progress bar shows a busy indicator if the total is 0). \warning \a done and \a total are not necessarily the size in bytes, since for large files these values might need to be "scaled" to avoid overflow. \sa get(), put(), QProgressBar */ /*! \fn void QFtp::rawCommandReply(int replyCode, const QString &detail); This signal is emitted in response to the rawCommand() function. \a replyCode is the 3 digit reply code and \a detail is the text that follows the reply code. \sa rawCommand() */ /*! Connects to the FTP server \a host using port \a port. The stateChanged() signal is emitted when the state of the connecting process changes, e.g. to \c HostLookup, then \c Connecting, then \c Connected. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa stateChanged() commandStarted() commandFinished() */ int QFtp::connectToHost(const QString &host, quint16 port) { QStringList cmds; cmds << host; cmds << QString::number((uint)port); int id = d->addCommand(new QFtpCommand(ConnectToHost, cmds)); d->pi.transferConnectionExtended = true; return id; } /*! Logs in to the FTP server with the username \a user and the password \a password. The stateChanged() signal is emitted when the state of the connecting process changes, e.g. to \c LoggedIn. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::login(const QString &user, const QString &password) { QStringList cmds; cmds << (QLatin1String("USER ") + (user.isNull() ? QLatin1String("anonymous") : user) + QLatin1String("\r\n")); cmds << (QLatin1String("PASS ") + (password.isNull() ? QLatin1String("anonymous@") : password) + QLatin1String("\r\n")); return d->addCommand(new QFtpCommand(Login, cmds)); } /*! Closes the connection to the FTP server. The stateChanged() signal is emitted when the state of the connecting process changes, e.g. to \c Closing, then \c Unconnected. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa stateChanged() commandStarted() commandFinished() */ int QFtp::close() { return d->addCommand(new QFtpCommand(Close, QStringList(QLatin1String("QUIT\r\n")))); } /*! Sets the current FTP transfer mode to \a mode. The default is QFtp::Passive. \sa QFtp::TransferMode */ int QFtp::setTransferMode(TransferMode mode) { int id = d->addCommand(new QFtpCommand(SetTransferMode, QStringList())); d->pi.transferConnectionExtended = true; d->transferMode = mode; return id; } /*! Enables use of the FTP proxy on host \a host and port \a port. Calling this function with \a host empty disables proxying. QFtp does not support FTP-over-HTTP proxy servers. Use QNetworkAccessManager for this. */ int QFtp::setProxy(const QString &host, quint16 port) { QStringList args; args << host << QString::number(port); return d->addCommand(new QFtpCommand(SetProxy, args)); } /*! Lists the contents of directory \a dir on the FTP server. If \a dir is empty, it lists the contents of the current directory. The listInfo() signal is emitted for each directory entry found. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa listInfo() commandStarted() commandFinished() */ int QFtp::list(const QString &dir) { QStringList cmds; cmds << QLatin1String("TYPE A\r\n"); cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); if (dir.isEmpty()) cmds << QLatin1String("LIST\r\n"); else cmds << (QLatin1String("LIST ") + dir + QLatin1String("\r\n")); return d->addCommand(new QFtpCommand(List, cmds)); } /*! Changes the working directory of the server to \a dir. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::cd(const QString &dir) { return d->addCommand(new QFtpCommand(Cd, QStringList(QLatin1String("CWD ") + dir + QLatin1String("\r\n")))); } /*! Downloads the file \a file from the server. If \a dev is 0, then the readyRead() signal is emitted when there is data available to read. You can then read the data with the read() or readAll() functions. If \a dev is not 0, the data is written directly to the device \a dev. Make sure that the \a dev pointer is valid for the duration of the operation (it is safe to delete it when the commandFinished() signal is emitted). In this case the readyRead() signal is \e not emitted and you cannot read data with the read() or readAll() functions. If you don't read the data immediately it becomes available, i.e. when the readyRead() signal is emitted, it is still available until the next command is started. For example, if you want to present the data to the user as soon as there is something available, connect to the readyRead() signal and read the data immediately. On the other hand, if you only want to work with the complete data, you can connect to the commandFinished() signal and read the data when the get() command is finished. The data is transferred as Binary or Ascii depending on the value of \a type. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa readyRead() dataTransferProgress() commandStarted() commandFinished() */ int QFtp::get(const QString &file, QIODevice *dev, TransferType type) { QStringList cmds; if (type == Binary) cmds << QLatin1String("TYPE I\r\n"); else cmds << QLatin1String("TYPE A\r\n"); cmds << QLatin1String("SIZE ") + file + QLatin1String("\r\n"); cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); cmds << QLatin1String("RETR ") + file + QLatin1String("\r\n"); return d->addCommand(new QFtpCommand(Get, cmds, dev)); } /*! \overload Writes a copy of the given \a data to the file called \a file on the server. The progress of the upload is reported by the dataTransferProgress() signal. The data is transferred as Binary or Ascii depending on the value of \a type. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. Since this function takes a copy of the \a data, you can discard your own copy when this function returns. \sa dataTransferProgress() commandStarted() commandFinished() */ int QFtp::put(const QByteArray &data, const QString &file, TransferType type) { QStringList cmds; if (type == Binary) cmds << QLatin1String("TYPE I\r\n"); else cmds << QLatin1String("TYPE A\r\n"); cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); cmds << QLatin1String("ALLO ") + QString::number(data.size()) + QLatin1String("\r\n"); cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n"); return d->addCommand(new QFtpCommand(Put, cmds, data)); } /*! Reads the data from the IO device \a dev, and writes it to the file called \a file on the server. The data is read in chunks from the IO device, so this overload allows you to transmit large amounts of data without the need to read all the data into memory at once. The data is transferred as Binary or Ascii depending on the value of \a type. Make sure that the \a dev pointer is valid for the duration of the operation (it is safe to delete it when the commandFinished() is emitted). */ int QFtp::put(QIODevice *dev, const QString &file, TransferType type) { QStringList cmds; if (type == Binary) cmds << QLatin1String("TYPE I\r\n"); else cmds << QLatin1String("TYPE A\r\n"); cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); if (!dev->isSequential()) cmds << QLatin1String("ALLO ") + QString::number(dev->size()) + QLatin1String("\r\n"); cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n"); return d->addCommand(new QFtpCommand(Put, cmds, dev)); } /*! Deletes the file called \a file from the server. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::remove(const QString &file) { return d->addCommand(new QFtpCommand(Remove, QStringList(QLatin1String("DELE ") + file + QLatin1String("\r\n")))); } /*! Creates a directory called \a dir on the server. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::mkdir(const QString &dir) { return d->addCommand(new QFtpCommand(Mkdir, QStringList(QLatin1String("MKD ") + dir + QLatin1String("\r\n")))); } /*! Removes the directory called \a dir from the server. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::rmdir(const QString &dir) { return d->addCommand(new QFtpCommand(Rmdir, QStringList(QLatin1String("RMD ") + dir + QLatin1String("\r\n")))); } /*! Renames the file called \a oldname to \a newname on the server. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa commandStarted() commandFinished() */ int QFtp::rename(const QString &oldname, const QString &newname) { QStringList cmds; cmds << QLatin1String("RNFR ") + oldname + QLatin1String("\r\n"); cmds << QLatin1String("RNTO ") + newname + QLatin1String("\r\n"); return d->addCommand(new QFtpCommand(Rename, cmds)); } /*! Sends the raw FTP command \a command to the FTP server. This is useful for low-level FTP access. If the operation you wish to perform has an equivalent QFtp function, we recommend using the function instead of raw FTP commands since the functions are easier and safer. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. \sa rawCommandReply() commandStarted() commandFinished() */ int QFtp::rawCommand(const QString &command) { QString cmd = command.trimmed() + QLatin1String("\r\n"); return d->addCommand(new QFtpCommand(RawCommand, QStringList(cmd))); } /*! Returns the number of bytes that can be read from the data socket at the moment. \sa get() readyRead() read() readAll() */ qint64 QFtp::bytesAvailable() const { return d->pi.dtp.bytesAvailable(); } /*! \fn qint64 QFtp::readBlock(char *data, quint64 maxlen) Use read() instead. */ /*! Reads \a maxlen bytes from the data socket into \a data and returns the number of bytes read. Returns -1 if an error occurred. \sa get() readyRead() bytesAvailable() readAll() */ qint64 QFtp::read(char *data, qint64 maxlen) { return d->pi.dtp.read(data, maxlen); } /*! Reads all the bytes available from the data socket and returns them. \sa get() readyRead() bytesAvailable() read() */ QByteArray QFtp::readAll() { return d->pi.dtp.readAll(); } /*! Aborts the current command and deletes all scheduled commands. If there is an unfinished command (i.e. a command for which the commandStarted() signal has been emitted, but for which the commandFinished() signal has not been emitted), this function sends an \c ABORT command to the server. When the server replies that the command is aborted, the commandFinished() signal with the \c error argument set to \c true is emitted for the command. Due to timing issues, it is possible that the command had already finished before the abort request reached the server, in which case, the commandFinished() signal is emitted with the \c error argument set to \c false. For all other commands that are affected by the abort(), no signals are emitted. If you don't start further FTP commands directly after the abort(), there won't be any scheduled commands and the done() signal is emitted. \warning Some FTP servers, for example the BSD FTP daemon (version 0.3), wrongly return a positive reply even when an abort has occurred. For these servers the commandFinished() signal has its error flag set to \c false, even though the command did not complete successfully. \sa clearPendingCommands() */ void QFtp::abort() { if (d->pending.isEmpty()) return; clearPendingCommands(); d->pi.abort(); } /*! Returns the identifier of the FTP command that is being executed or 0 if there is no command being executed. \sa currentCommand() */ int QFtp::currentId() const { if (d->pending.isEmpty()) return 0; return d->pending.first()->id; } /*! Returns the command type of the FTP command being executed or \c None if there is no command being executed. \sa currentId() */ QFtp::Command QFtp::currentCommand() const { if (d->pending.isEmpty()) return None; return d->pending.first()->command; } /*! Returns the QIODevice pointer that is used by the FTP command to read data from or store data to. If there is no current FTP command being executed or if the command does not use an IO device, this function returns 0. This function can be used to delete the QIODevice in the slot connected to the commandFinished() signal. \sa get() put() */ QIODevice* QFtp::currentDevice() const { if (d->pending.isEmpty()) return 0; QFtpCommand *c = d->pending.first(); if (c->is_ba) return 0; return c->data.dev; } /*! Returns true if there are any commands scheduled that have not yet been executed; otherwise returns false. The command that is being executed is \e not considered as a scheduled command. \sa clearPendingCommands() currentId() currentCommand() */ bool QFtp::hasPendingCommands() const { return d->pending.count() > 1; } /*! Deletes all pending commands from the list of scheduled commands. This does not affect the command that is being executed. If you want to stop this as well, use abort(). \sa hasPendingCommands() abort() */ void QFtp::clearPendingCommands() { // delete all entires except the first one while (d->pending.count() > 1) delete d->pending.takeLast(); } /*! Returns the current state of the object. When the state changes, the stateChanged() signal is emitted. \sa State stateChanged() */ QFtp::State QFtp::state() const { return d->state; } /*! Returns the last error that occurred. This is useful to find out what went wrong when receiving a commandFinished() or a done() signal with the \c error argument set to \c true. If you start a new command, the error status is reset to \c NoError. */ QFtp::Error QFtp::error() const { return d->error; } /*! Returns a human-readable description of the last error that occurred. This is useful for presenting a error message to the user when receiving a commandFinished() or a done() signal with the \c error argument set to \c true. The error string is often (but not always) the reply from the server, so it is not always possible to translate the string. If the message comes from Qt, the string has already passed through tr(). */ QString QFtp::errorString() const { return d->errorString; } /*! \internal */ void QFtpPrivate::_q_startNextCommand() { Q_Q(QFtp); if (pending.isEmpty()) return; QFtpCommand *c = pending.first(); error = QFtp::NoError; errorString = QT_TRANSLATE_NOOP(QFtp, QLatin1String("Unknown error")); if (q->bytesAvailable()) q->readAll(); // clear the data emit q->commandStarted(c->id); // Proxy support, replace the Login argument in place, then fall // through. if (c->command == QFtp::Login && !proxyHost.isEmpty()) { QString loginString = c->rawCmds.first().trimmed(); loginString += QLatin1Char('@') + host; if (port && port != 21) loginString += QLatin1Char(':') + QString::number(port); loginString += QLatin1String("\r\n"); c->rawCmds[0] = loginString; } if (c->command == QFtp::SetTransferMode) { _q_piFinished(QLatin1String("Transfer mode set")); } else if (c->command == QFtp::SetProxy) { proxyHost = c->rawCmds[0]; proxyPort = c->rawCmds[1].toUInt(); c->rawCmds.clear(); _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort)); } else if (c->command == QFtp::ConnectToHost) { #ifndef QT_NO_BEARERMANAGEMENT //copy network session down to the PI pi.setProperty("_q_networksession", q->property("_q_networksession")); #endif if (!proxyHost.isEmpty()) { host = c->rawCmds[0]; port = c->rawCmds[1].toUInt(); pi.connectToHost(proxyHost, proxyPort); } else { pi.connectToHost(c->rawCmds[0], c->rawCmds[1].toUInt()); } } else { if (c->command == QFtp::Put) { if (c->is_ba) { pi.dtp.setData(c->data.ba); pi.dtp.setBytesTotal(c->data.ba->size()); } else if (c->data.dev && (c->data.dev->isOpen() || c->data.dev->open(QIODevice::ReadOnly))) { pi.dtp.setDevice(c->data.dev); if (c->data.dev->isSequential()) { pi.dtp.setBytesTotal(0); pi.dtp.connect(c->data.dev, SIGNAL(readyRead()), SLOT(dataReadyRead())); pi.dtp.connect(c->data.dev, SIGNAL(readChannelFinished()), SLOT(dataReadyRead())); } else { pi.dtp.setBytesTotal(c->data.dev->size()); } } } else if (c->command == QFtp::Get) { if (!c->is_ba && c->data.dev) { pi.dtp.setDevice(c->data.dev); } } else if (c->command == QFtp::Close) { state = QFtp::Closing; emit q->stateChanged(state); } pi.sendCommands(c->rawCmds); } } /*! \internal */ void QFtpPrivate::_q_piFinished(const QString&) { if (pending.isEmpty()) return; QFtpCommand *c = pending.first(); if (c->command == QFtp::Close) { // The order of in which the slots are called is arbitrary, so // disconnect the SIGNAL-SIGNAL temporary to make sure that we // don't get the commandFinished() signal before the stateChanged() // signal. if (state != QFtp::Unconnected) { close_waitForStateChange = true; return; } } emit q_func()->commandFinished(c->id, false); pending.removeFirst(); delete c; if (pending.isEmpty()) { emit q_func()->done(false); } else { _q_startNextCommand(); } } /*! \internal */ void QFtpPrivate::_q_piError(int errorCode, const QString &text) { Q_Q(QFtp); if (pending.isEmpty()) { qWarning("QFtpPrivate::_q_piError was called without pending command!"); return; } QFtpCommand *c = pending.first(); // non-fatal errors if (c->command == QFtp::Get && pi.currentCommand().startsWith(QLatin1String("SIZE "))) { pi.dtp.setBytesTotal(0); return; } else if (c->command==QFtp::Put && pi.currentCommand().startsWith(QLatin1String("ALLO "))) { return; } error = QFtp::Error(errorCode); switch (q->currentCommand()) { case QFtp::ConnectToHost: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Connecting to host failed:\n%1")) .arg(text); break; case QFtp::Login: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Login failed:\n%1")) .arg(text); break; case QFtp::List: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Listing directory failed:\n%1")) .arg(text); break; case QFtp::Cd: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Changing directory failed:\n%1")) .arg(text); break; case QFtp::Get: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Downloading file failed:\n%1")) .arg(text); break; case QFtp::Put: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Uploading file failed:\n%1")) .arg(text); break; case QFtp::Remove: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing file failed:\n%1")) .arg(text); break; case QFtp::Mkdir: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Creating directory failed:\n%1")) .arg(text); break; case QFtp::Rmdir: errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing directory failed:\n%1")) .arg(text); break; default: errorString = text; break; } pi.clearPendingCommands(); q->clearPendingCommands(); emit q->commandFinished(c->id, true); pending.removeFirst(); delete c; if (pending.isEmpty()) emit q->done(true); else _q_startNextCommand(); } /*! \internal */ void QFtpPrivate::_q_piConnectState(int connectState) { state = QFtp::State(connectState); emit q_func()->stateChanged(state); if (close_waitForStateChange) { close_waitForStateChange = false; _q_piFinished(QLatin1String(QT_TRANSLATE_NOOP("QFtp", "Connection closed"))); } } /*! \internal */ void QFtpPrivate::_q_piFtpReply(int code, const QString &text) { if (q_func()->currentCommand() == QFtp::RawCommand) { pi.rawCommand = true; emit q_func()->rawCommandReply(code, text); } } /*! Destructor. */ QFtp::~QFtp() { abort(); close(); } QT_END_NAMESPACE #include "qftp.moc" #include "moc_qftp.cpp" #endif // QT_NO_FTP #endif // QT_VERSION qsstv_8.2.12/qsstv/videocapt/videocapture.cpp000664 001750 001750 00000045766 12440612574 021351 0ustar00jomajoma000000 000000 /* * videoCapture.cpp -- Kapture * * Copyright (C) 2006-2009 * Detlev Casanova (detlev.casanova@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ #define DEBUG #include "videocapture.h" #include "configparams.h" #include "qsstvglobal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CLIP(x) ( (x)>=0xFF ? 0xFF : ( (x) <= 0x00 ? 0x00 : (x) ) ) videoCapture::videoCapture() { dev = 0; opened = false; allocated = false; localImage=NULL; numBuffers=2; } videoCapture::~videoCapture() { if(localImage!=NULL) delete localImage; close(); } void videoCapture::close() { if(!opened) return; ::close(dev); opened = false; allocated = false; } bool videoCapture::open() { struct v4l2_capability cap; int ret; if (opened) return true; addToLog("opening Videocapture device",LOGCAM); dev = ::open(videoDevice.toLatin1().data(), O_RDWR); if (dev < 0) { addToLog(QString("Error opening %1, %2").arg(videoDevice).arg(errno),LOGCAM); return false; } memset(&cap, 0, sizeof cap); ret = ioctl(dev, VIDIOC_QUERYCAP, &cap); if (ret < 0) { addToLog(QString("Error querying capabilities for %1, %2").arg(videoDevice).arg(errno),LOGCAM); return false; } dumpCaps(cap); if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { addToLog(QString("Error checking caps for %1").arg(videoDevice),LOGCAM); return false; } formatList=getFormatList(descripList); getFormat(); setFormat(currentWidth(), currentHeight(), currentPixelFormat()); sizeList=getSizesList(); //Allocate buffers if (!allocated) { memset(&rb, 0, sizeof rb); rb.count = numBuffers; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rb.memory = V4L2_MEMORY_MMAP; ret = ioctl(dev, VIDIOC_REQBUFS, &rb); if (ret < 0) { addToLog(QString("Unable to allocate buffersfor %1, %2").arg(videoDevice).arg(errno),LOGCAM); return false; } allocated = true; } opened = true; return true; } QList videoCapture::getFormatList(QList &description) const { QList formatList; int ret; struct v4l2_fmtdesc fmtList; addToLog("getFomatList()",LOGCAM); memset(&fmtList, 0, sizeof fmtList); fmtList.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int i = 0; do { fmtList.index = i; if ((ret = ioctl(dev, VIDIOC_ENUM_FMT, &fmtList)) < 0) break; else { formatList.append((int)fmtList.pixelformat); description.append((char*)fmtList.description); } i++; } while (ret != EINVAL); return formatList; } QList videoCapture::getSizesList() const { int i = 0; QList rSizes; QSize tmp; #ifdef V4L2_CAP_VIDEO_OUTPUT_OVERLAY // sort of test for v4l2 if this one does not exist, v4l2_frmsizeenum will not exist struct v4l2_frmsizeenum sizes; addToLog("getSizesList()",LOGCAM); memset(&sizes, 0, sizeof sizes); sizes.pixel_format = currentPixelFormat(); sizes.index = i; while(ioctl(dev, VIDIOC_ENUM_FRAMESIZES, &sizes) != -1) { tmp.setWidth((int)sizes.discrete.width); tmp.setHeight((int)sizes.discrete.height); rSizes.append(tmp); i++; sizes.index = i; } #else tmp.setWidth(320); tmp.setHeight(240); rSizes.append(tmp); #endif return rSizes; } bool videoCapture::setFormat(unsigned int width, unsigned int height, int pixelformat) { addToLog("setFormat",LOGCAM); memset(&fmt, 0, sizeof fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = width; fmt.fmt.pix.height = height; fmt.fmt.pix.field = V4L2_FIELD_ANY; fmt.fmt.pix.pixelformat = pixelformat; if (ioctl(dev, VIDIOC_S_FMT, &fmt) < 0) { addToLog(QString("Error while setting format , %1").arg(strerror(errno)),LOGCAM); return false; } return true; } bool videoCapture::getFormat() { addToLog("getFormat",LOGCAM); memset(&fmt, 0, sizeof fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(dev, VIDIOC_G_FMT, &fmt) < 0) { addToLog(QString("Error while getting format , %1").arg(errno),LOGCAM); return false; } return true; } bool videoCapture::getFrame() { int ret = 0; // addToLog("getFrame",LOGCAM); // Dequeue a buffer. ret = ioctl(dev, VIDIOC_DQBUF, &buf); //addToLog(QString("Dequeue buffer %1").arg(buf.index),LOGCAM); if (ret < 0) { addToLog(QString("Unable to dequeue buffer , %1").arg(strerror(errno)),LOGCAM); return false; } // while(ioctl(dev, VIDIOC_DQBUF, &buf)<0) // { // qApp->processEvents(); // } // Save the image. if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { addToLog(QString("Unsupported MJPEG Format"),LOGCAM); return false; } if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { YUV422toRGB888_ITU_R(mem[buf.index],currentWidth(), currentHeight()); } // Requeue the buffer. ret = ioctl(dev, VIDIOC_QBUF, &buf); //addToLog(QString("Requeue buffer %1").arg(buf.index),LOGCAM); if (ret < 0) { addToLog(QString("Unable to requeue buffer %1").arg(errno),LOGCAM); return false; } return true; } /** Convert from YUV422 format to RGB888 using ITU_R_FLOAT. Formulae are described on http://en.wikipedia.org/wiki/YUV \param width width of image \param height height of image \param src source \param dst destination */ void videoCapture::YUV422toRGB888_ITU_R( unsigned char *src,int width, int height) { int line, column; unsigned char *py, *pu, *pv; unsigned char r,g,b; QRgb *dst; if (localImage!=NULL) delete localImage; localImage=new QImage( width,height,QImage::Format_RGB32); /* In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. */ py = src; pu = src + 1; pv = src + 3; for (line = 0; line < height; ++line) { dst=(QRgb *)localImage->scanLine(line); for (column = 0; column < width; ++column) // ITU-R float { r = CLIP((double)*py + 1.402*((double)*pv-128.0)); g = CLIP((double)*py - 0.344*((double)*pu-128.0) - 0.714*((double)*pv-128.0)); b = CLIP((double)*py + 1.772*((double)*pu-128.0)); dst[column]=qRgb(r,g,b); // increase py every time py += 2; // increase pu,pv every second time if ((column & 1)==1) { pu += 4; pv += 4; } } } } /** Convert from YUV422 format to RGB888 using NTSC. Formulae are described on http://en.wikipedia.org/wiki/YUV \param width width of image \param height height of image \param src source \param dst destination */ void videoCapture::YUV422toRGB888_NTSC(unsigned char *src,int width, int height) { int line, column; unsigned char *py, *pu, *pv; unsigned char r,g,b; QRgb *dst; if (localImage!=NULL) delete localImage; localImage=new QImage( width,height,QImage::Format_RGB32); /* In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. */ py = src; pu = src + 1; pv = src + 3; for (line = 0; line < height; ++line) { dst=(QRgb *)localImage->scanLine(line); for (column = 0; column < width; ++column) { // NTSC integer r = CLIP( (298*(*py-16) + 409*(*pv-128) + 128) >> 8 ); g = CLIP( (298*(*py-16) - 100*(*pu-128) - 208*(*pv-128) + 128) >> 8 ); b = CLIP( (298*(*py-16) + 516*(*pu-128) + 128) >> 8 ); dst[column]=qRgb(r,g,b); // increase py every time py += 2; // increase pu,pv every second time if ((column & 1)==1) { pu += 4; pv += 4; } } } } int videoCapture::changeCtrl(int ctrl, int value) // an enum for formats and reorganisation would be great... { struct v4l2_queryctrl queryctrl; struct v4l2_control control; if(!opened) // At the begining of the function. { return -1; } /* * ctrl values : * 0 : Saturation * 1 : Power line Frequency (néons) * 2 : Brightness * 3 : Contrast * 4 : Sharpness * 5 : Reset Pan/Tilt */ __u32 CTRL; switch(ctrl) { case Saturation: { CTRL = V4L2_CID_SATURATION; break; } case Brightness: { CTRL = V4L2_CID_BRIGHTNESS; break; } case Hue: { CTRL = V4L2_CID_HUE; break; } case Contrast: { CTRL = V4L2_CID_CONTRAST; break; } //#ifdef V4L2_CID_POWER_LINE_FREQUENCY // case PowerLineFreq: // { // CTRL = V4L2_CID_POWER_LINE_FREQUENCY; // break; // } //#endif case Sharpness: { #ifdef V4L2_CID_SHARPNESS CTRL = V4L2_CID_SHARPNESS; #else CTRL=0; #endif break; } default: CTRL = 0; } memset (&queryctrl, 0, sizeof queryctrl); memset (&control, 0, sizeof control); queryctrl.id = CTRL; if (-1 == ioctl (dev, VIDIOC_QUERYCTRL, &queryctrl)) { if (errno != EINVAL) { #ifdef DEBUG perror ("VIDIOC_QUERYCTRL"); #endif return EXIT_FAILURE; } } else { control.id = CTRL; control.value = value; if (-1 == ioctl (dev, VIDIOC_S_CTRL, &control)) { #ifdef DEBUG perror("VIDIOC_S_CTRL"); printf(" * Error while setting control\n"); #endif return EXIT_FAILURE; } } return EXIT_SUCCESS; } int videoCapture::currentWidth() const { return (int) fmt.fmt.pix.width; } int videoCapture::currentHeight() const { return (int) fmt.fmt.pix.height; } int videoCapture::currentPixelFormat() const { return (int) fmt.fmt.pix.pixelformat; } int videoCapture::defaultCtrlVal(unsigned int control, int &defaultValue) { struct v4l2_queryctrl queryctrl; QString ctrl; if(!opened) { return false; } memset(&queryctrl, 0, sizeof queryctrl); switch(control) { case Saturation : { ctrl = "Saturation"; queryctrl.id = V4L2_CID_SATURATION; break; } case Brightness : { ctrl = "Brightness"; queryctrl.id = V4L2_CID_BRIGHTNESS; break; } case Hue : { ctrl = "Hue"; queryctrl.id = V4L2_CID_HUE; break; } case Contrast : { ctrl = "Contrast"; queryctrl.id = V4L2_CID_CONTRAST; break; } // case PowerLineFreq : // { // ctrl = "Powerline Frequecy"; // queryctrl.id = V4L2_CID_POWER_LINE_FREQUENCY; // break; // } case Sharpness : { ctrl = "Sharpness"; #ifdef V4L2_CID_SHARPNESS queryctrl.id = V4L2_CID_SHARPNESS; #endif break; } default : ctrl = "ERROR"; } QString str; if (-1 == ioctl(dev, VIDIOC_QUERYCTRL, &queryctrl)) { addToLog(QString("Unable to set control %1, %2").arg(ctrl).arg(errno),LOGCAM); return false; } defaultValue = (int)queryctrl.default_value; return true; } //bool videoCapture::panTiltSupported() //{ // struct v4l2_queryctrl queryctrl; // if(!opened) return false; // memset(&queryctrl, 0, sizeof queryctrl); // queryctrl.id = V4L2_CID_TILT_RELATIVE; // Could be V4L2_CID_PAN_RELATIVE. // if (ioctl(dev, VIDIOC_QUERYCTRL, &queryctrl)<0) // { // addToLog(QString("Unable to check wether Pan Tilt is supported, %1").arg(errno),LOGCAM); // return false; // } // if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) // { // addToLog("Pan & Tilt not supported."),LOGCAM); // return false; //FLAG_NOT_SUPPORTED; // } // return true; //} //void videoCapture::turnRight() //{ //#ifdef V4L2_CID_PAN_RELATIVE // struct v4l2_queryctrl queryctrl; // struct v4l2_control control; // memset (&queryctrl, 0, sizeof queryctrl); // memset (&control, 0, sizeof control); // queryctrl.id = V4L2_CID_PAN_RELATIVE; // if (-1 == ioctl (dev, VIDIOC_QUERYCTRL, &queryctrl)) // { // if (errno != EINVAL) // { // perror ("VIDIOC_QUERYCTRL"); // return; // } // } else // { // control.id = V4L2_CID_PAN_RELATIVE; // control.value = -320; // if (-1 == ioctl (dev, VIDIOC_S_CTRL, &control)) { // perror("VIDIOC_S_CTRL"); // return; // } // } //#endif //} //void videoCapture::turnLeft() //{ //#ifdef V4L2_CID_PAN_RELATIVE // struct v4l2_queryctrl queryctrl; // struct v4l2_control control; // memset (&queryctrl, 0, sizeof queryctrl); // memset (&control, 0, sizeof control); // queryctrl.id = V4L2_CID_PAN_RELATIVE; // if (-1 == ioctl (dev, VIDIOC_QUERYCTRL, &queryctrl)) // { // if (errno != EINVAL) // { // perror ("VIDIOC_QUERYCTRL"); // return; // } // } else // { // control.id = V4L2_CID_PAN_RELATIVE; // control.value = 320; // if (-1 == ioctl (dev, VIDIOC_S_CTRL, &control)) { // perror("VIDIOC_S_CTRL"); // return; // } // } //#endif //} //void videoCapture::turnUp() //{ //#ifdef V4L2_CID_TILT_RELATIVE // struct v4l2_queryctrl queryctrl; // struct v4l2_control control; // memset (&queryctrl, 0, sizeof queryctrl); // memset (&control, 0, sizeof control); // queryctrl.id = V4L2_CID_TILT_RELATIVE; // if (-1 == ioctl (dev, VIDIOC_QUERYCTRL, &queryctrl)) // { // if (errno != EINVAL) // { // perror ("VIDIOC_QUERYCTRL"); // return; // } // } else // { // control.id = V4L2_CID_TILT_RELATIVE; // control.value = -320; // if (-1 == ioctl (dev, VIDIOC_S_CTRL, &control)) { // perror("VIDIOC_S_CTRL"); // return; // } // } //#endif //} //void videoCapture::turnDown() //{ //#ifdef V4L2_CID_TILT_RELATIVE // struct v4l2_queryctrl queryctrl; // struct v4l2_control control; // memset (&queryctrl, 0, sizeof queryctrl); // memset (&control, 0, sizeof control); // queryctrl.id = V4L2_CID_TILT_RELATIVE; // if (-1 == ioctl (dev, VIDIOC_QUERYCTRL, &queryctrl)) // { // if (errno != EINVAL) // { // perror ("VIDIOC_QUERYCTRL"); // return; // } // } else // { // control.id = V4L2_CID_TILT_RELATIVE; // control.value = 320; // if (-1 == ioctl (dev, VIDIOC_S_CTRL, &control)) { // perror("VIDIOC_S_CTRL"); // return; // } // } //#endif //} bool videoCapture::captureStop() { int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int ret; if(!streaming) return false; ret = ioctl(dev, VIDIOC_STREAMOFF, &type); if (ret < 0) { addToLog(QString("Unable to stop capture, %1").arg(errno),LOGCAM); return false; } streaming = false; return true; } bool videoCapture::captureStart() { int i, ret; if (!opened) return false; abortCap=false; addToLog("captureStart",LOGCAM); // if ((ret = setFormat(currentWidth(), currentHeight(), currentPixelFormat())) != 0) // { // addToLog(QString("Set format error : %1").arg(ret),LOGCAM); // return false; // } ////Allocate buffers // if (!allocated) // { // memset(&rb, 0, sizeof rb); // rb.count = 2; // rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // rb.memory = V4L2_MEMORY_MMAP; // ret = ioctl(dev, VIDIOC_REQBUFS, &rb); // if (ret < 0) // { // addToLog(QString("Unable to allocate buffers %1").arg(ret),LOGCAM); // return false; // } // allocated = true; // } // Map the buffers. memset(&buf, 0, sizeof buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; for (i = 0; i < numBuffers; i++) { buf.index = i; ret = ioctl(dev, VIDIOC_QUERYBUF, &buf); if (ret < 0) { addToLog(QString("Unable to query buffer %1").arg(ret),LOGCAM); return false; } mem[i] = (uchar *) mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, dev, buf.m.offset); if (mem[i] == MAP_FAILED) { addToLog(QString("Unable to map buffers %1").arg(ret),LOGCAM); return false; } bufLength = buf.length; mmaped = true; } // Queue the buffers for (i = 0; i < numBuffers; i++) { buf.index = i; ret = ioctl(dev, VIDIOC_QBUF, &buf); if (ret < 0) { addToLog(QString("Unable to queue buffer %1").arg(errno),LOGCAM); return false; } } // Start streaming. ret = ioctl(dev, VIDIOC_STREAMON, &buf.type); if (ret < 0) { addToLog(QString("Unable to start capture %1").arg(errno),LOGCAM); return false; } streaming = true; return true; } bool videoCapture::stopStreaming() { if(!streaming) return false; if (munmap(mem[0], bufLength) == -1) { addToLog(QString("videoCapture::stopStreaming : munmap 0 failed. errno = %1").arg(errno),LOGCAM); } if (munmap(mem[1], bufLength) == -1) { addToLog(QString("videoCapture::stopStreaming : munmap 1 failed. errno = %1").arg(errno),LOGCAM); } if (munmap(mem[2], bufLength) == -1) { addToLog(QString("videoCapture::stopStreaming : munmap 2 failed. errno = %1").arg(errno),LOGCAM); } if (munmap(mem[3], bufLength) == -1) { addToLog(QString("videoCapture::stopStreaming : munmap 3 failed. errno = %1").arg(errno),LOGCAM); } else mmaped = false; if(captureStop() == 0) { streaming = false; addToLog(" * Succesful Stopped",LOGCAM); } return true; } bool videoCapture::takeSnapshot() { if(!open()) return false; if(!captureStart()) return false; if(!getFrame()) return false; // first frame always corrupted if(!getFrame()) return false; return stopStreaming(); } bool videoCapture::startSnapshots() { if(!open()) return false; if(!captureStart()) return false; return true; } void videoCapture::dumpCaps(v4l2_capability &cap) { if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) addToLog("The device supports the Video Capture interface",LOGCAM); if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) addToLog("The device supports the Video Output interface",LOGCAM); if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) addToLog("The device supports the Video Overlay interface",LOGCAM); if (cap.capabilities & V4L2_CAP_VBI_CAPTURE) addToLog("The device supports the Raw VBI Capture interface",LOGCAM); if (cap.capabilities & V4L2_CAP_VBI_OUTPUT) addToLog("The device supports the Raw VBI Output interface",LOGCAM); if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) addToLog("The device supports the Sliced VBI Capture interface",LOGCAM); if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) addToLog("The device supports the Sliced VBI Output interface",LOGCAM); if (cap.capabilities & V4L2_CAP_RDS_CAPTURE) addToLog("[to be defined]",LOGCAM); #ifdef V4L2_CAP_VIDEO_OUTPUT_OVERLAY if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) addToLog("The device supports the Video Output Overlay (OSD) interface",LOGCAM); #endif if (cap.capabilities & V4L2_CAP_TUNER) addToLog("The device has some sort of tuner or modulator",LOGCAM); if (cap.capabilities & V4L2_CAP_AUDIO) addToLog("The device has audio inputs or outputs.",LOGCAM); if (cap.capabilities & V4L2_CAP_READWRITE) addToLog("The device supports the read() and/or write() I/O methods.",LOGCAM); if (cap.capabilities & V4L2_CAP_ASYNCIO) addToLog("The device supports the asynchronous I/O methods.",LOGCAM); if (cap.capabilities & V4L2_CAP_STREAMING) addToLog("The device supports the streaming I/O method.",LOGCAM); } qsstv_8.2.12/qsstv/videocapt/videocapture.h000664 001750 001750 00000004145 12440612574 021000 0ustar00jomajoma000000 000000 /* * videoCapture.h -- Kapture * * Copyright (C) 2006-2007 * Detlev Casanova (detlev.casanova@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * */ #ifndef _VIDEOCAPTURE_H #define _VIDEOCAPTURE_H #include #include #include #include "qsstvdefs.h" struct tableFormat { QString description; unsigned int val1; unsigned int val2; }; extern tableFormat sizeList[]; extern tableFormat fpsList[]; enum ecamSize{PICMAX,PICMIN,PICHALF}; class videoCapture : public QObject { Q_OBJECT public: videoCapture(); ~videoCapture(); void close(); bool open(); QList getFormatList(QList &description) const; QList getSizesList() const; QList formatList; QList sizeList; QList descripList; bool setFormat(unsigned int width, unsigned int height, int pixelformat=V4L2_PIX_FMT_MJPEG); bool getFormat(); bool getFrame(); int currentWidth() const; int currentHeight() const; int currentPixelFormat() const; int changeCtrl(int ctrl, int value = 0); int defaultCtrlVal(unsigned int control, int &defaultValue); bool isOpened() const {return opened;}; bool takeSnapshot(); QImage *getImage() {return localImage;} bool captureStart(); bool captureStop(); bool stopStreaming(); bool startSnapshots(); void abortCapture() { abortCap=true;} enum econtrol {Saturation = 0,Hue,Brightness,Contrast,Sharpness}; signals: void imageReady(); private: int dev; v4l2_format fmt; v4l2_buffer buf; v4l2_requestbuffers rb; bool allocated; uchar *mem[4]; size_t bufLength; QImage *localImage; bool opened; bool mmaped; void YUV422toRGB888_ITU_R( unsigned char *src,int width, int height); void YUV422toRGB888_NTSC( unsigned char *src,int width, int height); bool streaming; void dumpCaps(v4l2_capability &cap); int numBuffers; bool abortCap; }; #endif qsstv_8.2.12/qsstv/widgets/blockview.cpp000664 001750 001750 00000002023 12440612574 020307 0ustar00jomajoma000000 000000 #include "blockview.h" #include "ui_blockview.h" #include blockView::blockView(QWidget *parent) : QFrame(parent), ui(new Ui::blockView) { maxBlocks=40; colFail=QColor(Qt::red); colOK=QColor(Qt::green); ui->setupUi(this); } blockView::~blockView() { delete ui; } void blockView::paintEvent(QPaintEvent *) { int i; QRectF rct; QPainter painter(this); painter.setPen(QPen(colFail, 1, Qt::SolidLine)); painter.setBrush(QBrush(colFail)); painter.setRenderHint(QPainter::Antialiasing); rct=QRectF(0,0,maxBlocks-1,30); painter.setWindow(0, 0, maxBlocks-1,30); painter.drawRect(rct); painter.setPen(QPen(colOK, 1, Qt::SolidLine)); for(i=0;i blkList) { blockList=blkList; // update(); } qsstv_8.2.12/qsstv/widgets/blockview.h000664 001750 001750 00000001107 12440612574 017756 0ustar00jomajoma000000 000000 #ifndef BLOCKVIEW_H #define BLOCKVIEW_H #include namespace Ui { class blockView; } class blockView : public QFrame { Q_OBJECT public: explicit blockView(QWidget *parent = 0); ~blockView(); void setColorFail(QColor color); void setColorOK(QColor color); void setMaxBlocks(int mb) {maxBlocks=mb;} void setBlocks(QList blkList); protected: void paintEvent(QPaintEvent *); private: Ui::blockView *ui; QColor colFail; QColor colOK; QList blockList; short int maxBlocks; }; #endif // BLOCKVIEW_H qsstv_8.2.12/qsstv/widgets/blockview.ui000664 001750 001750 00000001137 12440612574 020147 0ustar00jomajoma000000 000000 blockView 0 0 414 192 Frame QFrame::StyledPanel QFrame::Sunken 3 qsstv_8.2.12/qsstv/widgets/cameracontrol.cpp000664 001750 001750 00000006744 12440612574 021171 0ustar00jomajoma000000 000000 #include "cameracontrol.h" #include "qsstvglobal.h" #include "videocapt/videocapture.h" #include "ui_cameracontrol.h" #include "utils/supportfunctions.h" #include #include cameraControl::cameraControl(QWidget *parent) : QDialog(parent), ui(new Ui::cameraControl) { ui->setupUi(this); camera=new videoCapture; readSettings(); } cameraControl::~cameraControl() { camera->close(); delete camera; writeSettings(); delete ui; } void cameraControl::readSettings() { QSettings qSettings; qSettings.beginGroup("Capture"); brightness=qSettings.value("brightness",128).toInt(); hue=qSettings.value("hue",0).toInt(); saturation=qSettings.value("saturation",128).toInt(); contrast=qSettings.value("contrast",128).toInt(); sharpness=qSettings.value("sharpness",128).toInt(); qSettings.endGroup(); setParams(); cameraActive=camera->open(); slotBrightnessSliderChanged(); slotHueSliderChanged(); slotSaturationSliderChanged(); slotContrastSliderChanged(); slotSharpnessSliderChanged(); connect(ui->brightnessSlider,SIGNAL(valueChanged(int)),SLOT(slotBrightnessSliderChanged())); connect(ui->hueSlider,SIGNAL(valueChanged(int)),SLOT(slotHueSliderChanged())); connect(ui->saturationSlider,SIGNAL(valueChanged(int)),SLOT(slotSaturationSliderChanged())); connect(ui->contrastSlider,SIGNAL(valueChanged(int)),SLOT(slotContrastSliderChanged())); connect(ui->sharpnessSlider,SIGNAL(valueChanged(int)),SLOT(slotSharpnessSliderChanged())); } void cameraControl::writeSettings() { getParams(); QSettings qSettings; qSettings.beginGroup("Capture"); qSettings.setValue( "brightness",brightness); qSettings.setValue( "hue",hue); qSettings.setValue( "saturation",saturation); qSettings.setValue( "contrast",contrast); qSettings.setValue( "sharpness",sharpness); qSettings.endGroup(); } void cameraControl::getParams() { getValue(brightness,ui->brightnessSlider); getValue(hue,ui->hueSlider); getValue(saturation,ui->saturationSlider); getValue(contrast,ui->contrastSlider); getValue(sharpness,ui->sharpnessSlider); } void cameraControl::setParams() { setValue(brightness,ui->brightnessSlider); setValue(hue,ui->hueSlider); setValue(saturation,ui->saturationSlider); setValue(contrast,ui->contrastSlider); setValue(sharpness,ui->sharpnessSlider); } int cameraControl::exec() { if(!cameraActive) return false; int timerID; int result; addToLog("cameracontrol exec",LOGCAM); camera->startSnapshots(); timerID=startTimer(50); result=QDialog::exec(); killTimer(timerID); camera->abortCapture(); camera->stopStreaming(); if(result==QDialog::Accepted) return true; return false; } void cameraControl::timerEvent(QTimerEvent *) { if(camera->getFrame()) { ui->imageFrame->openImage(*camera->getImage()); } } QImage *cameraControl::getImage() { return camera->getImage(); } void cameraControl::slotBrightnessSliderChanged() { getParams(); camera->changeCtrl(videoCapture::Brightness,brightness); } void cameraControl::slotHueSliderChanged() { getParams(); camera->changeCtrl(videoCapture::Hue,hue); } void cameraControl::slotSaturationSliderChanged() { getParams(); camera->changeCtrl(videoCapture::Saturation,saturation); } void cameraControl::slotContrastSliderChanged() { getParams(); camera->changeCtrl(videoCapture::Contrast,contrast); } void cameraControl::slotSharpnessSliderChanged() { getParams(); camera->changeCtrl(videoCapture::Sharpness,sharpness); } qsstv_8.2.12/qsstv/widgets/cameracontrol.h000664 001750 001750 00000001530 12440612574 020622 0ustar00jomajoma000000 000000 #ifndef CAMERACONTROL_H #define CAMERACONTROL_H #include namespace Ui { class cameraControl; } class videoCapture; class cameraControl : public QDialog { Q_OBJECT public: explicit cameraControl(QWidget *parent = 0); ~cameraControl(); void readSettings(); void writeSettings(); int exec(); QImage *getImage(); private slots: void slotBrightnessSliderChanged(); void slotHueSliderChanged(); void slotSaturationSliderChanged(); void slotContrastSliderChanged(); void slotSharpnessSliderChanged(); private: Ui::cameraControl *ui; void getParams(); void setParams(); bool cameraActive; int brightness; int hue; int saturation; int contrast; int sharpness; videoCapture *camera; void timerEvent(QTimerEvent *event); }; #endif // CAMERACONTROL_H qsstv_8.2.12/qsstv/widgets/cameracontrol.ui000664 001750 001750 00000024104 12440612574 021012 0ustar00jomajoma000000 000000 cameraControl 0 0 230 364 9 Dialog 2 1 QFrame::StyledPanel QFrame::Raised 0 0 100 0 Courier [Xft] 9 75 true Sharpness Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 0 255 1 10 127 Qt::Horizontal 1000 6 0 100 0 Courier [Xft] 9 75 true Brightness Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 255 1 10 127 Qt::Horizontal 1000 6 0 100 0 Courier [Xft] 9 75 true Hue Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 255 1 10 127 Qt::Horizontal 1000 6 0 0 0 100 0 Courier [Xft] 9 75 true Saturation Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 255 1 10 127 Qt::Horizontal 1000 6 0 100 0 Courier [Xft] 9 75 true Contrast Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 0 255 1 10 127 Qt::Horizontal 1000 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok imageViewer QFrame
widgets/imageviewer.h
1
buttonBox accepted() cameraControl accept() 248 254 157 274 buttonBox rejected() cameraControl reject() 316 260 286 274
qsstv_8.2.12/qsstv/widgets/fftdisplay.cpp000664 001750 001750 00000013106 12440612574 020473 0ustar00jomajoma000000 000000 #include "fftdisplay.h" #include "qsstvglobal.h" #include "math.h" #include fftDisplay::fftDisplay(QWidget *parent) : QLabel(parent) { blockIndex=0; arMag=NULL; arMagAvg=NULL; // ready=false; windowWidth=0; windowHeight=0; im=NULL; fftArray=NULL; // windowWidth=294;windowHeight=112; // im=new QImage( windowWidth,windowHeight,QImage::Format_RGB32); setSize(120,180); out=NULL; dataBuffer=NULL; showWaterfall=false; fftMax=FFTMAX; range=RANGE; } fftDisplay::~fftDisplay() { // ready=false; delete im; if(fftArray) delete fftArray; fftw_destroy_plan(plan); if(out) fftw_free(out); if(dataBuffer) fftw_free(dataBuffer); if (arMag) delete [] arMag; if(arMagAvg) delete []arMagAvg; } void fftDisplay::setSize(int w,int h) { windowWidth=w; windowHeight=h; if(w==0 || h==0) { qDebug() << "Null Image"; } if(im) { *im=im->scaled(QSize(windowWidth, windowHeight)); } else { im=new QImage( windowWidth,windowHeight,QImage::Format_RGB32); im->fill(Qt::black); } if(fftArray) delete fftArray; fftArray=new QPolygon(windowWidth); if(arMag) delete []arMag; arMag=new double[windowWidth]; if(arMagAvg) delete []arMagAvg; arMagAvg=new double[windowWidth]; for(int i=0;imax) max=dataBuffer[j]; } doFFT(); } void fftDisplay::realFFT(double *data) { int i,j; for(i=0,j=windowSize*blockIndex;imaxTmp) maxTmp=dataBuffer[i]; } fftw_execute(plan); step=(double)samplingrate/(double)fftLength; //freq step per bin arMag[0]=0; arMagAvg[0]=0; for(i=0;isetPoint(i,i,((windowHeight)*(maxMagnitude-magTmp))/range); } memmove(im->scanLine(1),im->scanLine(0),(windowWidth*(windowHeight-2))*sizeof(uint)); uint *ptr=(uint *)im->scanLine(0); for(i=0;ifftMax) arMag[i]=fftMax; if(arMag[i]1) val=1; // tmp=rint(180*((double)i)/((double)FFTSPAN)); // c.setHsv(240-val*240,255,255); c.setHsv(240-val*60,255,val*255); // c.setRgb(val*255,val*255,val*255); ptr[i]=c.rgb(); // ptr[i]=(uint) val*256+255; } update(); } void fftDisplay::paintEvent(QPaintEvent *p) { QPen pn; // if(!ready) return; QPainter painter(this); // painter.setWindow(0,0,windowWidth,windowHeight); if((windowWidth!=width())||(windowHeight!=height())) { setSize(width(),height()); return; } // painter.setRenderHint(QPainter::Antialiasing); if(!showWaterfall) { pn.setColor(Qt::red); pn.setWidth(1); painter.setPen(pn); painter.drawLine((((marker1-FFTLOW)*windowWidth)/FFTSPAN),0,(((marker1-FFTLOW)*windowWidth)/FFTSPAN),windowHeight); painter.drawLine((((marker2-FFTLOW)*windowWidth)/FFTSPAN),0,(((marker2-FFTLOW)*windowWidth)/FFTSPAN),windowHeight); painter.drawLine((((marker3-FFTLOW)*windowWidth)/FFTSPAN),0,(((marker3-FFTLOW)*windowWidth)/FFTSPAN),windowHeight); pn.setColor(Qt::green); painter.setPen(pn); painter.drawPolyline(*fftArray); } else { painter.drawImage(0,0,*im); } QLabel::paintEvent(p); } void fftDisplay::mousePressEvent( QMouseEvent *e ) { if (e->button() == Qt::LeftButton) { showWaterfall=!showWaterfall; } } qsstv_8.2.12/qsstv/widgets/fftdisplay.h000664 001750 001750 00000002700 12440612574 020136 0ustar00jomajoma000000 000000 #ifndef FFTDISPLAY_H #define FFTDISPLAY_H #include #include #include "qsstvdefs.h" #include "fftw3.h" #include #include #define FFTAVERAGING 0.1 #define VALAVG 0.02 #define FFTHIGH 3000 #define FFTLOW 200 #define FFTSPAN (FFTHIGH-FFTLOW) #define FFTMAX 75. #define RANGE 30. class fftDisplay : public QLabel { Q_OBJECT public: explicit fftDisplay(QWidget *parent=0); ~fftDisplay(); void init(int size,int slices,int isamplingrate); void realFFT(short int *iBuffer); void realFFT(float *iBuffer); void realFFT(double *iBuffer); void setMaxDb(int mb){fftMax=mb;} void setRange(int rg) {range=rg;} void displayWaterfall(bool wf) {showWaterfall=wf;} void setMarkers(int mrk1=0, int mrk2=0, int mrk3=0){ marker1=mrk1;marker2=mrk2;marker3=mrk3;update();} private: void createHamming(); void doFFT(); void paintEvent(QPaintEvent *p); void mousePressEvent( QMouseEvent *e ); double *hammingBuffer; double *dataBuffer; int windowSize; int fftLength; int samplingrate; unsigned int blocks; unsigned int blockIndex; fftw_plan plan; double *arMag; double *arMagAvg; double *out; double maxMagnitude; QPolygon *fftArray; // bool ready; bool showWaterfall; double fftMax; double fftMin; double range; QImage *im; int windowWidth; int windowHeight; void setSize(int w,int h); QMutex mutex; int marker1; int marker2; int marker3; }; #endif // FFTDISPLAY_H qsstv_8.2.12/qsstv/widgets/freqform.ui000664 001750 001750 00000015041 12440612574 020002 0ustar00jomajoma000000 000000 freqForm 0 0 270 139 8 Test Signal 6 11 6 0 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 Frequency false 300 2500 1200 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 Duration (sec) false 1 100 10 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 Qt::Horizontal QSizePolicy::Expanding 20 20 OK Cancel Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Expanding 20 20 qPixmapFromMimeSource okButton clicked() freqForm accept() 20 20 20 20 cancelButton clicked() freqForm reject() 20 20 20 20 qsstv_8.2.12/qsstv/widgets/imageviewer.cpp000664 001750 001750 00000035312 12440612574 020635 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "imageviewer.h" #include "utils/supportfunctions.h" #include "utils/logging.h" #include "configparams.h" #include "dispatcher.h" #include "txwidget.h" #include "utils/qjp2io.h" #include #include #define RATIOSCALE 800. /** \class imageViewer The image is stored in it's original format and size. All interactions are done on the original image. A scaled version is used to display the contents. */ imageViewer::imageViewer(QWidget *parent): QLabel(parent) { addToLog("image creation",LOGIMAG); validImage=false; setFrameStyle(QFrame::Sunken | QFrame::Panel); QBrush b; QPalette palette; b.setTexture(QPixmap::fromImage(QImage(":/icons/transparency.png"))); palette.setBrush(QPalette::Active,QPalette::Base,b); palette.setBrush(QPalette::Inactive,QPalette::Base,b); palette.setBrush(QPalette::Disabled,QPalette::Base,b); setPalette(palette); setBackgroundRole(QPalette::Base); setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); setScaledContents(true); setBackgroundRole(QPalette::Dark); popup=new QMenu (this); newAct = new QAction(tr("&New"),this); connect(newAct, SIGNAL(triggered()), this, SLOT(slotNew())); loadAct = new QAction(tr("&Load"), this); connect(loadAct, SIGNAL(triggered()), this, SLOT(slotLoad())); toTXAct = new QAction(tr("&To TX"), this); connect(toTXAct, SIGNAL(triggered()), this, SLOT(slotToTX())); editAct = new QAction(tr("&Edit"), this); connect(editAct, SIGNAL(triggered()), this, SLOT(slotEdit())); printAct = new QAction(tr("&Print"), this); connect(printAct, SIGNAL(triggered()), this, SLOT(slotPrint())); deleteAct = new QAction(tr("&Delete"), this); connect(deleteAct, SIGNAL(triggered()), this, SLOT(slotDelete())); propertiesAct = new QAction(tr("Propert&ies"), this); connect(propertiesAct, SIGNAL(triggered()), this, SLOT(slotProperties())); popup->addAction(newAct); popup->addAction(loadAct); popup->addAction(toTXAct); popup->addAction(editAct); popup->addAction(printAct); popup->addAction(deleteAct); popup->addAction(propertiesAct); setScaledContents(false); setAlignment(Qt::AlignCenter); setAutoFillBackground(true); QPalette mpalette; mpalette.setColor(QPalette::Window,QColor(0,0,128)); setBackgroundRole(QPalette::Window); mpalette.setColor(QPalette::WindowText, Qt::yellow); setPalette(mpalette); init(RXIMG); activeMovie=false; // } imageViewer::~imageViewer() { } void imageViewer::init(thumbType tp) { setScaledContents(false); setAlignment(Qt::AlignCenter); setAutoFillBackground(true); QPalette mpalette; mpalette.setColor(QPalette::Window,QColor(0,0,128)); setBackgroundRole(QPalette::Window); mpalette.setColor(QPalette::WindowText, Qt::yellow); setPalette(mpalette); addToLog("image creation",LOGIMAG); imageFileName=""; image=QImage(); setType(tp); popupEnabled=true; setPixmap(QPixmap()); clear(); } bool imageViewer::openImage(QString &filename,QString start,bool ask,bool showMessage,bool emitSignal) { QImage tempImage; displayMBoxEvent *stmb=0; editorScene ed; if(activeMovie) { activeMovie=false; qm.stop(); } if (filename.isEmpty()&&!ask) return false; if(ask) { dirDialog dd((QWidget *)this,"Browse"); filename=dd.openFileName(start,"*"); } if(filename.isEmpty()) { imageFileName=""; return false; } if(!tempImage.load(filename)) { QFile fi(filename); // try to load it with the editor, it coud be a template file if(!ed.load(fi)) { //try loading jpg2 tempImage=readJP2Image(filename); if(tempImage.isNull()) { if(showMessage) { stmb= new displayMBoxEvent("Image Loader",QString("Unable to load image:\n%1").arg(filename)); QApplication::postEvent( dispatcherPtr, stmb ); // Qt will delete it when done } validImage=false; imageFileName=""; return false; } } else { tempImage=QImage(ed.renderImage(0,0)->copy()); } } image=tempImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); imageFileName=filename; QFileInfo fi(filename); if (fi.suffix().toLower()=="gif") { //we will try a animated gif qm.setFileName(filename); if(qm.isValid()) { if(qm.frameCount()>1) { activeMovie=true; setMovie(&qm); qm.start(); } } } else { displayImage(false); } validImage=true; if (emitSignal) emit imageChanged(); return true; } bool imageViewer::openImage(QString &filename,bool showMessage,bool emitSignal) { return openImage(filename,"",false,showMessage,emitSignal); } bool imageViewer::openImage(QImage im) { image=im; if(!image.isNull()) { displayImage(false); validImage=true; return true; } validImage=false; return false; } bool imageViewer::openImage(QByteArray *ba) { QImage tempImage; QBuffer buffer(ba); buffer.open(QIODevice::ReadOnly); if(tempImage.load(&buffer,NULL)) { imageFileName=""; validImage=true; image=tempImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); displayImage(false); return true; } validImage=false; return false; } bool imageViewer::hasValidImage() { return validImage; } QImage *imageViewer::createImage(QSize sz,QColor fill) { image=QImage(sz,QImage::Format_ARGB32_Premultiplied); image.fill(fill.rgb()); displayImage(false); emit imageChanged(); return ℑ } void imageViewer::copy(imageViewer *src) { imageFileName=src->imageFileName; ttype=src->ttype; openImage(imageFileName,false,false); } QRgb *imageViewer::getScanLineAddress(int line) { return (QRgb *)image.scanLine(line); } void imageViewer::displayImage(bool useCompression) { QTemporaryFile itmp(QDir::tempPath()+"/qsstvXXXXXX.jp2"); if((image.width()==0) || (image.height()==0)) return; // qDebug()<< "displayImage" << image.width() << image.height() << width() << height(); if(ttype==TXIMG) { // we want to display the image with the defined quality QBuffer buffer; if(useCompression) { if(!itmp.open()) return; writeJP2Image(image.convertToFormat(QImage::Format_RGB32), itmp.fileName(),psizeRatio); compressedImage=readJP2Image(itmp.fileName()); } else { compressedImage=image.copy(); } if(compressedImage.isNull()||width()==0 || height()==0) { return; } if(hasScaledContents()) { setPixmap(QPixmap::fromImage(compressedImage)); } else { // qDebug() << "WxH" << width() << height() << compressedImage.width() << compressedImage.height(); setPixmap(QPixmap::fromImage(compressedImage.scaled(width(),height(),Qt::KeepAspectRatio,Qt::SmoothTransformation))); } } else { if(hasScaledContents()) { setPixmap(QPixmap::fromImage(image)); } else { // qDebug() << "WxH" << width() << height() << image.width() << image.height(); setPixmap(QPixmap::fromImage(image.scaled(width()-2,height()-2,Qt::KeepAspectRatio,Qt::SmoothTransformation))); } } } bool imageViewer::readThumbSettings(QSettings *qs) { qs->beginGroup("Thumbnails"); addToLog(QString("/THUMB/"+objectName()+"/"),LOGIMAG); imageFileName =qs->value(objectName()+"/filename","").toString(); qs->endGroup(); return openImage(imageFileName,false,false); } void imageViewer::writeThumbSettings(QSettings *qs) { qs->beginGroup("Thumbnails"); qs->setValue(objectName()+"/filename",imageFileName); qs->endGroup(); } void imageViewer::setType(thumbType tp) { ttype=tp; switch(tp) { case RXIMG: case RXTHUMB: imageFilePath=rxImagesPath; break; case TXIMG: case TXTHUMB: imageFilePath=txImagesPath; break; case TEMPLATETHUMB: imageFilePath=templatesPath; break; } if((tp==RXTHUMB) || (tp==TXTHUMB) || (tp==TEMPLATETHUMB)) { setScaledContents(true); setAlignment(Qt::AlignCenter); } } void imageViewer::mousePressEvent( QMouseEvent *e ) { QString temp; QString fn; if (e->button() == Qt::RightButton) { if(popupEnabled) { popup->popup(QCursor::pos()); } } } void imageViewer::slotDelete() { if(imageFileName.isEmpty()) return; if(QMessageBox::question(this,"Delete file","Do you want to delete the file and\n move it to the trash folder?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes) { trash(imageFileName,true); } imageFileName=""; emit layoutChanged(); } void imageViewer::slotEdit() { if(imageFileName.isEmpty()) { slotLoad(); if (imageFileName.isEmpty()) return; } callEditorEvent *ce = new callEditorEvent( this,imageFileName ); QApplication::postEvent(dispatcherPtr, ce ); // Qt will delete it when done } void imageViewer::slotLoad() { QString fileNameTmp; dirDialog dd((QWidget *)this,"Browse"); fileNameTmp=dd.openFileName(imageFilePath); if(openImage(fileNameTmp,true,true)) { imageFileName=fileNameTmp; if(ttype==TEMPLATETHUMB) { templatesChangedEvent *ce = new templatesChangedEvent( ); QApplication::postEvent(dispatcherPtr, ce ); // Qt will delete it when done } } } void imageViewer::slotNew() { callEditorEvent *ce = new callEditorEvent( this,NULL); QApplication::postEvent(dispatcherPtr, ce ); // Qt will delete it when done } void imageViewer::slotPrint() { } void imageViewer::slotProperties() { QFileInfo fi(imageFileName); if(fi.exists()) { QMessageBox::information(this,"Image Properties", "File: " + imageFileName + "\n File size: " + QString::number(fi.size()) + "\n Image width: " + QString::number(image.width()) + "\n Image heigth: " + QString::number(image.height()) + "\n Last Modified: " + fi.lastModified().toString() ,QMessageBox::Ok); } else { QMessageBox::information(this,"Image Properties", "No image loaded",QMessageBox::Ok); } } void imageViewer::slotToTX() { txWidgetPtr->setImage(imageFileName); } void imageViewer::save(QString fileName,QString fmt,bool convertRGB) { QImage im; if(image.isNull()) return; if(!convertRGB) { image.save(fileName,fmt.toUpper().toLatin1().data()); } else { im=image.convertToFormat(QImage::Format_RGB32); im.save(fileName,fmt.toUpper().toLatin1().data()); } } void imageViewer::copyToBuffer(QByteArray *ba) { QTemporaryFile itmp(QDir::tempPath()+"/qsstvXXXXXX.jp2"); if(image.isNull()) return; if(!itmp.open()) return; writeJP2Image(image.convertToFormat(QImage::Format_RGB32), itmp.fileName(),psizeRatio); *ba=itmp.readAll(); } int imageViewer::calcSize(int &sizeRatio) { if(sizeRatio>100) sizeRatio=100; if(sizeRatio<1) sizeRatio=1; return (int)(rint(((double)image.byteCount()*sizeRatio))/(RATIOSCALE*1000.)); } void imageViewer:: setSizeRatio(int sizeRatio) { format="jp2"; if(sizeRatio>100) sizeRatio=100; if(sizeRatio<1) sizeRatio=1; psizeRatio=sizeRatio/RATIOSCALE; } bool imageViewer::reload() { return openImage(imageFileName ,true,false); } void imageViewer::scale( int w, int h) { image=image.scaled(QSize(w,h),Qt::IgnoreAspectRatio,Qt::SmoothTransformation); } void imageViewer::applyTemplate(QString templateName, bool useTemplate,int w,int h) { if(!reload()) return ; addToLog("apply temlate",LOGIMAG); // sconvert cnv; editorScene tscene(0); QFile fi(templateName); if((!fi.fileName().isEmpty()) && (useTemplate)) { tscene.load(fi); tscene.addConversion('c',toCall,true); tscene.addConversion('r',rsv); tscene.addConversion('o',toOperator); tscene.addConversion('t',QDateTime::currentDateTime().toUTC().toString("hh:mm")); tscene.addConversion('d',QDateTime::currentDateTime().toUTC().toString("yyyy/MM/dd")); tscene.addConversion('m',myCallsign); tscene.addConversion('q',myQth); tscene.addConversion('l',myLocator); tscene.addConversion('n',myLastname); tscene.addConversion('f',myFirstname); tscene.addConversion('v',qsstvVersion); tscene.addConversion('x',comment1); tscene.addConversion('y',comment2); tscene.addConversion('z',comment3); addToLog(QString("applyTemplate size=%1,%2").arg(tscene.width()).arg(tscene.height()),LOGIMAG); if(w!=0 && h!=0) { overlayedImage= QImage(image.scaled(w,h)); tscene.overlay(&overlayedImage); } else { tscene.overlay(&image); } openImage(*tscene.getImagePtr()); } else { if(w!=0 && h!=0) { overlayedImage= QImage(image.scaled(w,h,Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); // same resolution as sstv mode openImage(overlayedImage); } else openImage(image); } overlayedImage=QImage(); } qsstv_8.2.12/qsstv/widgets/imageviewer.h000664 001750 001750 00000007733 12440612574 020310 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef IMAGEVIEWER_H #define IMAGEVIEWER_H #include #include #include #include #include "editor/editor.h" #include "editor/editorscene.h" class QMenu; class QAction; class editor; class imageViewer : public QLabel { Q_OBJECT /*! thumbnail type */ public: enum thumbType { RXIMG, /*!< just for receiver */ TXIMG, /*!< just for transmitter */ RXTHUMB, /*!< thumbnail for receiver. */ TXTHUMB,/*!< thumbnail for transmitter. */ TEMPLATETHUMB /*!< thumbnail for template. */ }; imageViewer(QWidget *parent=0); ~imageViewer(); void init(thumbType tp); bool openImage(QString &filename, QString start, bool ask, bool showMessage, bool emitSignal); bool openImage(QString &filename, bool showMessage, bool emitSignal); bool openImage(QImage im); bool openImage(QByteArray *ba); bool reload(); void scale( int w, int h); QImage * getImagePtr() {return ℑ} bool hasValidImage(); QImage *createImage(QSize sz,QColor fill); QRgb *getScanLineAddress(int line); void copy(imageViewer *src); bool readThumbSettings(QSettings *qs); void writeThumbSettings(QSettings *qs); void setType(thumbType t); QString getFilename() {return imageFileName;} void enablePopup(bool en) {popupEnabled=en;} void displayImage(bool useCompression); void save(QString fileName, QString fmt, bool convertRGB); void copyToBuffer(QByteArray *ba); int calcSize(int &sizeRatio); void setSizeRatio(int sizeRatio); int getFileSize(){return fileSize;} QString toCall; QString toOperator; QString rsv; QString comment1; QString comment2; QString comment3; void applyTemplate(QString templateName, bool useTemplate, int w=0, int h=0); // QSize sizeHint () {return QSize(32,26);} signals: void layoutChanged(); void imageChanged(); private: QImage image; QImage overlayedImage; QImage compressedImage; void mousePressEvent( QMouseEvent *e ); bool validImage; QString imageFileName; QString imageFilePath; thumbType ttype; bool popupEnabled; QMenu *popup; QAction *newAct; QAction *loadAct; QAction *toTXAct; QAction *editAct; QAction *printAct; QAction *deleteAct; QAction *propertiesAct; double psizeRatio; int fileSize; QString format; QMovie qm; bool activeMovie; // for overlays private slots: void slotDelete(); void slotEdit(); void slotLoad(); void slotNew(); void slotPrint(); void slotProperties(); void slotToTX(); }; #endif qsstv_8.2.12/qsstv/widgets/markerwidget.cpp000664 001750 001750 00000001440 12440612574 021011 0ustar00jomajoma000000 000000 #include "markerwidget.h" #include "fftdisplay.h" #include "QDebug" markerWidget::markerWidget(QWidget *parent) : QLabel(parent) { } void markerWidget::paintEvent(QPaintEvent *p) { QPen pn; QPainter painter(this); pn.setColor(Qt::red); pn.setWidth(2); painter.setPen(pn); if ((marker1>FFTLOW)&&(marker1<(FFTLOW+FFTSPAN))) { painter.drawLine((((marker1-FFTLOW)*width())/FFTSPAN),0,(((marker1-FFTLOW)*width())/FFTSPAN),height()); } if ((marker2>FFTLOW)&&(marker2<(FFTLOW+FFTSPAN))) painter.drawLine((((marker2-FFTLOW)*width())/FFTSPAN),0,(((marker2-FFTLOW)*width())/FFTSPAN),height()); if ((marker3>FFTLOW)&&(marker3<(FFTLOW+FFTSPAN))) painter.drawLine((((marker3-FFTLOW)*width())/FFTSPAN),0,(((marker3-FFTLOW)*width())/FFTSPAN),height()); QLabel::paintEvent(p); } qsstv_8.2.12/qsstv/widgets/markerwidget.h000664 001750 001750 00000000721 12440612574 020457 0ustar00jomajoma000000 000000 #ifndef MARKERWIDGET_H #define MARKERWIDGET_H #include class markerWidget : public QLabel { Q_OBJECT public: explicit markerWidget(QWidget *parent = 0); void setMarkerLabel(QLabel *markerLabel); void setMarkers(int mrk1, int mrk2=0, int mrk3=0){ marker1=mrk1;marker2=mrk2;marker3=mrk3;update();} signals: public slots: private: void paintEvent(QPaintEvent *p); int marker1; int marker2; int marker3; }; #endif // MARKERWIDGET_H qsstv_8.2.12/qsstv/widgets/qscale.cpp000664 001750 001750 00000023351 12440612574 017601 0ustar00jomajoma000000 000000 /* * Copyright 2008-2012 Meinert Jordan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "qscale.h" #include #include QScale::QScale(QWidget *parent) : QWidget(parent) { m_minimum = 0; m_maximum = 100; m_value = 0; m_labelsVisible = true; m_scaleVisible = true; m_borderWidth = 6; m_labelsFormat = 'g'; m_labelsPrecision = -1; m_majorStepSize = 0; m_minorStepCount = -1; m_invertedAppearance = false; m_orientations = (Qt::Horizontal | Qt::Vertical); pi = acos(-1); setBackgroundRole(QPalette::Base); updateLabelSample(); setMinimumSize(80,60); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } QScale::~QScale() { } void QScale::setMinimum(double min) { if(min < INFINITY && min > -INFINITY) m_minimum = min; updateLabelSample(); update(); } double QScale::minimum() const { return m_minimum; } void QScale::setMaximum(double max) { if(max < INFINITY && max > -INFINITY) m_maximum = max; updateLabelSample(); update(); } double QScale::maximum() const { return m_maximum; } void QScale::setRange(double min, double max) { if(max < INFINITY && max > -INFINITY) m_maximum = max; if(min < INFINITY && min > -INFINITY) m_minimum = min; updateLabelSample(); update(); } void QScale::setValue(double value) { m_value = value; update(); } double QScale::value() const { return m_value; } void QScale::setLabelsVisible(bool visible) { m_labelsVisible = visible; update(); } bool QScale::isLabelsVisible() const { return m_labelsVisible; } void QScale::setScaleVisible(bool visible) { m_scaleVisible = visible; update(); } bool QScale::isScaleVisible() const { return m_scaleVisible; } void QScale::setBorderWidth(int width) { m_borderWidth = qMin(width, 0); update(); } int QScale::borderWidth() const { return m_borderWidth; } void QScale::setLabelsFormat(char format, int precision) { m_labelsFormat = format; m_labelsPrecision = precision; updateLabelSample(); update(); } void QScale::setMajorStepSize(double stepSize) { m_majorStepSize = stepSize; update(); } double QScale::majorStepSize() const { return m_majorStepSize; } void QScale::setMinorStepCount(int stepCount) { m_minorStepCount = stepCount; update(); } int QScale::minorStepCount() const { return m_minorStepCount; } void QScale::setInvertedAppearance(bool invert) { m_invertedAppearance = invert; update(); } bool QScale::invertedAppearance() const { return m_invertedAppearance; } void QScale::setOrientations(Qt::Orientations orientations) { m_orientations = orientations; update(); } Qt::Orientations QScale::orientations() const { return m_orientations; } void QScale::resizeEvent(QResizeEvent *re) { QWidget::resizeEvent(re); } void QScale::paintEvent(QPaintEvent*) { painter = new QPainter(this); bool vertical; int wWidget, hWidget; double wLabel, hLabel; double wScale, hScale; double radius; double angleSpan; double angleStart; double valueSpan; double majorStep; int minorSteps; int order; QRectF boundingRect; QPointF center; QPolygon polygon; double u; if(!(m_orientations & Qt::Vertical) ^ !(m_orientations & Qt::Horizontal)) vertical = (bool)(m_orientations & Qt::Vertical); else vertical = (height() > width()); wWidget = width(); hWidget = height(); painter->setRenderHint(QPainter::Antialiasing, true); boundingRect = painter->boundingRect(QRectF(0, 0, width(), height()), Qt::AlignBottom | Qt::AlignHCenter, labelSample); wLabel = (m_labelsVisible)? boundingRect.width() : 0; hLabel = (m_labelsVisible)? boundingRect.height() : 0; if(vertical){ qSwap(wWidget, hWidget); qSwap(wLabel, hLabel); } wScale = wWidget - wLabel - 2. * m_borderWidth; hScale = .5 * hWidget - hLabel - m_borderWidth; radius = .125 * pow( wScale, 2) / hScale + .5 * hScale; if(radius < hScale + .5* hWidget - m_borderWidth){ radius = (4. * (hLabel + m_borderWidth) + sqrt(4. * pow(hLabel + m_borderWidth, 2) + 3. * pow(wScale, 2)) ) / 3. - hLabel - 2. * m_borderWidth; center = QPointF(.5 * wWidget, hWidget - m_borderWidth); } else center = QPointF(.5 * wWidget, radius + hLabel + m_borderWidth); angleSpan = - 360 / pi * asin(wScale/(2. * radius)); angleStart = 90. - .5 * angleSpan; valueSpan = m_maximum - m_minimum; majorStep = fabs(valueSpan) * qMax(wLabel, 1.5 * boundingRect.height()) / wScale; order = 0; while(majorStep < 1) majorStep *= 10, order--; while(majorStep >= 10) majorStep /= 10, order++; if(majorStep > 5) majorStep = 10 * pow(10, order), minorSteps = 5; else if(majorStep > 2) majorStep = 5 * pow(10, order), minorSteps = 5; else majorStep = 2 * pow(10, order), minorSteps = 4; if(m_majorStepSize > 0) majorStep = m_majorStepSize; if(m_minorStepCount > 0) minorSteps = m_minorStepCount; // draw scale painter->setPen(QPen(palette().color(QPalette::Text), 1)); if(m_scaleVisible && majorStep != 0){ if(vertical){ painter->rotate(90); painter->translate(0, -hWidget + wLabel / 4); } painter->translate(center); painter->rotate(fmod(m_minimum, majorStep / minorSteps) / valueSpan * angleSpan - angleStart); int offsetCount = (minorSteps - (int)ceil(fmod(m_minimum, majorStep) / majorStep * minorSteps)) % minorSteps; double scaleWidth = qMin(qMin(.25 * (hWidget - m_borderWidth), .25 * radius), 2.5 * boundingRect.height()); for(int i = 0; i <= (int)(minorSteps * valueSpan / majorStep); i++){ if(i % minorSteps == offsetCount) painter->drawLine(QLineF(radius - scaleWidth, 0, radius, 0)); else painter->drawLine(QLineF(radius - scaleWidth, 0, radius - scaleWidth * 0.4, 0)); painter->rotate(majorStep * angleSpan / (-valueSpan * minorSteps)); } painter->resetMatrix(); } // draw labels if(m_labelsVisible && majorStep != 0) for(int i = (int)ceil(m_minimum / majorStep); i <= (int)(m_maximum / majorStep); i++){ u = pi/180 * ((majorStep * i - m_minimum) / valueSpan * angleSpan + angleStart); QRect position; Qt::Alignment align; if(vertical){ align = Qt::AlignLeft | Qt::AlignVCenter; position = QRect(width() - center.y() + radius * sin(u), 0, width(), height() + 2 * radius * cos(u)); } else{ align = Qt::AlignHCenter | Qt::AlignBottom; position = QRect(0, 0, 2. * (center.x() + radius * cos(u)), center.y() - radius * sin(u)); } painter->resetMatrix(); painter->drawText(position, align, QString::number(i * majorStep, m_labelsFormat, m_labelsPrecision)); } // draw needle if(vertical){ painter->rotate(90); painter->translate(0, -hWidget + wLabel / 4); } painter->translate(center); painter->rotate((m_minimum - m_value) / valueSpan * angleSpan - angleStart); painter->setPen(Qt::NoPen); painter->setBrush(palette().color(QPalette::Text)); polygon.setPoints(5, 0, -2, (int)radius - 10, -2, (int)radius, 0, (int)radius - 10, 2, 0, 2); painter->drawConvexPolygon(polygon); painter->setPen(QPen(palette().color(QPalette::Base), 2)); painter->drawLine(0, 0, radius - 15, 0); painter->resetMatrix(); // draw cover painter->setPen(Qt::NoPen); painter->setBrush(palette().color(QPalette::Mid)); if(vertical){ painter->drawRect(QRect(0, 0, m_borderWidth, height())); center = QPointF(width() - center.y() - wLabel / 4, .5 * height()); u = .25 * (hWidget - wLabel) - center.x() - m_borderWidth; } else{ painter->drawRect(QRect(0, hWidget, wWidget, -m_borderWidth)); u = center.y() - m_borderWidth - .75 * hWidget; } u = qMax(u, .25 * radius); painter->drawEllipse(center, u, u); delete painter; } void QScale::updateLabelSample() { double margin = qMax(fabs(m_minimum), fabs(m_maximum)); double wildcard = (qMin(m_minimum, m_maximum) < 0)? -8 : 8; while(margin < 1){ margin *= 10; wildcard /= 10; } while(margin >= 10){ margin /= 10; wildcard *= 10; } labelSample = QString::number(wildcard, m_labelsFormat, m_labelsPrecision); } qsstv_8.2.12/qsstv/widgets/qscale.h000664 001750 001750 00000004703 12440612574 017246 0ustar00jomajoma000000 000000 /* * Copyright 2008-2012 Meinert Jordan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef QSCALE_H #define QSCALE_H #include "qglobal.h" #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #else #include #endif class QScale : public QWidget { Q_OBJECT public: QScale(QWidget *parent = 0); ~QScale(); double minimum() const; double maximum() const; double value() const; void setLabelsVisible(bool); bool isLabelsVisible() const; void setScaleVisible(bool); bool isScaleVisible() const; void setBorderWidth(int); int borderWidth() const; void setLabelsFormat(char format, int precision = -1); double majorStepSize() const; int minorStepCount() const; void setInvertedAppearance(bool invert); bool invertedAppearance() const; Qt::Orientations orientations() const; // QSize sizeHint() const; // QSize minimumSizeHint() const; public Q_SLOTS: void setMinimum(double); void setMaximum(double); void setRange(double min, double max); void setValue(double); void setMajorStepSize(double); void setMinorStepCount(int); void setOrientations(Qt::Orientations); protected: // bool event(QEvent *e); void resizeEvent(QResizeEvent *re); void paintEvent(QPaintEvent *pe); private: double m_minimum; double m_maximum; double m_value; bool m_labelsVisible; bool m_scaleVisible; int m_borderWidth; char m_labelsFormat; int m_labelsPrecision; double m_majorStepSize; int m_minorStepCount; bool m_invertedAppearance; Qt::Orientations m_orientations; QPainter *painter; QString labelSample; double pi; void updateLabelSample(); }; #endif // QSCALE_H qsstv_8.2.12/qsstv/widgets/spectrumwidget.cpp000664 001750 001750 00000004627 12440612574 021404 0ustar00jomajoma000000 000000 #include "spectrumwidget.h" #include "qsstvglobal.h" #include "ui_spectrumwidget.h" #include "utils/supportfunctions.h" #include "utils/logging.h" #include "markerwidget.h" spectrumWidget::spectrumWidget(QWidget *parent) : QFrame(parent), ui(new Ui::spectrumWidget) { ui->setupUi(this); readSettings(); connect(ui->maxDbSpinbox,SIGNAL(valueChanged(int)),SLOT(slotMaxDbChanged(int))); connect(ui->rangeSpinBox,SIGNAL(valueChanged(int)),SLOT(slotRangeChanged(int))); } spectrumWidget::~spectrumWidget() { writeSettings(); delete ui; } void spectrumWidget::init(int size,int slices,int isamplingrate) { addToLog(QString("Size: %1, Slices %2, Samplingrate %3").arg(size).arg(slices).arg(isamplingrate),LOGFFT); ui->fftFrame->init(size,slices,isamplingrate); // ui->fftFrame->setMarkerLabel(ui->markerLabel); // ui->fftFrame->setSize(ui->fftFrame->width(),ui->fftFrame->height()); } void spectrumWidget::realFFT(short int *iBuffer) { ui->fftFrame->realFFT(iBuffer); } void spectrumWidget::realFFT(float *iBuffer) { ui->fftFrame->realFFT(iBuffer); } void spectrumWidget::realFFT(double *iBuffer) { ui->fftFrame->realFFT(iBuffer); } void spectrumWidget::slotMaxDbChanged(int mb) { ui->fftFrame->setMaxDb(mb); maxdb=mb; } void spectrumWidget::slotRangeChanged(int rg) { ui->fftFrame->setRange(rg); range=rg; } void spectrumWidget::readSettings() { QSettings qSettings; qSettings.beginGroup("SPECTRUM"); maxdb=qSettings.value("maxdb",0).toInt(); slotMaxDbChanged(maxdb); range=qSettings.value("range",35).toInt(); slotRangeChanged(range); qSettings.endGroup(); setParams(); } void spectrumWidget::writeSettings() { QSettings qSettings; getParams(); qSettings.beginGroup("SPECTRUM"); qSettings.setValue( "maxdb",maxdb); qSettings.setValue( "range",range); qSettings.endGroup(); } void spectrumWidget::getParams() { getValue(maxdb,ui->maxDbSpinbox); getValue(range,ui->rangeSpinBox); } void spectrumWidget::setParams() { setValue(maxdb,ui->maxDbSpinbox); setValue(range,ui->rangeSpinBox); slotMaxDbChanged(maxdb); slotRangeChanged(range); } void spectrumWidget::displaySettings(bool wf, bool drm) { ui->fftFrame->displayWaterfall(wf); if(drm) { ui->fftFrame->setMarkers(725,1475,1850); ui->markerLabel->setMarkers(725,1475,1850); } else { ui->fftFrame->setMarkers(1200,1500,2300); ui->markerLabel->setMarkers(1200,1500,2300); } } qsstv_8.2.12/qsstv/widgets/spectrumwidget.h000664 001750 001750 00000001265 12440612574 021044 0ustar00jomajoma000000 000000 #ifndef SPECTRUMWIDGET_H #define SPECTRUMWIDGET_H #include namespace Ui { class spectrumWidget; } class spectrumWidget : public QFrame { Q_OBJECT public: spectrumWidget(QWidget *parent = 0); ~spectrumWidget(); void init(int size,int slices,int isamplingrate); void realFFT(short int *iBuffer); void realFFT(float *iBuffer); void realFFT(double *iBuffer); void readSettings(); void writeSettings(); void displaySettings(bool wf,bool drm); private slots: void slotMaxDbChanged(int mb); void slotRangeChanged(int rg); void getParams(); void setParams(); private: Ui::spectrumWidget *ui; int maxdb; int range; }; #endif // SPECTRUMWIDGET_H qsstv_8.2.12/qsstv/widgets/spectrumwidget.ui000664 001750 001750 00000040245 12440612574 021233 0ustar00jomajoma000000 000000 spectrumWidget 0 0 334 219 334 0 Ubuntu Mono 9 50 false Frame QFrame::Panel QFrame::Sunken 2 0 0 16777215 8 255 255 255 0 0 127 0 0 191 0 0 159 0 0 63 0 0 84 255 255 255 255 255 255 255 255 255 0 0 0 0 0 127 0 0 0 0 0 63 255 255 220 0 0 0 255 255 255 0 0 127 0 0 191 0 0 159 0 0 63 0 0 84 255 255 255 255 255 255 255 255 255 0 0 0 0 0 127 0 0 0 0 0 63 255 255 220 0 0 0 0 0 63 0 0 127 0 0 191 0 0 159 0 0 63 0 0 84 0 0 63 255 255 255 0 0 63 0 0 127 0 0 127 0 0 0 0 0 127 255 255 220 0 0 0 true QFrame::NoFrame QFrame::Plain 1 4 Qt::Horizontal 40 20 10 50 false false Max dB 0 0 16777215 20 9 -30 20 0 10 Range 0 0 16777215 20 9 25 40 30 Qt::Horizontal 40 20 fftDisplay QLabel
widgets/fftdisplay.h
markerWidget QLabel
widgets/markerwidget.h
qsstv_8.2.12/qsstv/widgets/sweepform.ui000664 001750 001750 00000015563 12440612574 020201 0ustar00jomajoma000000 000000 sweepForm 0 0 469 156 Test Signal 6 0 Lower Frequency false 300 2500 1200 6 0 Upper Frequency false 300 2500 2300 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 Duration (sec) false 1 100 10 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 Qt::Horizontal QSizePolicy::Expanding 20 20 OK Cancel Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Expanding 20 20 qPixmapFromMimeSource okButton clicked() sweepForm accept() 20 20 20 20 cancelButton clicked() sweepForm reject() 20 20 20 20 qsstv_8.2.12/qsstv/widgets/textdisplay.cpp000664 001750 001750 00000000712 12440612574 020677 0ustar00jomajoma000000 000000 #include "textdisplay.h" #include "ui_textdisplay.h" textDisplay::textDisplay(QWidget *parent) : QDialog(parent), ui(new Ui::textDisplay) { ui->setupUi(this); } textDisplay::~textDisplay() { delete ui; } void textDisplay::clear() { ui->plainTextEdit->clear(); } void textDisplay::append(QString t) { int i; QStringList sl; sl=t.split("\r\n"); for(i=0;iplainTextEdit->appendPlainText(sl.at(i)); } } qsstv_8.2.12/qsstv/widgets/textdisplay.h000664 001750 001750 00000000511 12440612574 020341 0ustar00jomajoma000000 000000 #ifndef TEXTDISPLAY_H #define TEXTDISPLAY_H #include namespace Ui { class textDisplay; } class textDisplay : public QDialog { Q_OBJECT public: explicit textDisplay(QWidget *parent = 0); ~textDisplay(); void clear(); void append(QString t); private: Ui::textDisplay *ui; }; #endif // TEXTDISPLAY_H qsstv_8.2.12/qsstv/widgets/textdisplay.ui000664 001750 001750 00000003201 12440612574 020526 0ustar00jomajoma000000 000000 textDisplay 0 0 400 300 Received Text 30 240 341 32 Qt::Horizontal QDialogButtonBox::Ok 10 20 371 211 buttonBox accepted() textDisplay accept() 248 254 157 274 buttonBox rejected() textDisplay reject() 316 260 286 274 qsstv_8.2.12/qsstv/widgets/vumeter.cpp000664 001750 001750 00000014462 12440612574 020023 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2008 - Giuseppe Cigala * * g_cigala@virgilio.it * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "vumeter.h" #include #define BW 5 #define SG 100 #define LG 500 #define OFFSET 50 vuMeter::vuMeter(QWidget *parent) : QWidget(parent) { colBack = QColor(50, 50, 255); colValue = Qt::white; colHigh = Qt::red; colMid = Qt::green; colLow = Qt::blue; min = 0; max = 100; val =9; horizontal=false; divisions=20; labelText="V"; } void vuMeter::setLabelText(QString t) { labelText=t; } void vuMeter::paintEvent(QPaintEvent *) { if(width()>height()) horizontal=true; else horizontal=false; if (horizontal) { w=LG; h=SG; rw=5; rh=30; // rect rounding } else { w=SG; h=LG; rw=30; rh=5; // rect rounding } paintBorder(); paintBar(); //paintValue(); } void vuMeter::paintBorder() { QLinearGradient linGrad; QLinearGradient linGrad1; QRectF border1; QRectF rct; QPainter painter(this); QColor light = Qt::white; QColor dark = colBack.darker(255); painter.setPen(QPen(colBack, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.setRenderHint(QPainter::Antialiasing); if (horizontal) { linGrad.setStart(250,BW); linGrad.setFinalStop(250, 2*BW); linGrad1.setStart(1,SG-3*BW); linGrad1.setFinalStop(1, SG-BW); border1=QRectF(5, 20, w-2*BW, h-5*BW); rct=QRectF(2*BW,h/2-10, 20, 25); } else { linGrad.setStart(BW,1); linGrad.setFinalStop(2*BW, 1); linGrad1.setStart(SG-3*BW,1); linGrad1.setFinalStop(SG-BW, 1); border1=QRectF(20, 5, w-5*BW, h-2*BW); rct=QRectF(w/2-10, h-4*BW-10, 20, 25); } painter.setWindow(0, 0, w, h); linGrad.setColorAt(0, light); linGrad.setColorAt(1, colBack); linGrad.setSpread(QGradient::PadSpread); painter.setBrush(linGrad); QRectF border(5, 5, w-2*BW, h-2*BW); painter.drawRoundRect(border, rw,rh); linGrad1.setColorAt(0, colBack); linGrad1.setColorAt(1, dark); linGrad1.setSpread(QGradient::PadSpread); painter.setBrush(linGrad1); painter.drawRoundRect(border1, rw,rh); //paint label painter.setPen(QPen(colValue, 2)); QFont valFont("Arial", 24, QFont::Bold); painter.setFont(valFont); painter.drawText(rct, Qt::AlignCenter, labelText); } void vuMeter::paintBar() { QLinearGradient linGrad; int i; double bar; QRectF bar1; QRectF bar2; double length; QPainter painter(this); painter.setWindow(0, 0, w, h); painter.setRenderHint(QPainter::Antialiasing); if (horizontal) { linGrad.setStart(w,h); linGrad.setFinalStop(0,h); bar2=QRectF(OFFSET,3*BW,w-OFFSET-3*BW,h-6*BW); length = bar2.width(); bar = abs(length * (1-(val-min)/(max-min))); bar1=QRectF(bar2.x()+bar2.width()-bar,bar2.y(),bar, bar2.height()); } else { linGrad.setStart(w,0); linGrad.setFinalStop(w,h); bar2=QRectF(3*BW,4*BW,w-6*BW,h-1*OFFSET); length = bar2.height(); bar = abs(length * (val-min)/(max-min)); bar1=QRectF(bar2.x(),bar2.y(),bar2.width(), bar2.height()-bar); } linGrad.setColorAt(0, colHigh); linGrad.setColorAt(0.5, colMid); linGrad.setColorAt(1, colLow); linGrad.setSpread(QGradient::PadSpread); painter.setBrush(linGrad); painter.drawRect(bar2); // draw background bar painter.setBrush(QColor(40, 40, 40)); painter.drawRect(bar1); painter.setPen(QPen(Qt::black, 2)); for (i = 0; i <=divisions; i++) { if(horizontal) { painter.drawLine(bar2.left()+bar2.width()*i/divisions, bar2.top(), bar2.left()+bar2.width()*i/divisions, bar2.bottom()); } else { painter.drawLine(bar2.left(), bar2.top()+bar2.height()*i/divisions, bar2.right(), bar2.top()+bar2.height()*i/divisions); } } } void vuMeter::setColorBg(QColor color) { colBack = color; update(); } void vuMeter::setColorValue(QColor color) { colValue = color; update(); } void vuMeter::setColorHigh(QColor color) { colHigh = color; update(); } void vuMeter::setColorMid(QColor color) { colMid = color; update(); } void vuMeter::setColors(QColor cL,QColor cM,QColor cH) { colLow = cL; colMid = cM; colHigh = cH; update(); } void vuMeter::setColorLow(QColor color) { colLow = color; update(); } void vuMeter::setValue(double value) { if (value > max) { val = max; update(); } else if (value < min) { val = min; update(); } else { val = value; update(); } } void vuMeter::setMinimum(double minValue) { if (minValue > max) { min = max; max = minValue; update(); } else { min = minValue; update(); } } void vuMeter::setMaximum(double maxValue) { if (maxValue < min) { max = min; min = maxValue; update(); } else { max = maxValue; update(); } } QSize vuMeter::minimumSizeHint() const { return QSize(10, 54); } QSize vuMeter::sizeHint() const { return QSize(100, 540); } qsstv_8.2.12/qsstv/widgets/vumeter.h000664 001750 001750 00000005565 12440612574 017474 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2008 - Giuseppe Cigala * * g_cigala@virgilio.it * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef VUMETER_H #define VUMETER_H #include #include #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif class vuMeter : public QWidget { Q_OBJECT QColor colorBg() const { return colBack; } QColor colorValue() const { return colValue;} QColor colorLow() const { return colLow;} QColor colorHigh() const { return colHigh;} double value() const { return val; } double minValue() const {return min;} double maxValue() const {return max; } public: vuMeter(QWidget *parent = 0); QSize minimumSizeHint() const; QSize sizeHint() const; void setHorizontal(bool h) {horizontal=h;} void setLabelText(QString t); signals: void valueChanged(double); public slots: void setColorBg(QColor); void setColorValue(QColor); void setColorHigh(QColor); void setColorMid(QColor); void setColorLow(QColor); void setColors(QColor,QColor ,QColor); void setDivisions(int div) {divisions=div;} void setValue(double); void setMaximum(double); void setMinimum(double); protected: void paintEvent(QPaintEvent *); void paintBorder(); void paintBar(); private: double min; double max; double val; QColor colBack; QColor colValue; QColor colHigh; QColor colLow; QColor colMid; bool horizontal; qreal w; qreal h; int rw; int rh; int divisions; QString labelText; }; #endif qsstv_8.2.12/qsstv/widgets/waterfallform.cpp000664 001750 001750 00000003665 12440612574 021204 0ustar00jomajoma000000 000000 #include "waterfallform.h" #include "ui_waterfallform.h" #include "qsstvglobal.h" #include "sound/waterfalltext.h" waterfallForm::waterfallForm(QWidget *parent) : QDialog(parent), ui(new Ui::waterfallForm) { ui->setupUi(this); connect (ui->text1PushButton,SIGNAL(clicked()),SLOT(slotText1())); connect (ui->text2PushButton,SIGNAL(clicked()),SLOT(slotText2())); connect (ui->text3PushButton,SIGNAL(clicked()),SLOT(slotText3())); connect (ui->text4PushButton,SIGNAL(clicked()),SLOT(slotText4())); readSettings(); txt=""; } waterfallForm::~waterfallForm() { writeSettings(); delete ui; } void waterfallForm::accept() { writeSettings(); done(QDialog::Accepted); } void waterfallForm::slotText1() { getParams(); txt=txt1; accept(); } void waterfallForm::slotText2() { getParams(); txt=txt2; accept(); } void waterfallForm::slotText3() { getParams(); txt=txt3; accept(); } void waterfallForm::slotText4() { getParams(); txt=txt4; accept(); } void waterfallForm::getParams() { txt1=ui->wfText1->toPlainText(); txt2=ui->wfText2->toPlainText(); txt3=ui->wfText3->toPlainText(); txt4=ui->wfText4->toPlainText(); } void waterfallForm::setParams() { ui->wfText1->setPlainText(txt1); ui->wfText2->setPlainText(txt2); ui->wfText3->setPlainText(txt3); ui->wfText4->setPlainText(txt4); } void waterfallForm::readSettings() { QFont ft; QSettings qSettings; qSettings.beginGroup("Waterfall"); txt1=qSettings.value("text1","").toString(); txt2=qSettings.value("text2","").toString(); txt3=qSettings.value("text3","").toString(); txt4=qSettings.value("text4","").toString(); qSettings.endGroup(); setParams(); } void waterfallForm::writeSettings() { getParams(); QSettings qSettings; qSettings.beginGroup("Waterfall"); qSettings.setValue("text1",txt1); qSettings.setValue("text2",txt2); qSettings.setValue("text3",txt3); qSettings.setValue("text4",txt4); qSettings.endGroup(); } qsstv_8.2.12/qsstv/widgets/waterfallform.h000664 001750 001750 00000001146 12440612574 020641 0ustar00jomajoma000000 000000 #ifndef WATERFALLFORM_H #define WATERFALLFORM_H #include namespace Ui { class waterfallForm; } class waterfallForm : public QDialog { Q_OBJECT public: explicit waterfallForm(QWidget *parent = 0); ~waterfallForm(); QString text(){ return txt;} private slots: void slotText1(); void slotText2(); void slotText3(); void slotText4(); private: Ui::waterfallForm *ui; QString txt1; QString txt2; QString txt3; QString txt4; QString txt; void readSettings(); void writeSettings(); void getParams(); void setParams(); void accept(); }; #endif // WATERFALLFORM_H qsstv_8.2.12/qsstv/widgets/waterfallform.ui000664 001750 001750 00000012406 12440612574 021030 0ustar00jomajoma000000 000000 waterfallForm 0 0 323 421 8 Dialog Maximum 10 charaters per line Qt::Horizontal 40 20 0 80 16777215 80 TX #1 0 80 16777215 80 TX #2 0 80 16777215 80 TX #3 0 80 16777215 80 TX #4 Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Save Qt::Horizontal 40 20 buttonBox accepted() waterfallForm accept() 248 254 157 274 buttonBox rejected() waterfallForm reject() 316 260 286 274 qsstv_8.2.12/qsstv/xmlrpc/ipcmessage.cpp000664 001750 001750 00000003220 12440612574 020301 0ustar00jomajoma000000 000000 #include "ipcmessage.h" #include #include #include #include #include #include #include //extern int errno; // error NO. ipcMessage::ipcMessage(int messageKey) { key=messageKey; messageQId = msgget(key, MSGPERM|IPC_CREAT); if(messageQId<0) qDebug() << "IPC Error" << strerror(errno); // else qDebug()<< "queue opened: id=" << messageQId; } ipcMessage::~ipcMessage() { closeQueue(); } bool ipcMessage::sendMessage(QString t) { if(messageQId<0) return false; int len; // message to send msgBuf.mtype = MTYPE; // set the type of message strncpy(msgBuf.mtext,t.toLatin1().data(),MSGTXMAXLEN); len=strlen(msgBuf.mtext); // send the message to queue rc = msgsnd(messageQId, &msgBuf, len+1, IPC_NOWAIT); if (rc < 0) { if(rc<0) qDebug() << "IPC Error" << strerror(errno); return false; } // qDebug() << "message type" << msgBuf.mtype; // qDebug() << "tx message:" << t; return true; } bool ipcMessage::receiveMessage(QString &t) { if(messageQId<0) return false; // read the message from queue rc = msgrcv(messageQId, &msgBuf, sizeof(msgBuf.mtext), 0, IPC_NOWAIT); if (rc < -1) { if(rc<0) qDebug() << "IPC Error" << strerror(errno); return false; } if(rc>=0) { t=msgBuf.mtext; // qDebug() << "rx message:" << t; return true; } return false; } bool ipcMessage::closeQueue() { // remove the queue rc=msgctl(messageQId,IPC_RMID,NULL); if (rc < 0) { if(rc<0) qDebug() << "IPC Error" << strerror(errno); return false; } // qDebug()<< "queue closed"; return 0; } qsstv_8.2.12/qsstv/xmlrpc/ipcmessage.h000664 001750 001750 00000000771 12440612574 017756 0ustar00jomajoma000000 000000 #ifndef IPCMESSAGE_H #define IPCMESSAGE_H #include #define MSGTXMAXLEN 2048 #define MSGPERM 0666 // msg queue permission #define MTYPE 88 struct smessageBuf { long mtype; char mtext[MSGTXMAXLEN]; }; class ipcMessage { public: ipcMessage(int messageKey); ~ipcMessage(); void essage(); bool sendMessage(QString t); bool receiveMessage(QString &t); bool closeQueue(); private: smessageBuf msgBuf; int key; int messageQId, rc; int done; }; #endif // IPCMESSAGE_H qsstv_8.2.12/qsstv/xmlrpc/maiaFault.cpp000664 001750 001750 00000004142 12440612574 020070 0ustar00jomajoma000000 000000 /* * libMaia - maiaFault.cpp * Copyright (c) 2007 Sebastian Wiedenroth * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maiaFault.h" #include "maiaObject.h" MaiaFault::MaiaFault(const MaiaFault &other) : QObject(other.parent()) { fault = other.fault; } MaiaFault::MaiaFault(int faultCode, QString faultString, QObject *parent) : QObject(parent) { fault["faultCode"] = faultCode; fault["faultString"] = faultString; } QString MaiaFault::toString() { QDomDocument doc; QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", QString("version=\"1.0\" encoding=\"UTF-8\"" )); doc.appendChild(header); QDomElement methodResponse = doc.createElement("methodResponse"); doc.appendChild(methodResponse); QDomElement faultelement = doc.createElement("fault"); methodResponse.appendChild(faultelement); faultelement.appendChild(MaiaObject::toXml(fault)); return doc.toString(); } qsstv_8.2.12/qsstv/xmlrpc/maiaFault.h000664 001750 001750 00000003245 12440612574 017540 0ustar00jomajoma000000 000000 /* * libMaia - maiaFault.h * Copyright (c) 2007 Sebastian Wiedenroth * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAIAFAULT_H #define MAIAFAULT_H #include #include class MaiaFault : public QObject { Q_OBJECT public: MaiaFault(int faultCode = 0, QString faultString = QString(), QObject *parent = 0); MaiaFault(const MaiaFault &other); QString toString(); QMap fault; }; Q_DECLARE_METATYPE(MaiaFault) #endif qsstv_8.2.12/qsstv/xmlrpc/maiaObject.cpp000664 001750 001750 00000024005 12474354470 020230 0ustar00jomajoma000000 000000 /* * libMaia - maiaObject.cpp * Copyright (c) 2003 Frerich Raabe and * Ian Reinhart Geiser * Copyright (c) 2007 Sebastian Wiedenroth * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maiaObject.h" MaiaObject::MaiaObject(QObject* parent) : QObject(parent) { QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars); } QDomElement MaiaObject::toXml(QVariant arg) { //dummy document QDomDocument doc; //value element, we need this in each case if(arg.isNull()) { QDomElement tagString = doc.createElement("value"); QDomText textString = doc.createTextNode(""); // tagValue.appendChild(tagString); tagString.appendChild(textString); return tagString; } QDomElement tagValue = doc.createElement("value"); switch(arg.type()) { case QVariant::String: { QDomElement tagString = doc.createElement("string"); QDomText textString = doc.createTextNode(arg.toString()); tagValue.appendChild(tagString); tagString.appendChild(textString); return tagValue; } case QVariant::Int: { QDomElement tagInt = doc.createElement("int"); QDomText textInt = doc.createTextNode(QString::number(arg.toInt())); tagValue.appendChild(tagInt); tagInt.appendChild(textInt); return tagValue; } case QVariant::Double: { QDomElement tagDouble = doc.createElement("double"); QDomText textDouble = doc.createTextNode(QString::number(arg.toDouble(),'g',9)); tagValue.appendChild(tagDouble); tagDouble.appendChild(textDouble); return tagValue; } case QVariant::Bool: { QString textValue = arg.toBool() ? "1" : "0"; QDomElement tag = doc.createElement("boolean"); QDomText text = doc.createTextNode(textValue); tagValue.appendChild(tag); tag.appendChild(text); return tagValue; } case QVariant::ByteArray: { QString textValue = arg.toByteArray().toBase64(); QDomElement tag = doc.createElement("base64"); QDomText text = doc.createTextNode(textValue); tagValue.appendChild(tag); tag.appendChild(text); return tagValue; } case QVariant::DateTime: { QString textValue = arg.toDateTime().toString("yyyyMMddThh:mm:ss"); QDomElement tag = doc.createElement("datetime.iso8601"); QDomText text = doc.createTextNode(textValue); tagValue.appendChild(tag); tag.appendChild(text); return tagValue; } case QVariant::List: { QDomElement tagArray = doc.createElement("array"); QDomElement tagData = doc.createElement("data"); tagArray.appendChild(tagData); tagValue.appendChild(tagArray); const QList args = arg.toList(); for(int i = 0; i < args.size(); ++i) { tagData.appendChild(toXml(args.at(i))); } return tagValue; } case QVariant::Map: { QDomElement tagStruct = doc.createElement("struct"); QDomElement member; QDomElement name; tagValue.appendChild(tagStruct); QMap map = arg.toMap(); QMapIterator i(map); while(i.hasNext()) { i.next(); member = doc.createElement("member"); name = doc.createElement("name"); // (key) -> name -> member -> struct tagStruct.appendChild(member); member.appendChild(name); name.appendChild(doc.createTextNode(i.key())); // add variables by recursion member.appendChild(toXml(i.value())); } return tagValue; } default: qDebug() << "Failed to marshal unknown variant type: " << arg.type() << endl; } return QDomElement(); //QString::null; } QVariant MaiaObject::fromXml(const QDomElement &elem) { if(elem.tagName().toLower() != "value") { return QVariant(); } // If no type is indicated, the type is string. if(!elem.firstChild().isElement()) { return QVariant(elem.text()); } const QDomElement typeElement = elem.firstChild().toElement(); const QString typeName = typeElement.tagName().toLower(); if(typeName == "string") return QVariant(typeElement.text()); else if(typeName == "i4" || typeName == "int") return QVariant(typeElement.text().toInt()); else if(typeName == "double") return QVariant(typeElement.text().toDouble()); else if (typeName == "boolean") { if(typeElement.text().toLower() == "true" || typeElement.text() == "1") return QVariant(true); else return QVariant(false); } else if(typeName == "base64") return QVariant(QByteArray::fromBase64( typeElement.text().toLatin1())); else if(typeName == "datetime" || typeName == "datetime.iso8601") return QVariant(QDateTime::fromString(typeElement.text(), "yyyyMMddThh:mm:ss")); else if(typeName == "nil") return QVariant(); // Non-standard extension: http://ontosys.com/xml-rpc/extensions.php else if ( typeName == "array" ) { QList values; QDomNode valueNode = typeElement.firstChild().firstChild(); while(!valueNode.isNull()) { values << fromXml(valueNode.toElement()); valueNode = valueNode.nextSibling(); } return QVariant(values); } else if ( typeName == "struct" ) { QMap map; QDomNode memberNode = typeElement.firstChild(); while(!memberNode.isNull()) { const QString key = memberNode.toElement().elementsByTagName("name").item(0).toElement().text(); const QVariant data = fromXml(memberNode.toElement().elementsByTagName("value").item(0).toElement()); map[key] = data; memberNode = memberNode.nextSibling(); } return QVariant(map); } else { qDebug() << "Cannot demarshal unknown type " << typeElement.tagName().toLower(); } return QVariant(); } QString MaiaObject::prepareCall(QString method, QList args) { QDomDocument doc; QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", QString("version=\"1.0\" encoding=\"UTF-8\"" )); doc.appendChild(header); QDomElement methodCall = doc.createElement("methodCall"); QDomElement methodName = doc.createElement("methodName"); QDomElement params = doc.createElement("params"); QDomElement param; doc.appendChild(methodCall); methodCall.appendChild(methodName); methodName.appendChild(doc.createTextNode(method)); methodCall.appendChild(params); for(int i = 0; i < args.size(); ++i) { param = doc.createElement("param"); param.appendChild(toXml(args.at(i))); params.appendChild(param); } return doc.toString(); } QString MaiaObject::prepareResponse(QVariant arg) { QDomDocument doc; QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", QString("version=\"1.0\" encoding=\"UTF-8\"" )); doc.appendChild(header); QDomElement methodResponse = doc.createElement("methodResponse"); QDomElement params = doc.createElement("params"); QDomElement param; doc.appendChild(methodResponse); methodResponse.appendChild(params); // if(!arg.isNull()) { param = doc.createElement("param"); param.appendChild(toXml(arg)); params.appendChild(param); } return doc.toString(-1); } void MaiaObject::parseResponse(QString response, QNetworkReply* reply) { QDomDocument doc; QVariant arg; QString errorMsg; int errorLine; int errorColumn; if(!doc.setContent(response, &errorMsg, &errorLine, &errorColumn)) { emit fault(-32700, QString("parse error: response not well formed at line %1: %2").arg(errorLine).arg(errorMsg), reply); delete this; return; } if(doc.documentElement().firstChild().toElement().tagName().toLower() == "params") { QDomNode paramNode = doc.documentElement().firstChild().firstChild(); if(!paramNode.isNull()) { arg = fromXml( paramNode.firstChild().toElement() ); } emit aresponse(arg, reply); } else if(doc.documentElement().firstChild().toElement().tagName().toLower() == "fault") { const QVariant errorVariant = fromXml(doc.documentElement().firstChild().firstChild().toElement()); emit fault(errorVariant.toMap() [ "faultCode" ].toInt(), errorVariant.toMap() [ "faultString" ].toString(), reply); } else { emit fault(-32600, tr("parse error: invalid xml-rpc. not conforming to spec."), reply); } delete this; return; } qsstv_8.2.12/qsstv/xmlrpc/maiaObject.h000664 001750 001750 00000004123 12440612574 017667 0ustar00jomajoma000000 000000 /* * libMaia - maiaObject.h * Copyright (c) 2003 Frerich Raabe and * Ian Reinhart Geiser * Copyright (c) 2007 Sebastian Wiedenroth * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAIAOBJECT_H #define MAIAOBJECT_H #include #include #include class MaiaObject : public QObject { Q_OBJECT public: MaiaObject(QObject* parent = 0); static QDomElement toXml(QVariant arg); static QVariant fromXml(const QDomElement &elem); QString prepareCall(QString method, QList args); static QString prepareResponse(QVariant arg); public slots: void parseResponse(QString response, QNetworkReply* reply); signals: void aresponse(QVariant &, QNetworkReply* reply); void call(const QString, const QList); void fault(int, const QString &, QNetworkReply* reply); }; #endif qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcClient.cpp000664 001750 001750 00000007344 12474354470 021375 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcClient.cpp * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maiaXmlRpcClient.h" #include "maiaFault.h" MaiaXmlRpcClient::MaiaXmlRpcClient(QObject* parent) : QObject(parent), manager(this), request() { init(); } MaiaXmlRpcClient::MaiaXmlRpcClient(QUrl url, QObject* parent) : QObject(parent), manager(this), request(url) { init(); setUrl(url); } MaiaXmlRpcClient::MaiaXmlRpcClient(QUrl url, QString userAgent, QObject *parent) : QObject(parent) { // userAgent should adhere to RFC 1945 http://tools.ietf.org/html/rfc1945 init(); request.setRawHeader("User-Agent", userAgent.toLatin1()); setUrl(url); } void MaiaXmlRpcClient::init() { request.setRawHeader("User-Agent", "libmaia/0.2"); request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml"); connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList &)), this, SIGNAL(sslErrors(QNetworkReply *, const QList &))); } void MaiaXmlRpcClient::setUrl(QUrl url) { if(!url.isValid()) return; request.setUrl(url); } void MaiaXmlRpcClient::setUserAgent(QString userAgent) { request.setRawHeader("User-Agent", userAgent.toLatin1()); } QNetworkReply* MaiaXmlRpcClient::call(QString method, QList args, QObject* responseObject, const char* responseSlot, QObject* faultObject, const char* faultSlot) { MaiaObject* call = new MaiaObject(this); connect(call, SIGNAL(aresponse(QVariant &, QNetworkReply *)), responseObject, responseSlot); connect(call, SIGNAL(fault(int, const QString &, QNetworkReply *)), faultObject, faultSlot); QNetworkReply* reply = manager.post( request, call->prepareCall(method, args).toUtf8() ); callmap[reply] = call; return reply; } void MaiaXmlRpcClient::setSslConfiguration(const QSslConfiguration &config) { request.setSslConfiguration(config); } QSslConfiguration MaiaXmlRpcClient::sslConfiguration () const { return request.sslConfiguration(); } void MaiaXmlRpcClient::replyFinished(QNetworkReply* reply) { QString response; if(!callmap.contains(reply)) return; if(reply->error() != QNetworkReply::NoError) { MaiaFault fault(-32300, reply->errorString()); response = fault.toString(); } else { response = QString::fromUtf8(reply->readAll()); } // parseResponse deletes the MaiaObject callmap[reply]->parseResponse(response, reply); reply->deleteLater(); callmap.remove(reply); } qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcClient.h000664 001750 001750 00000004476 12440612574 021040 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcClient.h * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAIAXMLRPCCLIENT_H #define MAIAXMLRPCCLIENT_H #include #include #include #include "maiaObject.h" class MaiaXmlRpcClient : public QObject { Q_OBJECT public: MaiaXmlRpcClient(QObject* parent = 0); MaiaXmlRpcClient(QUrl url, QObject* parent = 0); MaiaXmlRpcClient(QUrl url, QString userAgent, QObject *parent = 0); void setUrl(QUrl url); void setUserAgent(QString userAgent); QNetworkReply* call(QString method, QList args, QObject* responseObject, const char* responseSlot, QObject* faultObject, const char* faultSlot); void setSslConfiguration(const QSslConfiguration &config); QSslConfiguration sslConfiguration () const; signals: void sslErrors(QNetworkReply *reply, const QList &errors); private slots: void replyFinished(QNetworkReply*); private: void init(); QNetworkAccessManager manager; QNetworkRequest request; QMap callmap; }; #endif qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcServer.cpp000664 001750 001750 00000006774 12474354470 021433 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcServer.cpp * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maiaXmlRpcServer.h" #include "maiaFault.h" MaiaXmlRpcServer::MaiaXmlRpcServer(const QHostAddress &address, quint16 port, QObject* parent) : QObject(parent) { allowedAddresses = NULL; connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection())); server.listen(address, port); } MaiaXmlRpcServer::MaiaXmlRpcServer(quint16 port, QObject* parent) : QObject(parent) { allowedAddresses = NULL; connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection())); server.listen(QHostAddress::Any, port); } MaiaXmlRpcServer::MaiaXmlRpcServer(const QHostAddress &address, quint16 port, QList *allowedAddresses, QObject *parent) : QObject(parent) { this->allowedAddresses = allowedAddresses; connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection())); server.listen(address, port); } void MaiaXmlRpcServer::addMethod(QString method, QObject* responseObject, const char* responseSlot) { objectMap[method] = responseObject; slotMap[method] = responseSlot; } void MaiaXmlRpcServer::removeMethod(QString method) { objectMap.remove(method); slotMap.remove(method); } void MaiaXmlRpcServer::getMethod(QString method, QObject **responseObject, const char **responseSlot) { if(!objectMap.contains(method)) { *responseObject = NULL; *responseSlot = NULL; return; } *responseObject = objectMap[method]; *responseSlot = slotMap[method]; } void MaiaXmlRpcServer::newConnection() { QTcpSocket *connection = server.nextPendingConnection(); if (!this->allowedAddresses || this->allowedAddresses->isEmpty() || this->allowedAddresses->contains(connection->peerAddress())) { MaiaXmlRpcServerConnection *client = new MaiaXmlRpcServerConnection(connection, this); connect(client, SIGNAL(getMethod(QString, QObject **, const char**)), this, SLOT(getMethod(QString, QObject **, const char**))); } else { qWarning() << "Rejected connection attempt from" << connection->peerAddress().toString(); connection->disconnectFromHost(); } } QHostAddress MaiaXmlRpcServer::getServerAddress() { return server.serverAddress(); } qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcServer.h000664 001750 001750 00000004643 12440612574 021064 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcServer.h * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAIAXMLRPCSERVER_H #define MAIAXMLRPCSERVER_H #include #include #include #include "maiaObject.h" #include "maiaXmlRpcServerConnection.h" class MaiaXmlRpcServer : public QObject { Q_OBJECT public: MaiaXmlRpcServer(const QHostAddress &address = QHostAddress::Any, quint16 port = 8080, QObject* parent = 0); MaiaXmlRpcServer(const QHostAddress &address = QHostAddress::Any, quint16 port = 8080, QList *allowedAddresses = 0, QObject *parent = 0); MaiaXmlRpcServer(quint16 port = 8080, QObject* parent = 0); void addMethod(QString method, QObject *responseObject, const char* responseSlot); void removeMethod(QString method); QHostAddress getServerAddress(); public slots: void getMethod(QString method, QObject **responseObject, const char** responseSlot); private slots: void newConnection(); private: QTcpServer server; QHash objectMap; QHash slotMap; QList *allowedAddresses; friend class maiaXmlRpcServerConnection; }; #endif qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcServerConnection.cpp000664 001750 001750 00000022470 12474354470 023442 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcServerConnection.cpp * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maiaXmlRpcServerConnection.h" #include "maiaXmlRpcServer.h" MaiaXmlRpcServerConnection::MaiaXmlRpcServerConnection(QTcpSocket *connection, QObject* parent) : QObject(parent) { header = NULL; clientConnection = connection; connect(clientConnection, SIGNAL(readyRead()), this, SLOT(readFromSocket())); connect(clientConnection, SIGNAL(disconnected()), this, SLOT(deleteLater())); } MaiaXmlRpcServerConnection::~MaiaXmlRpcServerConnection() { clientConnection->deleteLater(); delete header; } void MaiaXmlRpcServerConnection::readFromSocket() { QString lastLine; while(clientConnection->canReadLine() && !header) { lastLine = clientConnection->readLine(); headerString += lastLine; if(lastLine == "\r\n") { /* http header end */ header = new QHttpRequestHeader(headerString); if(!header->isValid()) { /* return http error */ qDebug() << "Invalid Header"; return; } else if(header->method() != "POST") { /* return http error */ qDebug() << "No Post!"; return; } else if(!header->contentLength()) { /* return fault */ qDebug() << "No Content Length"; return; } } } if(header) { if(header->contentLength() <= clientConnection->bytesAvailable()) { /* all data complete */ parseCall(clientConnection->readAll()); } } } void MaiaXmlRpcServerConnection::sendResponse(QString content) { QHttpResponseHeader header(200, "OK"); QByteArray block; header.setValue("Server", "MaiaXmlRpc/0.1"); header.setValue("Content-Type", "text/xml"); header.setValue("Connection","close"); header.setContentLength(content.toUtf8().length()); block.append(header.toString().toUtf8()); block.append(content.toUtf8()); clientConnection->write(block); clientConnection->disconnectFromHost(); } void MaiaXmlRpcServerConnection::parseCall(QString call) { QDomDocument doc; QList args; QVariant ret; QString response; QObject *responseObject; const char *responseSlot; if(!doc.setContent(call)) { /* received invalid xml */ MaiaFault fault(-32700, "parse error: not well formed"); sendResponse(fault.toString()); return; } QDomElement methodNameElement = doc.documentElement().firstChildElement("methodName"); QDomElement params = doc.documentElement().firstChildElement("params"); if(methodNameElement.isNull()) { /* invalid call */ MaiaFault fault(-32600, "server error: invalid xml-rpc. not conforming to spec"); sendResponse(fault.toString()); return; } QString methodName = methodNameElement.text(); // qDebug() << "methodname" << methodName; emit getMethod(methodName, &responseObject, &responseSlot); if(!responseObject) { /* unknown method */ MaiaFault fault(-32601, "server error: requested method not found"); sendResponse(fault.toString()); return; } QDomNode paramNode = params.firstChild(); while(!paramNode.isNull()) { args << MaiaObject::fromXml( paramNode.firstChild().toElement()); paramNode = paramNode.nextSibling(); } if(!invokeMethodWithVariants(responseObject, responseSlot, args, &ret)) { /* error invoking... */ MaiaFault fault(-32602, "server error: invalid method parameters"); sendResponse(fault.toString()); return; } if(ret.canConvert()) { response = ret.value().toString(); } else { response = MaiaObject::prepareResponse(ret); } sendResponse(response); } /* taken from http://delta.affinix.com/2006/08/14/invokemethodwithvariants/ thanks to Justin Karneges once again :) */ bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type) { // QMetaObject::invokeMethod() has a 10 argument maximum if(args.count() > 10) return false; QList argTypes; for(int n = 0; n < args.count(); ++n) argTypes += args[n].typeName(); // get return type int metatype = 0; QByteArray retTypeName = getReturnType(obj->metaObject(), method, argTypes); if(!retTypeName.isEmpty() && retTypeName != "QVariant") { metatype = QMetaType::type(retTypeName.data()); // qDebug() << QMetaType::typeName(metatype); if(metatype == 0) // lookup failed return false; } QGenericArgument arg[10]; for(int n = 0; n < args.count(); ++n) arg[n] = QGenericArgument(args[n].typeName(), args[n].constData()); QGenericReturnArgument retarg; QVariant retval; QString test(QMetaType::typeName(metatype)); if(metatype != 0) { if( test=="void") { retval=QVariant(); retTypeName=""; } else { retval = QVariant(metatype, (const void *)0); } retarg = QGenericReturnArgument(retval.typeName(), retval.data()); } else { /* QVariant */ retarg = QGenericReturnArgument("QVariant", &retval); } if(retTypeName.isEmpty()) { /* void */ if(!QMetaObject::invokeMethod(obj, method.data(), type, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9])) return false; } else { if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9])) return false; } if(retval.isValid() && ret) *ret = retval; return true; } QByteArray getReturnType(const QMetaObject *obj,const QByteArray &method, const QList argTypes) { for(int n = 0; n < obj->methodCount(); ++n) { QMetaMethod m = obj->method(n); #if QT_VERSION >= 0x050000 QByteArray sig = m.methodSignature(); #else QByteArray sig = m.signature(); #endif int offset = sig.indexOf('('); if(offset == -1) continue; QByteArray name = sig.mid(0, offset); if(name != method) continue; if(m.parameterTypes() != argTypes) continue; return m.typeName(); } return QByteArray(); } /* simple Qt4 class emulater */ #if QT_VERSION >= 0x050000 QHttpRequestHeader::QHttpRequestHeader(QString headerString) { this->mHeaderString = headerString; QStringList hdrs = headerString.split("\r\n"); QStringList hdrkv; for (int i = 0; i < hdrs.size(); i++) { if (hdrs.at(i).trimmed().isEmpty()) break; if (i == 0) { hdrkv = hdrs.at(i).split(" "); this->mMethod = hdrkv.at(0); } else { hdrkv = hdrs.at(i).split(":"); this->mHeaders[hdrkv.at(0)] = hdrkv.at(1).trimmed(); } } } bool QHttpRequestHeader::isValid() { if (this->mHeaderString.isEmpty()) return false; if (this->mMethod != "GET" && this->mMethod != "POST") return false; if (this->mHeaders.size() < 2) return false; return true; } QString QHttpRequestHeader::method() { return this->mMethod; } uint QHttpRequestHeader::contentLength() const { uint clen = 0; clen = this->mHeaders.value("Content-length").toUInt(); return clen; } QHttpResponseHeader::QHttpResponseHeader(int code, QString text) { this->mCode = code; this->mText = text; } void QHttpResponseHeader::setValue(const QString &key, const QString &value) { this->mHeaders[key] = value; } QString QHttpResponseHeader::toString() const { QMapIterator it(this->mHeaders); QString hdrstr; hdrstr += QString("HTTP/1.1 %1 %2\r\n").arg(this->mCode).arg(this->mText); while (it.hasNext()) { it.next(); hdrstr += it.key() + ": " + it.value() + "\r\n"; } hdrstr += "\r\n"; return hdrstr; } #endif qsstv_8.2.12/qsstv/xmlrpc/maiaXmlRpcServerConnection.h000664 001750 001750 00000006056 12474354470 023111 0ustar00jomajoma000000 000000 /* * libMaia - maiaXmlRpcServerConnection.h * Copyright (c) 2007 Sebastian Wiedenroth * and Karl Glatz * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAIAXMLRPCSERVERCONNECTION_H #define MAIAXMLRPCSERVERCONNECTION_H #include #include #include #include "maiaFault.h" #if QT_VERSION >= 0x050000 class QHttpRequestHeader { public: explicit QHttpRequestHeader(QString headerString); virtual ~QHttpRequestHeader() {} bool isValid(); QString method(); uint contentLength() const; private: QString mHeaderString; QString mMethod; QMap mHeaders; }; class QHttpResponseHeader { public: explicit QHttpResponseHeader(int code, QString text); virtual ~QHttpResponseHeader() {} void setValue(const QString &key, const QString &value); virtual QString toString() const; void setContentLength(int len) { setValue("Content-length", QString::number(len)); } private: int mCode; QString mText; QMap mHeaders; }; #endif class MaiaXmlRpcServerConnection : public QObject { Q_OBJECT public: MaiaXmlRpcServerConnection(QTcpSocket *connection, QObject *parent = 0); ~MaiaXmlRpcServerConnection(); signals: void getMethod(QString method, QObject **responseObject, const char **responseSlot); private slots: void readFromSocket(); private: void sendResponse(QString content); void parseCall(QString call); QTcpSocket *clientConnection; QString headerString; QHttpRequestHeader *header; }; QByteArray getReturnType(const QMetaObject *obj, const QByteArray &method, const QList argTypes); bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection); #endif qsstv_8.2.12/qsstv/xmlrpc/xmlinterface.cpp000664 001750 001750 00000007052 12474354470 020656 0ustar00jomajoma000000 000000 #include "xmlinterface.h" #include "qsstvglobal.h" xmlInterface::xmlInterface(QObject *parent) : QObject(parent) { rigInfo.trxState="RX"; rpcServer = new MaiaXmlRpcServer(7362, this); rpcServer->addMethod("main.get_trx_state", this, "getTrxState"); rpcServer->addMethod("rig.take_control", this, "takeControl"); rpcServer->addMethod("rig.set_name", this, "setName"); rpcServer->addMethod("rig.set_modes", this, "setModes"); rpcServer->addMethod("rig.set_mode", this, "setMode"); rpcServer->addMethod("rig.set_bandwidths", this, "setBandwidths"); rpcServer->addMethod("rig.set_bandwidth", this, "setBandwidth"); rpcServer->addMethod("main.set_wf_sideband", this, "setWfSideband"); rpcServer->addMethod("rig.set_frequency", this, "setFrequency"); rpcServer->addMethod("system.multicall", this, "systemMulticall"); rpcServer->addMethod("main.get_frequency", this, "getFrequency"); rpcServer->addMethod("rig.get_mode", this, "getMode"); rpcServer->addMethod("rig.get_bandwidth", this, "getBandwidth"); } void xmlInterface::takeControl() { log("takeControl",""); } void xmlInterface::setName(QString t) { rigInfo.rigName=t; log("setName",t); } void xmlInterface::setMode(QString t) { rigInfo.mode=t; log("setMode",t); } void xmlInterface::setModes(QVariantList t) { log("setModes",t); } void xmlInterface::setBandwidths(QVariantList t) { log("setBandwidths",t); } void xmlInterface::setBandwidth(QString t) { rigInfo.bandWidth=t; log("setBandwidth",t); } void xmlInterface::setWfSideband(QString t) { log("setWfSideband",t); } void xmlInterface::setFrequency(double d) { rigInfo.frequency=d; log("setFrequency",QString::number(d,'g',9)); } QString xmlInterface::getTrxState() { // log("getTrxSate",rigInfo.trxState); return rigInfo.trxState; } double xmlInterface::getFrequency() { log("getFrequency",QString::number(rigInfo.frequency,'g',9)); // return rigInfo.frequency; return 14077777; } QString xmlInterface::getMode() { log("getMode",rigInfo.mode); return rigInfo.mode; } QString xmlInterface::getBandwidth() { log("getBandwidth",rigInfo.bandWidth); return rigInfo.bandWidth; } QVariantList xmlInterface::systemMulticall(QVariantList s) { QVariant ret; QVariantMap m; QVariantList args; QVariantList tmp; QVariantList results; // QString response; QObject *responseObject; const char *responseSlot; int i,j; log("systemMulticall",s); for(i=0;igetMethod(m["methodName"].toString(), &responseObject, &responseSlot); if(responseObject!=0) { args=m["params"].toList(); for(j=0;j #include "maiaXmlRpcServer.h" #include "maiaXmlRpcServerConnection.h" struct sxmlInfo { sxmlInfo() { frequency=-1.; } QString rigName; QString bandWidth; double frequency; QString mode; QString trxState; }; class xmlInterface : public QObject { Q_OBJECT public: explicit xmlInterface(QObject *parent = 0); void activatePTT(bool b); public slots: void takeControl(); void setName(QString t); void setModes(QVariantList t); void setBandwidths(QVariantList t); void setBandwidth(QString t); void setWfSideband(QString t); void setMode(QString t); void setFrequency(double d); QVariantList systemMulticall(QVariantList s); double getFrequency(); QString getMode(); QString getBandwidth(); QString getTrxState(); private: MaiaXmlRpcServer *rpcServer; void log(QString cmd,QString t); void log(QString cmd, QVariantList t); sxmlInfo rigInfo; }; #endif // XMLINTERFACE_H qsstv_8.2.12/qsstv/COPYING000664 001750 001750 00000104517 12440612574 015216 0ustar00jomajoma000000 000000 QSSTV uses Qt see http://qt.digia.com/ if any restrictions apply. As far as I know, QSSTV does not use any none-public software. If there are doubts, please let me know by email: on4qz@telenet.be If part of whole of this code is used, you have to include a statement to indicate that the program is based in whole or in part on QSSTV. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qsstv_8.2.12/qsstv/Doxyfile000664 001750 001750 00000227653 12440612574 015700 0ustar00jomajoma000000 000000 # Doxyfile 1.7.6.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = "QSSTV" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 8.2.7 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "SSTV and HAMDRM" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = Documentation # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ./. # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES qsstv_8.2.12/qsstv/configdialog.cpp000664 001750 001750 00000047546 12473461473 017332 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "configdialog.h" #include "configparams.h" #include #include #include #include "sstv/sstvparam.h" //#include #include #include "qsstvglobal.h" #include "utils/supportfunctions.h" #include "videocapt/videocapture.h" #include "rig/rigcontrol.h" #include "mainwindow.h" #include "sound/soundcontrol.h" #include "txwidget.h" #include "utils/ftp.h" #include "utils/hybridcrypt.h" #include /** \class configDialog The configDialog provides access to the application-wide configuration parameters. */ /** constructor for configDialog */ configDialog::configDialog(QWidget *, const char *) :Ui::configForm() { setupUi(this); int i=0; setModal(false); foreach (QByteArray format, QImageWriter::supportedImageFormats()) { QString text = tr("%1").arg(QString(format)); defaultImageFormatComboBox->addItem(text); ftpDefaultImageFormatComboBox->addItem(text); } for(i=0;i<(NUMSSTVMODES-1);i++) // exclude Calibrate { repeaterTxModeComboBox->addItem(getSSTVModeNameLong((esstvMode)i)); } rigWidget->attachRigController(rigControllerR1); // rigR2Widget->attachRigController(rigControllerR2); readSettings(); connect(rxImagesPathBrowseButton,SIGNAL(clicked()),SLOT(slotBrowseRxImagesPath())); connect(txImagesPathBrowseButton,SIGNAL(clicked()),SLOT(slotBrowseTxImagesPath())); connect(templatesPathBrowseButton,SIGNAL(clicked()),SLOT(slotBrowseTemplatesPath())); connect(audioPathBrowseButton,SIGNAL(clicked()),SLOT(slotBrowseAudioPath())); connect(rp1BrowseButton,SIGNAL(clicked()),SLOT(slotRp1BrowseButton())); connect(rp2BrowseButton,SIGNAL(clicked()),SLOT(slotRp2BrowseButton())); connect(rp3BrowseButton,SIGNAL(clicked()),SLOT(slotRp3BrowseButton())); connect(rp4BrowseButton,SIGNAL(clicked()),SLOT(slotRp4BrowseButton())); connect(repeaterTemplateBrowseButton,SIGNAL(clicked()),SLOT(slotRepeaterTemplateBrowseButton())); connect(idleTemplateBrowseButton,SIGNAL(clicked()),SLOT(slotIdleTemplateBrowseButton())); drmProfilePtr=drmProfileWidget; tabWidget->setCurrentIndex(0); connect(testFTPPushButton,SIGNAL(clicked()),SLOT(slotTestFTPPushButton())); connect(testHybridPushButton,SIGNAL(clicked()),SLOT(slotTestHybridPushButton())); } /** destructor for configDialog */ configDialog::~configDialog() { } /** read variables from config file Read the config file and initializes the variables. If not found, default values will be used. \sa writeSettings */ void configDialog::readSettings() { QSettings qSettings; qSettings.beginGroup("Config"); myCallsign=qSettings.value("callsign",QString("NOCALL")).toString(); myQth=qSettings.value("qth",QString("NOWHERE")).toString(); myLastname=qSettings.value("lastname",QString("NONAME")).toString(); myFirstname=qSettings.value("firstname",QString("NOFIRSTNAME")).toString(); myLocator=qSettings.value("locator",QString("NOLOCATOR")).toString(); rxImagesPath=qSettings.value("rxImagesPath",QString(getenv("HOME"))+"/").toString(); txImagesPath=qSettings.value("txImagesPath",QString(getenv("HOME"))+"/").toString(); templatesPath=qSettings.value("templatesPath",QString(getenv("HOME"))+"/").toString(); docURL=qSettings.value("docURL","http://users.telenet.be/on4qz/qsstv/manual").toString(); audioPath=qSettings.value("audioPath",QString(getenv("HOME"))+"/").toString(); defaultImageFormat=qSettings.value("defaultImageFormat","png").toString(); // fontString=qSettings.value("fontString","").toString(); samplingrate=qSettings.value("samplingrate",11025).toInt(); cwText=qSettings.value("cwtext","").toString(); cwTone=qSettings.value("cwtone",800).toInt(); cwWPM=qSettings.value("cwWPM",12).toInt(); enableFTP=qSettings.value("enableFTP",false).toBool(); ftpPort=qSettings.value("ftpPort",21).toInt(); ftpRemoteHost=qSettings.value("ftpRemoteHost","").toString(); ftpRemoteDirectory=qSettings.value("ftpRemoteDirectory","").toString(); ftpLogin=qSettings.value("ftpLogin","").toString(); ftpPassword=qSettings.value("ftpPassword","").toString(); ftpFilename=qSettings.value("ftpFilename","").toString(); ftpDefaultImageFormat=qSettings.value("ftpDefaultImageFormat","png").toString(); ftpSaveFormat=(eftpSaveFormat)qSettings.value("ftpSaveFormat",0).toInt(); ftpNumImages=qSettings.value("ftpNumImages",30).toInt(); enableHybridRx=qSettings.value("enableHybridRx",true).toBool(); enableSpecialServer=qSettings.value("enableSpecialServer",false).toBool(); hybridFtpPort=qSettings.value("hybridFtpPort",21).toInt(); hybridFtpRemoteHost=qSettings.value("hybridFtpRemoteHost","").toString(); hybridFtpRemoteDirectory=qSettings.value("hybridFtpRemoteDirectory","").toString(); hybridFtpHybridFilesDirectory=qSettings.value("hybridFtpHybridFilesDirectory","HybridFiles1").toString(); hybridFtpLogin=qSettings.value("hybridFtpLogin","").toString(); hybridFtpPassword=qSettings.value("hybridFtpPassword","").toString(); repeaterImageInterval=qSettings.value("repeaterImageInterval",10).toInt(); repeaterEnable=qSettings.value("repeaterEnable",false).toBool(); repeaterTxMode=(esstvMode)qSettings.value("repeaterTxMode",0).toInt(); repeaterImage1=qSettings.value("repeaterImage1","").toString(); repeaterImage2=qSettings.value("repeaterImage2","").toString(); repeaterImage3=qSettings.value("repeaterImage3","").toString(); repeaterImage4=qSettings.value("repeaterImage4","").toString(); repeaterAcknowledge=qSettings.value("repeaterAcknowledge","").toString(); repeaterTemplate=qSettings.value("repeaterTemplate","").toString(); idleTemplate=qSettings.value("idleTemplate","").toString(); videoDevice=qSettings.value("videoDevice","/dev/video0").toString(); channelNumber=qSettings.value("channelNumber",0).toInt(); // framesPerSecondIndex=qSettings.value("framesPerSecondIndex",0).toInt(); colorFormatIndex=qSettings.value("colorFormatIndex",0).toInt(); // DRM startPicWF=qSettings.value("startPicWF","START PIC").toString(); endPicWF=qSettings.value("endPicWF","END PIC").toString(); fixWF=qSettings.value("fixWF","FIX").toString(); bsrWF=qSettings.value("bsrWF","BSR").toString(); sizeIndex=qSettings.value("sizeIndex",0).toInt(); qSettings.endGroup(); setParams(); soundWidget->readSettings(); rigWidget->readSettings(); } /** write variables to config file \sa readSettings */ void configDialog::writeSettings() { rigWidget->writeSettings(); soundWidget->writeSettings(); getParams(); QSettings qSettings; qSettings.beginGroup("Config"); qSettings.setValue("callsign",myCallsign); qSettings.setValue("qth",myQth); qSettings.setValue("locator",myLocator); qSettings.setValue("lastname",myLastname); qSettings.setValue("firstname",myFirstname); qSettings.setValue("rxImagesPath",rxImagesPath); qSettings.setValue("txImagesPath",txImagesPath); qSettings.setValue("templatesPath",templatesPath); qSettings.setValue("audioPath",audioPath); qSettings.setValue("docURL",docURL); qSettings.setValue("defaultImageFormat",defaultImageFormat); // qSettings.setValue("fontString",fontString); qSettings.setValue("samplingrate",samplingrate); qSettings.setValue("cwtext",cwText); qSettings.setValue("cwtone",cwTone); qSettings.setValue("cwWPM",cwWPM); qSettings.setValue("enableFTP",enableFTP); qSettings.setValue("ftpPort",ftpPort); qSettings.setValue("ftpRemoteHost",ftpRemoteHost); qSettings.setValue("ftpRemoteDirectory",ftpRemoteDirectory); qSettings.setValue("ftpLogin",ftpLogin); qSettings.setValue("ftpPassword",ftpPassword); qSettings.setValue("ftpFilename",ftpFilename); qSettings.setValue("ftpDefaultImageFormat",ftpDefaultImageFormat); qSettings.setValue("ftpSaveFormat",(int)ftpSaveFormat); qSettings.setValue("ftpNumImages",ftpNumImages); qSettings.setValue("repeaterImageInterval",repeaterImageInterval); qSettings.setValue("enableHybridRx",enableHybridRx); qSettings.setValue("enableSpecialServer",enableSpecialServer); qSettings.setValue("hybridFtpPort",hybridFtpPort); qSettings.setValue("hybridFtpRemoteHost",hybridFtpRemoteHost); qSettings.setValue("hybridFtpRemoteDirectory",hybridFtpRemoteDirectory); qSettings.setValue("hybridFtpHybridFilesDirectory",hybridFtpHybridFilesDirectory); qSettings.setValue("hybridFtpLogin",hybridFtpLogin); qSettings.setValue("hybridFtpPassword",hybridFtpPassword); qSettings.setValue("repeaterEnable",repeaterEnable); qSettings.setValue("repeaterTxMode",repeaterTxMode); qSettings.setValue("repeaterImage1",repeaterImage1); qSettings.setValue("repeaterImage2",repeaterImage2); qSettings.setValue("repeaterImage3",repeaterImage3); qSettings.setValue("repeaterImage4",repeaterImage4); qSettings.setValue("repeaterAcknowledge",repeaterAcknowledge); qSettings.setValue("repeaterTemplate",repeaterTemplate); qSettings.setValue("idleTemplate",idleTemplate); qSettings.setValue("videoDevice",videoDevice); qSettings.setValue("channelNumber",channelNumber); // qSettings.setValue("framesPerSecondIndex",framesPerSecondIndex); qSettings.setValue("colorFormatIndex",colorFormatIndex); qSettings.setValue("sizeIndex",sizeIndex); qSettings.setValue("startPicWF",startPicWF); qSettings.setValue("endPicWF",endPicWF); qSettings.setValue("fixWF",fixWF); qSettings.setValue("bsrWF",bsrWF); qSettings.endGroup(); drmProfileWidget->writeSettings(); } /** Opens the configuration dialog */ int configDialog::exec() { videoCapture vc; int i=0; colorFormatComboBox->clear(); sizeComboBox->clear(); if(vc.open()) { QList description; vc.getFormatList(description); for(i=0;iaddItem(description[i]); } QList sizeList(vc.getSizesList()); for(i=0;iaddItem(QString::number(sizeList[i].width())+ " x " + QString::number(sizeList[i].height())); } vc.close(); } setParams(); soundWidget->setParams(); drmProfileWidget->setParams(); if(QDialog::exec()) { writeSettings(); txWidgetPtr->setProfileNames(); mainWindowPtr->setNewFont(); return QDialog::Accepted; } else { return QDialog::Rejected; } } /** copies the values from the variables to the userinterface \sa getParams */ void configDialog::setParams() { setValue(myCallsign,callsignLineEdit); setValue(myLastname,lastnameLineEdit); setValue(myFirstname,firstnameLineEdit); setValue(myQth,qthLineEdit); setValue(myLocator,locatorLineEdit); setValue(rxImagesPath, rxImagesPathLineEdit); setValue(txImagesPath, txImagesPathLineEdit); setValue(templatesPath, templatesPathLineEdit); setValue(audioPath, audioPathLineEdit); setValue(docURL, docPathLineEdit); setValue(defaultImageFormat, defaultImageFormatComboBox); QFont fnt; // fnt.fromString(fontString); // fontComboBox->setCurrentFont(fnt); // setValue(fnt.pointSize(),fontSizeSpinBox); setValue(cwText,cwTextLineEdit); setValue(cwTone,cwToneSpinBox); setValue(cwWPM,cwWPMSpinBox); setValue(enableFTP,enableFTPCheckBox); setValue(ftpPort,ftpPortSpinBox); setValue(ftpRemoteHost,remoteHostLineEdit); setValue(ftpRemoteDirectory,remoteDirectoryLineEdit); setValue(ftpLogin,ftpLoginLineEdit); setValue(ftpPassword,ftpPasswordLineEdit); if(ftpSaveFormat==FTPIM) { imageRadioButton->setChecked(true); } else { filenameRadioButton->setChecked(true); } setValue(ftpNumImages,ftpNumImagesSpinBox); setValue(enableHybridRx,enableHybridRxCheckBox); setValue(enableSpecialServer,enableSpecialServerCheckBox); setValue(hybridFtpPort,hybridFtpPortSpinBox); setValue(hybridFtpRemoteHost,hybridRemoteHostLineEdit); setValue(hybridFtpRemoteDirectory,hybridRemoteDirectoryLineEdit); setValue(hybridFtpHybridFilesDirectory,hybridFilesDirectoryLineEdit); setValue(hybridFtpLogin,hybridFtpLoginLineEdit); setValue(hybridFtpPassword,hybridFtpPasswordLineEdit); setValue(ftpDefaultImageFormat,ftpDefaultImageFormatComboBox); setValue(repeaterEnable,repeaterEnableCheckBox); setIndex(repeaterTxMode,repeaterTxModeComboBox); setValue(repeaterImage1,repeaterImage1LineEdit); setValue(repeaterImage2,repeaterImage2LineEdit); setValue(repeaterImage3,repeaterImage3LineEdit); setValue(repeaterImage4,repeaterImage4LineEdit); setValue(idleTemplate,idleTemplateLineEdit); setValue(repeaterTemplate,repeaterTemplateLineEdit); setValue(videoDevice,videoDeviceLineEdit); setValue(channelNumber, channelSpinBox); setIndex(colorFormatIndex,colorFormatComboBox); setIndex(sizeIndex,sizeComboBox); setValue(startPicWF,startPicTextEdit); setValue(endPicWF,endPicTextEdit); setValue(fixWF,fixTextEdit); setValue(bsrWF,bsrTextEdit); } /** copies the values from the userinterface to the variables \sa setParams */ void configDialog::getParams() { getValue(myCallsign,callsignLineEdit); getValue(myLastname,lastnameLineEdit); getValue(myFirstname,firstnameLineEdit); getValue(myQth,qthLineEdit); getValue(myLocator,locatorLineEdit); getValue(rxImagesPath, rxImagesPathLineEdit); getValue(txImagesPath, txImagesPathLineEdit); getValue(templatesPath, templatesPathLineEdit); getValue(audioPath, audioPathLineEdit); getValue(docURL, docPathLineEdit); getValue(defaultImageFormat, defaultImageFormatComboBox); // QFont fnt(fontComboBox->currentFont()); // fnt.setPointSize(fontSizeSpinBox->value()); // fontString=fnt.toString(); getValue(cwText,cwTextLineEdit); getValue(cwTone,cwToneSpinBox); getValue(cwWPM,cwWPMSpinBox); getValue(enableFTP,enableFTPCheckBox); getValue(ftpPort,ftpPortSpinBox); getValue(ftpRemoteHost,remoteHostLineEdit); getValue(ftpRemoteDirectory,remoteDirectoryLineEdit); getValue(ftpLogin,ftpLoginLineEdit); getValue(ftpPassword,ftpPasswordLineEdit); // getValue(ftpFilename,ftpFilenameLineEdit); if(imageRadioButton->isChecked()) { ftpSaveFormat=FTPIM; } else { ftpSaveFormat=FTPFILE; } getValue(ftpNumImages,ftpNumImagesSpinBox); getValue(ftpDefaultImageFormat,ftpDefaultImageFormatComboBox); getValue(enableHybridRx,enableHybridRxCheckBox); getValue(enableSpecialServer,enableSpecialServerCheckBox); getValue(hybridFtpPort,hybridFtpPortSpinBox); getValue(hybridFtpRemoteHost,hybridRemoteHostLineEdit); getValue(hybridFtpRemoteDirectory,hybridRemoteDirectoryLineEdit); getValue(hybridFtpHybridFilesDirectory,hybridFilesDirectoryLineEdit); getValue(hybridFtpLogin,hybridFtpLoginLineEdit); getValue(hybridFtpPassword,hybridFtpPasswordLineEdit); getValue(repeaterEnable,repeaterEnableCheckBox); int temp; getIndex(temp,repeaterTxModeComboBox); repeaterTxMode=esstvMode(temp); getValue(repeaterImage1,repeaterImage1LineEdit); getValue(repeaterImage2,repeaterImage2LineEdit); getValue(repeaterImage3,repeaterImage3LineEdit); getValue(repeaterImage4,repeaterImage4LineEdit); getValue(idleTemplate,idleTemplateLineEdit); getValue(repeaterTemplate,repeaterTemplateLineEdit); getValue(videoDevice,videoDeviceLineEdit); getValue(channelNumber, channelSpinBox); getIndex(colorFormatIndex,colorFormatComboBox); getIndex(sizeIndex,sizeComboBox); getValue(startPicWF,startPicTextEdit); getValue(endPicWF,endPicTextEdit); getValue(fixWF,fixTextEdit); getValue(bsrWF,bsrTextEdit); } /** Browse function for path where the rximages are stored */ void configDialog::slotBrowseRxImagesPath() { browseDir(rxImagesPathLineEdit,rxImagesPath); } /** Browse function for path where the tximages are stored */ void configDialog::slotBrowseTxImagesPath() { browseDir(txImagesPathLineEdit,txImagesPath); } /** Browse function for path where the templates are stored */ void configDialog::slotBrowseTemplatesPath() { browseDir(templatesPathLineEdit,templatesPath); } /** Browse function for audio path */ void configDialog::slotBrowseAudioPath() { browseDir(audioPathLineEdit,audioPath); } /** Browse function for documentation path */ void configDialog::slotRp1BrowseButton() { browseGetFile(repeaterImage1LineEdit,txImagesPath); } void configDialog::slotRp2BrowseButton() { browseGetFile(repeaterImage2LineEdit,txImagesPath); } void configDialog::slotRp3BrowseButton() { browseGetFile(repeaterImage3LineEdit,txImagesPath); } void configDialog::slotRp4BrowseButton() { browseGetFile(repeaterImage4LineEdit,txImagesPath); } void configDialog::slotRepeaterTemplateBrowseButton() { browseGetFile(repeaterTemplateLineEdit,templatesPath); } void configDialog::slotIdleTemplateBrowseButton() { browseGetFile(idleTemplateLineEdit,templatesPath); } void configDialog::slotTestFTPPushButton() { ftpInterface fInt("TestUploadConnection"); getParams(); fInt.setupConnection(ftpRemoteHost,ftpPort,ftpLogin,ftpPassword,ftpRemoteDirectory); execFTPTest(&fInt); } void configDialog::slotTestHybridPushButton() { ftpInterface fInt("TestHybridConnection"); getParams(); hybridCrypt hc; fInt.setupConnection(hc.host(),hc.port(),hc.user(),hc.passwd(),hc.dir()+"/"+hybridFtpHybridFilesDirectory); execFTPTest(&fInt); } void configDialog::execFTPTest(ftpInterface *ftpPtr) { eftpError ftpResult; QString fn(QString("%1/test.txt").arg(rxImagesPath)); //checkConnection QFile tst(fn); if(tst.open(QIODevice::WriteOnly)<=0) { QMessageBox::critical(this, tr("File Error"),QString("").arg(strerror(errno))); } tst.write("connection test\n"); tst.close(); ftpResult=ftpPtr->uploadFile(fn,QString("test_%1.txt").arg( myCallsign),true); switch(ftpResult) { case FTPCANCELED: QMessageBox::information(this, tr("FTP Info"),"Connection Canceled"); break; case FTPOK: QMessageBox::information(this, tr("FTP Info"),"Connection OK"); break; case FTPERROR: QMessageBox::critical(this, tr("FTP Error"),ftpPtr->getLastError()); break; case FTPNAMEERROR: QMessageBox::critical(this, tr("FTP Error"),"Error in filename"); break; case FTPTIMEOUT: QMessageBox::critical(this, tr("FTP Error"),"FTP timed out"); return; } tst.remove(); } qsstv_8.2.12/qsstv/configdialog.h000664 001750 001750 00000001660 12440612574 016754 0ustar00jomajoma000000 000000 #ifndef CONFIGDIALOG_H #define CONFIGDIALOG_H #include "ui_configform.h" /** @author Johan Maes - ON4QZ */ class ftpInterface; class configForm; //! configuration Dialog class configDialog: public QDialog, private Ui::configForm { Q_OBJECT public: configDialog(QWidget *parent = 0, const char *name = 0); ~configDialog(); void writeSettings(); void readSettings(); int exec(); public slots: void slotBrowseRxImagesPath(); void slotBrowseTxImagesPath(); void slotBrowseTemplatesPath(); void slotBrowseAudioPath(); void slotRp1BrowseButton(); void slotRp2BrowseButton(); void slotRp3BrowseButton(); void slotRp4BrowseButton(); void slotRepeaterTemplateBrowseButton(); void slotIdleTemplateBrowseButton(); void slotTestFTPPushButton(); void slotTestHybridPushButton(); private: void getParams(); void setParams(); void execFTPTest(ftpInterface *ftpPtr); }; #endif qsstv_8.2.12/qsstv/configform.ui000664 001750 001750 00000233435 12440612574 016655 0ustar00jomajoma000000 000000 configForm 0 0 733 441 9 ConfigForm 2 1 1 1 1 true QTabWidget::Rounded 9 Personal Settings 2 1 1 1 1 0 0 130 25 Callsign false Qt::AlignRight Qt::Horizontal QSizePolicy::Expanding 120 20 0 0 130 25 Firstname false Qt::AlignRight Qt::Horizontal QSizePolicy::Expanding 120 20 0 0 130 25 Lastname false Qt::AlignRight Qt::Horizontal QSizePolicy::Expanding 120 20 0 0 130 25 QTH false Qt::AlignRight Qt::Horizontal QSizePolicy::Expanding 120 20 0 0 130 25 Locator false Qt::AlignRight Qt::Horizontal QSizePolicy::Expanding 120 20 Qt::Vertical QSizePolicy::Expanding 21 30 Directories 6 0 0 0 0 0 0 150 25 RX Images false 0 0 Browse ... 6 0 0 0 0 0 0 150 25 TX Images false 0 0 Browse ... 6 0 0 0 0 0 0 150 25 Templates false 0 0 Browse ... 6 0 0 0 0 0 0 150 25 Audio Records false 0 0 Browse ... 6 0 0 0 0 0 0 150 25 Documentation false 0 0 150 25 Default Image format false Qt::Vertical QSizePolicy::Expanding 20 40 Audio CAT CW 6 0 0 0 0 0 0 145 25 Tone false 300 2300 50 800 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 0 0 0 0 0 145 25 Words PerMinute false 4 30 12 Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 0 0 0 0 0 145 25 Text to send false Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Expanding 20 160 Repeater Enable Repeater Qt::Horizontal QSizePolicy::Expanding 20 20 6 0 0 0 0 Image Interval (min) false 5 Qt::Horizontal QSizePolicy::Expanding 60 20 6 0 0 0 0 Repeater TX mode false 6 0 0 0 0 Idle Image 1 false false 0 0 Browse ... 6 0 0 0 0 Idle Image 2 false false 0 0 Browse ... 6 0 0 0 0 Idle Image 3 false false 0 0 Browse ... 6 0 0 0 0 Idle Image 4 false false 0 0 Browse ... Idle Template false 0 0 Browse ... Repeater Template false 0 0 Browse ... FTP 6 0 0 0 0 Enable File Upload to FTP Server Qt::Horizontal QSizePolicy::Expanding 20 20 FTP Port false 1 10000 21 Qt::Horizontal QSizePolicy::Expanding 20 20 Default Image Format false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 Remote Hostname false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 Remote Directory false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 FTP Loginname false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 FTP Password false QLineEdit::Password Qt::Horizontal QSizePolicy::Preferred 20 20 Image store image1 to image 1 50 30 Qt::Horizontal 40 20 filename This ftp server is used to upload your received pictures. You can save them as a rotating sequence of images (image1 being the latest and image30 being the oldest) or simply under their own filename. true Test connection Qt::Vertical QSizePolicy::Expanding 20 66 Camera 0 0 145 25 Video device false Qt::Horizontal QSizePolicy::Expanding 245 20 0 0 145 25 Color Format Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false Qt::Horizontal QSizePolicy::Expanding 221 20 0 0 145 25 Size Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false Qt::Horizontal QSizePolicy::Expanding 131 20 0 0 145 25 Channel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 8 Qt::Horizontal QSizePolicy::Expanding 399 20 Qt::Vertical QSizePolicy::Expanding 21 50 Waterfall 0 0 145 25 Start Picture false 0 0 145 25 End Picture false 0 0 145 25 FIX false 0 0 145 25 BSR false Qt::Horizontal 40 20 Hybrid Enable Reception in Hybrid Mode true 6 0 0 0 0 Enable Special Server true Qt::Horizontal QSizePolicy::Expanding 20 20 FTP Port false 1 10000 21 Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 Remote Hostname false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 FTP Loginname false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 FTP Password false QLineEdit::Password Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 Remote Directory false Qt::Horizontal QSizePolicy::Preferred 20 20 6 0 0 0 0 0 0 145 25 Hybrid Files Directory false Qt::Horizontal QSizePolicy::Preferred 20 20 By default all hybrid files are uploaded to a default server ("Enable Special Server" not checked). If you wish to use your own server for sending in Hybrid mode then you need to check "Enable Special Server" and fill in the details. See manual for more information. true Test connection Qt::Vertical QSizePolicy::Expanding 20 191 DRM Profiles 2 0 0 0 0 Qt::Horizontal QSizePolicy::Expanding 20 20 OK Qt::Horizontal QSizePolicy::Expanding 20 20 Cancel Qt::Horizontal QSizePolicy::Expanding 20 20 qPixmapFromMimeSource soundControl QWidget
sound/soundcontrol.h
1
rigControlForm QWidget
rig/rigcontrolform.h
1
drmProfileForm QWidget
drmprofileform.h
1
okButton clicked() configForm accept() 20 20 20 20 cancelButton clicked() configForm reject() 20 20 20 20
qsstv_8.2.12/qsstv/configparams.cpp000664 001750 001750 00000007121 12440612574 017331 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "configparams.h" QString rxImagesPath; //!< path to the received images directory QString txImagesPath; //!< path to the transmit images directory QString templatesPath; //!< path to the templates directory QString audioPath; //!< directory path to the audio files QString docURL; //!< url of documentation QString defaultImageFormat; //!< the default format for to save the image in (e.g. png, jpg ..) //QString fontString; //int fontSize; int samplingrate; //!< samplingrate of the souncard (the nominal sampling frequency i.e. 8000, 11025 ...) double rxClock; //!< adjusted receive Clock double txClock; //!< adjusted transmit Clock QString serialPort; QString pttSerialPort; QString radioModel; int radioModelNumber; int civAddress; int baudrate; QString parity; int stopbits; int databits; QString handshake; bool enableCAT; //bool enableSerialPTT; QString cwText; //!< message to send in CW after sending the image int cwTone; //!< frequency of the CW signal int cwWPM; //!< CW words per minute bool enableFTP; int ftpPort; QString ftpRemoteHost; QString ftpRemoteDirectory; QString ftpLogin; QString ftpPassword; QString ftpFilename; QString ftpDefaultImageFormat; eftpSaveFormat ftpSaveFormat; int ftpNumImages; bool enableHybridRx; bool enableSpecialServer; int hybridFtpPort; QString hybridFtpRemoteHost; QString hybridFtpRemoteDirectory; QString hybridFtpHybridFilesDirectory; QString hybridFtpLogin; QString hybridFtpPassword; bool useHybrid; int repeaterImageInterval; bool repeaterEnable; esstvMode repeaterTxMode; QString repeaterImage1; QString repeaterImage2; QString repeaterImage3; QString repeaterImage4; QString idleTemplate; QString repeaterTemplate; QString repeaterAcknowledge; QString myCallsign; QString myQth; QString myLocator; QString myLastname; QString myFirstname; QString startPicWF; QString endPicWF; QString fixWF; QString bsrWF; QString drmCallsign; drmProfileForm *drmProfilePtr; QString videoDevice; //int framesPerSecondIndex; int colorFormatIndex; int sizeIndex; int channelNumber; etransmissionMode transmissionModeIndex; // SSTV or DRM or FAX unsigned int dataScopeOffset; qsstv_8.2.12/qsstv/configparams.h000664 001750 001750 00000004456 12440612574 017006 0ustar00jomajoma000000 000000 #ifndef CONFIGPARAMS_H #define CONFIGPARAMS_H #include "sstv/sstvparam.h" #include "drmprofileform.h" #include extern QString rxImagesPath; extern QString txImagesPath; extern QString templatesPath; extern QString audioPath; extern QString docURL; extern QString defaultImageFormat; //extern QString fontString; //extern int fontSize; extern int samplingrate; extern double rxClock; extern double txClock; extern QString serialPort; /**< serial port device*/ extern QString radioModel; extern int radioModelNumber; extern int civAddress; extern int baudrate; /**< serial port baudrate*/ extern QString parity; extern int stopbits; extern int databits; extern QString handshake; extern bool enableCAT; //extern bool enableSerialPTT; extern QString pttSerialPort; extern QString myCallsign; extern QString myQth; extern QString myLocator; extern QString myLastname; extern QString myFirstname; extern QString cwText; extern int cwTone; extern int cwWPM; extern bool enableFTP; extern int ftpPort; extern QString ftpRemoteHost; extern QString ftpRemoteDirectory; extern QString ftpLogin; extern QString ftpPassword; extern QString ftpFilename; extern QString ftpDefaultImageFormat; extern int ftpNumImages; extern bool enableHybridRx; extern bool enableSpecialServer; extern int hybridFtpPort; extern QString hybridFtpRemoteHost; extern QString hybridFtpRemoteDirectory; extern QString hybridFtpHybridFilesDirectory; extern QString hybridFtpLogin; extern QString hybridFtpPassword; extern bool useHybrid; enum eftpSaveFormat {FTPIM,FTPFILE}; extern eftpSaveFormat ftpSaveFormat; extern bool repeaterEnable; extern int repeaterImageInterval; extern esstvMode repeaterTxMode; extern QString repeaterImage1; extern QString repeaterImage2; extern QString repeaterImage3; extern QString repeaterImage4; extern QString repeaterAcknowledge; extern QString repeaterTemplate; extern QString idleTemplate; extern QString startPicWF; extern QString endPicWF; extern QString fixWF; extern QString bsrWF; extern QString drmCallsign; extern drmProfileForm *drmProfilePtr; extern QString videoDevice; //extern int framesPerSecondIndex; extern int colorFormatIndex; extern int sizeIndex; extern int channelNumber; extern etransmissionMode transmissionModeIndex; // SSTV , DRM or FAX extern unsigned int dataScopeOffset; #endif // CONFIGPARAMS_H qsstv_8.2.12/qsstv/dispatcher.cpp000664 001750 001750 00000037730 12473460726 017025 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /*! The dispatcher is the central system that routes all messages from the different threads. It also starts, stops and synchronizes the threads. */ #include "dispatcher.h" #include "qsstvglobal.h" #include "configparams.h" #include "rxwidget.h" #include "txwidget.h" #include "gallerywidget.h" #include #include "widgets/spectrumwidget.h" #include "widgets/vumeter.h" #include "rig/rigcontrol.h" #include "editor/editor.h" #include "sound/soundio.h" #include "sound/waterfalltext.h" #include "mainwindow.h" #include "drmrx/drm.h" #include "utils/ftp.h" #include "utils/hybridcrypt.h" /*! creates dispatcher instance */ dispatcher::dispatcher() { mbox = new QMessageBox(mainWindowPtr); progressFTP=NULL; serialP=0; } /*! delete dispatcher instance */ dispatcher::~dispatcher() { if(serialP!=0) { close(serialP); serialP=0; } } QString dispatcher::init() { QString ret; editorActive=false; rxWidgetPtr->fftDisplayPtr()->init(RXSTRIPE,1,BASESAMPLERATE/SUBSAMPLINGRATIO); galleryWidgetPtr->init(); rxWidgetPtr->init(); txWidgetPtr->init(); waterfallPtr=new waterfallText; waterfallPtr->init(); if(!rigController->init()) { ret=rigController->initError; } restartRXFlag=false; infoTextPtr=new textDisplay(mainWindowPtr); infoTextPtr->hide(); return ret; } void dispatcher::stopRX() { rxWidgetPtr->start(false); } void dispatcher::stopTX() { rigController->activatePTT(false); txWidgetPtr->start(false); } void dispatcher::stopRXTX() { stopRX(); stopTX(); } void dispatcher::startRX(bool st) { stopTX(); rxWidgetPtr->start(st); if(st) { addToLog("dispatcher: starting RX",LOGDISPAT); } else { addToLog("dispatcher: stopping RX",LOGDISPAT); } } void dispatcher::startTX(bool st) { stopRX(); if(st) { addToLog("dispatcher: starting TX",LOGDISPAT); } else { addToLog("dispatcher: stopping TX",LOGDISPAT); } rigController->activatePTT(st); txWidgetPtr->start(st); } void dispatcher::readSettings() { QSettings qSettings; logfile->readSettings(qSettings); } void dispatcher::writeSettings() { QSettings qSettings; logfile->writeSettings(qSettings); } /*! All communication between the threads are passed via this eventhandler. */ void dispatcher::customEvent( QEvent * e ) { dispatchEventType type; QString fn; type=(dispatchEventType)e->type(); addToLog(((baseEvent*)e)->description,LOGDISPAT); switch(type) { case displayFFT: addToLog("dispatcher: displayFFT",LOGDISPAT); rxWidgetPtr->fftDisplayPtr()->realFFT(((displayFFTEvent*)e)->data()); rxWidgetPtr->fftDisplayPtr()->repaint(); break; case displaySync: // addToLog("dispatcher: displaySync",LOGDISPAT); uint s;double v; ((displaySyncEvent*)e)->getInfo(s,v); rxWidgetPtr->sMeterPtr()->setValue((double)s); rxWidgetPtr->vMeterPtr()->setValue(v); break; case rxSSTVStatus: rxWidgetPtr->setSSTVStatusText(((statusMsgEvent*)e)->getStr()); break; case rxDRMStatus: rxWidgetPtr->setDRMStatusText(((statusMsgEvent*)e)->getStr()); break; case startImageRX: addToLog("dispatcher: clearing RxImage",LOGDISPAT); rxWidgetPtr->getImageViewerPtr()->createImage( ((startImageRXEvent*)e)->getSize(),QColor(255,255,0)); rxWidgetPtr->getImageViewerPtr()->clear(); break; case lineDisplay: { rxWidgetPtr->getImageViewerPtr()->displayImage(false); } break; // case syncLost: // case verticalRetrace: // addToLog("dispatcher: verticalRetrace",LOGDISPAT); // if(autoSave) // { // addToLog("dispatcher: verticalRetrace savingRxImage",LOGDISPAT); // saveRxSSTVImage(); // } // rxWidgetPtr->functionsPtr()->retraceVertical(); // break; case endImageRX: if(autoSave) { addToLog("dispatcher:endImage savingRxImage",LOGDISPAT); saveRxSSTVImage(); } break; case callEditor: if(editorActive) break; editorActive=true; ed=new editor(); ed->show(); iv=((callEditorEvent*)e)->getImageViewer(); addToLog (QString(" callEditorEvent imageViewPtr: %1").arg(QString::number((ulong)iv,16)),LOGDISPAT); addToLog(QString("editor: filename %1").arg(((callEditorEvent*)e)->getFilename()),LOGDISPAT); ed->openFile(((callEditorEvent*)e)->getFilename()); break; case editorFinished: if(!editorActive) break; if(((editorFinishedEvent*)e)->isOK()) { addToLog (QString(" editorFinishedEvent imageViewPtr: %1").arg(QString::number((ulong)iv,16)),LOGDISPAT); iv->reload(); } editorActive=false; delete ed; break; case templatesChanged: txWidgetPtr->setupTemplatesComboBox(); break; case progressTX: txTimeCounter=0; prTimerIndex=startTimer(((progressTXEvent*)e)->getInfo()*10); // time in seconds -> times 1000 for msec,divide by 100 for progress break; case stoppingTX: addToLog("dispatcher: endTXImage",LOGDISPAT); while(!soundIOPtr->stoppedPlaying()) { qApp->processEvents(); } rigController->activatePTT(false); break; case endImageTX: addToLog("dispatcher: endTXImage",LOGDISPAT); while(!soundIOPtr->stoppedPlaying()) { qApp->processEvents(); } rigController->activatePTT(false); restartRX(); break; case displayDRMInfo: // rxWidgetPtr->psdWdg()->setPSD(); rxWidgetPtr->mscWdg()->setConstellation(MSC); rxWidgetPtr->facWdg()->setConstellation(FAC); rxWidgetPtr->statusWdg()->setStatus(); break; case displayDRMStat: DSPFLOAT s1;DSPFLOAT v1; ((displayDRMStatEvent*)e)->getInfo(s1,v1); rxWidgetPtr->sMeterPtr()->setValue(s1); rxWidgetPtr->vMeterPtr()->setValue(v1); break; case loadRXImage: { ((loadRXImageEvent*)e)->getFilename(fn); rxWidgetPtr->getImageViewerPtr()->openImage(fn,true,false); } break; case saveDRMImage: { ((saveDRMImageEvent*)e)->getFilename(fn); rxWidgetPtr->getImageViewerPtr()->openImage(fn,true,false); saveImage(fn); } break; case prepareFix: addToLog("prepareFix",LOGDISPAT); startDRMFIXTx( ((prepareFixEvent*)e)->getData()); break; case displayText: infoTextPtr->clear(); infoTextPtr->setWindowTitle(QString("Received from %1").arg(drmCallsign)); infoTextPtr->append(((displayTextEvent*)e)->getStr()); infoTextPtr->show(); break; case displayMBox: mbox->setWindowTitle(((displayMBoxEvent*)e)->getTitle()); mbox->setText(((displayMBoxEvent*)e)->getStr()); mbox->show(); QTimer::singleShot(4000, mbox, SLOT(hide())); break; case displayProgressFTP: { if(((displayProgressFTPEvent*)e)->getTotal()==0) { delete progressFTP; progressFTP=NULL; break; } if(progressFTP==NULL) { progressFTP=new QProgressDialog("FTP Transfer","Cancel",0,0,mainWindowPtr); } progressFTP->show(); progressFTP->setMaximum(((displayProgressFTPEvent*)e)->getTotal()); progressFTP->setValue(((displayProgressFTPEvent*)e)->getBytes()); } break; default: addToLog(QString("unsupported event: %1").arg(((baseEvent*)e)->description), LOGALL); break; } ((baseEvent *)e)->setDone(); } void dispatcher::receiveImage() { } void dispatcher::restartRX() { txTimeCounter=9999999; //force stop timer startRX(true); } void dispatcher::startSSTVTx() { stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSSTVIMAGE); addToLog("send SSTV Image",LOGDISPAT); } void dispatcher::sendTone(double duration,double freq) { stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; txWidgetPtr->functionsPtr()->setToneParam(duration,freq); rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDTONE); addToLog("sendTone",LOGDISPAT); } void dispatcher::sendWF(QString txt) { stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; waterfallPtr->setText(txt); rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDID); addToLog("sendID",LOGDISPAT); } void dispatcher::startDRMTx() { stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; // waterfallPtr->setText(pictureWF); rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDDRM); addToLog("sendDRM",LOGDISPAT); } void dispatcher::startDRMBSRTx(QByteArray *ba) { if(ba==NULL) return; stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; rigController->activatePTT(true); txWidgetPtr->functionsPtr()->initDRMBSR(ba); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDDRMBSR); addToLog("sendDRMBSR",LOGDISPAT); } void dispatcher::startDRMFIXTx(QByteArray ba) { if(!txWidgetPtr->prepareFIX(ba)) return; stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDDRMFIX); addToLog("sendDRMFIX",LOGDISPAT); } void dispatcher::startDRMHybridTx(QString fn) { eftpError ftpResult; QByteArray ba; QTemporaryFile ftmp; ftpInterface ftpIntf("HybridTX"); hybridCrypt hc; ftpIntf.setupConnection(hc.host(),hc.port(),hc.user(),hc.passwd(),hc.dir()+"/"+hybridFtpHybridFilesDirectory); // txWidgetPtr->getImageViewerPtr()->getFilename(); txWidgetPtr->getImageViewerPtr()->copyToBuffer(&ba); if(!ftmp.open()) return; ftmp.write(ba); ftmp.close(); ftpResult=ftpIntf.uploadFile(ftmp.fileName(),fn,true); switch(ftpResult) { case FTPCANCELED: QMessageBox::information(mainWindowPtr, tr("FTP Info"),"Connection Canceled"); return; break; case FTPOK: break; case FTPERROR: QMessageBox::critical(mainWindowPtr, tr("FTP Error"),ftpIntf.getLastError()); return; break; case FTPNAMEERROR: QMessageBox::critical(mainWindowPtr, tr("FTP Error"),"Error in filename"); return; break; case FTPTIMEOUT: QMessageBox::critical(mainWindowPtr, tr("FTP Error"),"FTP timed out"); return; break; } stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDDRM); addToLog("sendDRMHybrid",LOGDISPAT); } void dispatcher::startDRMHybridText(QString txt) { if(!txWidgetPtr->prepareText(txt)) return; stopRX(); txWidgetPtr->start(true,false); if(txWidgetPtr->functionsPtr()->getTXState()!=txFunctions::TXIDLE) return; rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDDRMTXT); addToLog("sendDRMTxt",LOGDISPAT); } void dispatcher::sendSweepTone(double duration,double lowerFreq,double upperFreq) { stopRX(); txWidgetPtr->start(true,false); txWidgetPtr->functionsPtr()->setToneParam(duration,lowerFreq,upperFreq); rigController->activatePTT(true); txWidgetPtr->functionsPtr()->setTXState(txFunctions::TXSENDTONE); addToLog("sendSweepTone",LOGDISPAT); } void dispatcher::saveRxSSTVImage() { if (rxWidgetPtr->functionsPtr()->getModeString().isEmpty()) return; if(!rxWidgetPtr->functionsPtr()->saveOK()) return; QString s,fileName; QDateTime dt(QDateTime::currentDateTime().toUTC()); //this is compatible with QT 4.6 dt.setTimeSpec(Qt::UTC); fileName=QString("%1/%2_%3.%4").arg(rxImagesPath).arg(rxWidgetPtr->functionsPtr()->getModeString()).arg(dt.toString("yyyyMMdd_HHmmss")).arg(defaultImageFormat); addToLog(QString("dispatcher: saveRxImage():%1 ").arg(fileName),LOGDISPAT); rxWidgetPtr->getImageViewerPtr()->save(fileName,defaultImageFormat,true); saveImage(fileName); } void dispatcher::saveImage(QString fileName) { QImage im; QFileInfo info(fileName); eftpError ftpResult; displayMBoxEvent *stmb=0; QString fn="/tmp/"+info.baseName()+"."+ftpDefaultImageFormat; galleryWidgetPtr->putRxImage(fileName); txWidgetPtr->setPreviewWidget(fileName); if(enableFTP) { ftpInterface ftpIntf("Save RX Image"); rxWidgetPtr->getImageViewerPtr()->save(fn,ftpDefaultImageFormat,true); ftpIntf.setupConnection(ftpRemoteHost,ftpPort,ftpLogin,ftpPassword,ftpRemoteDirectory); ftpResult=ftpIntf.uploadToRXServer(fn); switch(ftpResult) { case FTPOK: break; case FTPERROR: stmb= new displayMBoxEvent("FTP Error",QString("Host: %1: %2").arg(ftpRemoteHost).arg(ftpIntf.getLastError())); break; case FTPNAMEERROR: stmb= new displayMBoxEvent("FTP Error",QString("Host: %1, Error in filename").arg(ftpRemoteHost)); break; case FTPCANCELED: stmb= new displayMBoxEvent("FTP Error",QString("Connection to %1 Canceled").arg(ftpRemoteHost)); break; case FTPTIMEOUT: stmb= new displayMBoxEvent("FTP Error",QString("Connection to %1 timed out").arg(ftpRemoteHost)); break; } if(ftpResult!=FTPOK) { QApplication::postEvent( dispatcherPtr, stmb ); // Qt will delete it when done return; } } } void dispatcher::timerEvent(QTimerEvent *event) { if(event->timerId()==prTimerIndex) { txWidgetPtr->setProgress(++txTimeCounter); if(txTimeCounter>=100) { if(prTimerIndex>=0) { killTimer(prTimerIndex); prTimerIndex=-1; txWidgetPtr->setProgress(0); } } txWidgetPtr->setProgress(txTimeCounter); } else if(event->timerId()==logTimerIndex) { // addToLog(QString("dumping dispatcher status"),LOGALL); // if( rxFuncPtr) rxFuncPtr->logStatus(); // if( txFuncPtr)txFuncPtr->logStatus(); // if( sndIO)sndIO->logStatus(); } } qsstv_8.2.12/qsstv/dispatcher.h000664 001750 001750 00000005422 12440624436 016455 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef DISPATCHER_H #define DISPATCHER_H #include "dispatchevents.h" #include "qsstvglobal.h" #include #include "widgets/textdisplay.h" class editor; class imageViewer; #include /** @author Johan Maes */ class dispatcher : public QObject { Q_OBJECT public: dispatcher(); ~dispatcher(); QString init(); void readSettings(); void writeSettings(); void customEvent( QEvent * e ); void receiveImage(); void restartRX(); void startSSTVTx(); void sendTone(double duration,double freq); void sendWF(QString txt); void startDRMTx(); void startDRMBSRTx(QByteArray *ba); void startDRMFIXTx(QByteArray ba); void startDRMHybridTx(QString fn); void startDRMHybridText(QString txt); void sendSweepTone(double duration,double lowerFreq,double upperFreq); void startRX(bool st); void startTX(bool st); void stopRX(); void stopTX(); void stopRXTX(); void saveImage(QString fileName); private: int serialP; void saveRxSSTVImage(); void timerEvent(QTimerEvent *event); bool editorActive; editor *ed; imageViewer *iv; int txTimeCounter; int prTimerIndex; int logTimerIndex; bool restartRXFlag; textDisplay *infoTextPtr; QMessageBox *mbox; QProgressDialog *progressFTP; }; #endif qsstv_8.2.12/qsstv/dispatchevents.h000664 001750 001750 00000030543 12440612574 017355 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef DISPATCHEVENT_H #define DISPATCHEVENT_H #include #include "widgets/imageviewer.h" #include "qsstvdefs.h" #include /** dispatch events are used to communicate with the different threads */ enum dispatchEventType { info = QEvent::User, //!< send when dsp stops running soundcardIdle, //!< send when soundcard stops running displayFFT, displaySync, displayDRMStat, displayDRMInfo, syncDisp, //!< synchro display event lineDisplay, //!< display 1 line eraseDisp, createMode, startImageRX, endImageRX, endImageTX, stoppingTX, progressTX, // verticalRetrace, // syncLost, outOfSync, statusMsg, //!< display status message rxSSTVStatus, //! shows message in sstv tab rxDRMStatus, //! shows message in drm tab closeWindows, callEditor, templatesChanged, editorFinished, changeRXFilter, startAutoRepeater, startRepeater, stopRxTx, loadRXImage, saveDRMImage, prepareFix, displayText, displayMBox, displayProgressFTP }; class baseEvent: public QEvent { public: baseEvent(QEvent::Type t):QEvent(t) {doneIt=NULL;} void waitFor(bool *d) {doneIt=d;} void setDone() { if(doneIt!=NULL) *doneIt=true; } QString description; private: bool *doneIt; }; /** this event is send when the dspfunc thread stops running */ class infoEvent : public baseEvent { public: /** create event */ infoEvent(QString t):baseEvent( (QEvent::Type) info ), str(t) { description="infoEvent"; } /** returns info string from the event */ QString getStr() const { return str; } private: QString str; }; /** this event is send when the soundcard thread goes to idle */ class soundcardIdleEvent : public baseEvent { public: /** create event */ soundcardIdleEvent():baseEvent( (QEvent::Type) soundcardIdle ) { { description=" soudcardIdleEvent"; } } }; //class rxDataAvailableEvent : public baseEvent //{ //public: // /** create event */ // rxDataAvailableEvent(uint idx,uint numSamples):baseEvent( (QEvent::Type)rxData ), index(idx),len(numSamples) {} // /** returns length and pointer from the event */ // uint getIndex(uint &idx) const { idx=index; return len;} //private: // uint index; // uint len; //}; /** this event is send with teh sync quality info and the signal volume */ class displaySyncEvent : public baseEvent { public: /** create event */ displaySyncEvent(uint s,double v):baseEvent( (QEvent::Type) displaySync), sync(s), vol(v) { description=" displaySyncEvent"; } /** returns length and pointer from the event */ void getInfo(uint &s,double &v) {s=sync; v=vol;} private: uint sync; DSPFLOAT vol; }; class displayDRMStatEvent : public baseEvent { public: /** create event */ displayDRMStatEvent(uint s,DSPFLOAT v):baseEvent( (QEvent::Type) displayDRMStat), snr(s), vol(v) { description=" displayDRMStatEvent"; } /** returns length and pointer from the event */ void getInfo(DSPFLOAT &s,DSPFLOAT &v) {s=snr; v=vol;} private: DSPFLOAT snr; DSPFLOAT vol; }; class statusMsgEvent : public baseEvent { public: /** create event */ statusMsgEvent(QString t):baseEvent( (QEvent::Type)statusMsg ), str(t) { description="statusMsgEvent"; } /** returns info string from the event */ QString getStr() const { return str; } private: QString str; }; class rxSSTVStatusEvent : public baseEvent { public: /** create event */ rxSSTVStatusEvent(QString t):baseEvent( (QEvent::Type)rxSSTVStatus ), str(t) { description="rxSSTVStatusEvent"; } /** returns info string from the event */ QString getStr() const { return str; } private: QString str; }; class rxDRMStatusEvent : public baseEvent { public: /** create event */ rxDRMStatusEvent(QString t):baseEvent( (QEvent::Type)rxDRMStatus ), str(t) { description="rxDRMStatusEvent"; } /** returns info string from the event */ QString getStr() const { return str; } private: QString str; }; class lineDisplayEvent : public baseEvent { public: /** create event */ lineDisplayEvent(uint lineNbr):baseEvent( (QEvent::Type)lineDisplay ), lineNumber(lineNbr) { description="lineDisplayEvent"; } /** returns length and pointer from the event */ void getInfo(uint &lineNbr) const { lineNbr=lineNumber;} private: uint lineNumber; }; class eraseDisplayEvent : public baseEvent { public: /** create event */ eraseDisplayEvent():baseEvent( (QEvent::Type)eraseDisp ) { description="eraseDisplayEvent"; } }; class displayDRMInfoEvent : public baseEvent { public: /** create event */ displayDRMInfoEvent():baseEvent( (QEvent::Type)displayDRMInfo) { description="displayDRMInfo"; } }; class startAutoRepeaterEvent: public baseEvent { public: /** create event */ startAutoRepeaterEvent():baseEvent( (QEvent::Type)startAutoRepeater ) { description="startAutoRepeaterEvent"; } }; class startRepeaterEvent: public baseEvent { public: /** create event */ startRepeaterEvent():baseEvent( (QEvent::Type)startRepeater ) { description="startRepeaterEvent"; } }; class createModeEvent : public baseEvent { public: /** create event */ createModeEvent(uint m,QString t):baseEvent( (QEvent::Type)createMode ), mode(m) ,str(t) { description="createModeEvent"; } /** returns info string from the event */ void getMode(uint &m,QString &s) const { m=mode;s=str; } private: uint mode; QString str; }; class loadRXImageEvent : public baseEvent { public: loadRXImageEvent(QString fn):baseEvent( (QEvent::Type)loadRXImage),fileName(fn) { description="loadRXImageEvent"; } void getFilename(QString &fn) {fn=fileName;} private: QString fileName; }; class saveDRMImageEvent : public baseEvent { public: saveDRMImageEvent(QString fn):baseEvent( (QEvent::Type)saveDRMImage),fileName(fn) { description="saveDRMImageEvent"; } void getFilename(QString &fn) {fn=fileName;} private: QString fileName; }; class startImageRXEvent : public baseEvent { public: /** create event */ startImageRXEvent(QSize ims):baseEvent( (QEvent::Type)startImageRX ),imSize(ims) { description="startImageRXEvent"; } QSize getSize() {return imSize;} private: QSize imSize; }; class endImageRXEvent : public baseEvent { public: /** create event */ endImageRXEvent():baseEvent( (QEvent::Type)endImageRX ) { description="endImageRXEvent"; } }; class endImageTXEvent : public baseEvent { public: /** create event */ endImageTXEvent():baseEvent( (QEvent::Type)endImageTX ) { description="endImageTXEvent"; } }; class stopTXEvent : public baseEvent { public: /** create event */ stopTXEvent():baseEvent( (QEvent::Type)stoppingTX ) { description="stopTXEvent"; } }; //class verticalRetraceEvent : public baseEvent //{ //public: // /** create event */ // verticalRetraceEvent():baseEvent( (QEvent::Type) verticalRetrace ) // { // description="verticalRetraceEvent"; // } //}; //class syncLostEvent : public baseEvent //{ //public: // /** create event */ // syncLostEvent():baseEvent( (QEvent::Type) syncLost ) // { // description="syncLostEvent"; // } //}; class outOfSyncEvent : public baseEvent { public: /** create event */ outOfSyncEvent():baseEvent( (QEvent::Type)outOfSync ) { description="outOfSyncEvent"; } }; class progressTXEvent : public baseEvent { public: /** create event */ progressTXEvent(double tim):baseEvent( (QEvent::Type)progressTX ), txTime(tim) { description="progressTXEvent"; } /** returns length and pointer from the event */ double getInfo() { return txTime;} private: double txTime; }; class closeWindowsEvent : public baseEvent { public: /** create event */ closeWindowsEvent():baseEvent( (QEvent::Type)closeWindows) { description="closeWindowEvent"; } /** returns length and pointer from the event */ }; class callEditorEvent : public baseEvent { public: /** create event */ callEditorEvent(imageViewer *iv,QString fn):baseEvent( (QEvent::Type) callEditor ), filename(fn),imviewer(iv) { description="callEditorEvent"; } /** returns info string from the event */ QString getFilename() const { return filename; } imageViewer *getImageViewer() { return imviewer; } private: QString filename; imageViewer *imviewer; }; class templatesChangedEvent : public baseEvent { public: /** create event */ templatesChangedEvent():baseEvent( (QEvent::Type) templatesChanged ) { description="templateChangeEvent"; } }; class editorFinishedEvent : public baseEvent { public: /** create event */ editorFinishedEvent(bool b,QString fn):baseEvent( (QEvent::Type)editorFinished),ok(b),filename(fn) { description="editorFinishedEvent"; } bool isOK() { return ok;} QString getFilename() const { return filename; } private: bool ok; QString filename; }; class displayFFTEvent : public baseEvent { public: /** create event */ displayFFTEvent(DSPFLOAT *buf):baseEvent( (QEvent::Type)displayFFT),buffer(buf) { description="displayFFTEvent"; } DSPFLOAT *data() { return buffer;} private: DSPFLOAT *buffer; }; class filterRXChangedEvent: public baseEvent { public: /** create event */ filterRXChangedEvent(int fIndex):baseEvent( (QEvent::Type)changeRXFilter),filterIndex(fIndex) { description="filterChangedEvent"; } int index() { return filterIndex;} private: int filterIndex; }; class stopRxTxEvent : public baseEvent { public: /** create event */ stopRxTxEvent():baseEvent( (QEvent::Type)stopRxTx) { description="stopRxTxEvent"; } }; class prepareFixEvent: public baseEvent { public: prepareFixEvent(QByteArray ba):baseEvent( (QEvent::Type)prepareFix),data(ba) { description="filterChangedEvent"; } QByteArray &getData() {return data;} private: QByteArray data; }; /** this event is send when the dspfunc thread stops running */ class displayTextEvent : public baseEvent { public: /** create event */ displayTextEvent(QString t):baseEvent( (QEvent::Type) displayText ), str(t) { description="displayTextEvent"; } /** returns info string from the event */ QString getStr() const { return str; } private: QString str; }; class displayMBoxEvent : public baseEvent { public: /** create event */ displayMBoxEvent(QString title,QString text):baseEvent( (QEvent::Type) displayMBox ), str(text), title(title) { description="displayMBoxEvent"; } /** returns info string from the event */ QString getStr() const { return str; } QString getTitle() const { return title; } private: QString str; QString title; }; class displayProgressFTPEvent : public baseEvent { public: /** create event */ displayProgressFTPEvent(quint64 byts,quint64 tot):baseEvent( (QEvent::Type) displayProgressFTP ), bytes(byts),total(tot) { description="displayMBoxEvent"; } /** returns info string from the event */ quint64 getTotal() const { return total; } quint64 getBytes() const { return bytes; } private: quint64 bytes; quint64 total; }; #endif qsstv_8.2.12/qsstv/drmprofileform.cpp000664 001750 001750 00000015664 12440612574 017722 0ustar00jomajoma000000 000000 #include "drmprofileform.h" #include "ui_drmprofileform.h" #include "utils/supportfunctions.h" #include "configparams.h" drmProfileForm::drmProfileForm(QWidget *parent) : QWidget(parent), ui(new Ui::drmProfileForm) { ui->setupUi(this); readSettings(); } drmProfileForm::~drmProfileForm() { writeSettings(); delete ui; } void drmProfileForm::readSettings() { QSettings qSettings; qSettings.beginGroup ("DRM Profile" ); drmPFArray[0].name=qSettings.value ("drmPF1Name","Profile 1").toString(); drmPFArray[0].params.robMode=qSettings.value ("drmPF1Mode",0).toInt(); drmPFArray[0].params.qam=qSettings.value("drmPF1QAM",0).toInt(); drmPFArray[0].params.bandwith=qSettings.value("drmPF1Bandwidth",0).toInt(); drmPFArray[0].params.protection=qSettings.value("drmPF1Protection",0).toInt(); drmPFArray[0].params.interleaver=qSettings.value("drmPF1Interleave",0).toInt(); drmPFArray[0].params.reedSolomon=qSettings.value("drmPF1ReedSolomon",0).toInt(); drmPFArray[1].name=qSettings.value ("drmPF2Name","Profile 2").toString(); drmPFArray[1].params.robMode=qSettings.value ("drmPF2Mode",0).toInt(); drmPFArray[1].params.qam=qSettings.value("drmPF2QAM",0).toInt(); drmPFArray[1].params.bandwith=qSettings.value("drmPF2Bandwidth",0).toInt(); drmPFArray[1].params.protection=qSettings.value("drmPF2Protection",0).toInt(); drmPFArray[1].params.interleaver=qSettings.value("drmPF2Interleave",0).toInt(); drmPFArray[1].params.reedSolomon=qSettings.value("drmPF2ReedSolomon",0).toInt(); drmPFArray[2].name=qSettings.value ("drmPF3Name","Profile 3").toString(); drmPFArray[2].params.robMode=qSettings.value ("drmPF3Mode",0).toInt(); drmPFArray[2].params.qam=qSettings.value("drmPF3QAM",0).toInt(); drmPFArray[2].params.bandwith=qSettings.value("drmPF3Bandwidth",0).toInt(); drmPFArray[2].params.protection=qSettings.value("drmPF3Protection",0).toInt(); drmPFArray[2].params.interleaver=qSettings.value("drmPF3Interleave",0).toInt(); drmPFArray[2].params.reedSolomon=qSettings.value("drmPF3ReedSolomon",0).toInt(); qSettings.endGroup(); setParams(); } void drmProfileForm::writeSettings() { QSettings qSettings; getParams(); qSettings.beginGroup ("DRM Profile" ); qSettings.setValue ("drmPF1Name",drmPFArray[0].name); qSettings.setValue ("drmPF1Mode",drmPFArray[0].params.robMode); qSettings.setValue("drmPF1QAM",drmPFArray[0].params.qam); qSettings.setValue("drmPF1Bandwidth",drmPFArray[0].params.bandwith); qSettings.setValue("drmPF1Protection",drmPFArray[0].params.protection); qSettings.setValue("drmPF1Interleave",drmPFArray[0].params.interleaver); qSettings.setValue("drmPF1ReedSolomon",drmPFArray[0].params.reedSolomon); qSettings.setValue ("drmPF2Name",drmPFArray[1].name); qSettings.setValue ("drmPF2Mode",drmPFArray[1].params.robMode); qSettings.setValue("drmPF2QAM",drmPFArray[1].params.qam); qSettings.setValue("drmPF2Bandwidth",drmPFArray[1].params.bandwith); qSettings.setValue("drmPF2Protection",drmPFArray[1].params.protection); qSettings.setValue("drmPF2Interleave",drmPFArray[1].params.interleaver); qSettings.setValue("drmPF2ReedSolomon",drmPFArray[1].params.reedSolomon); qSettings.setValue ("drmPF3Name",drmPFArray[2].name); qSettings.setValue ("drmPF3Mode",drmPFArray[2].params.robMode); qSettings.setValue("drmPF3QAM",drmPFArray[2].params.qam); qSettings.setValue("drmPF3Bandwidth",drmPFArray[2].params.bandwith); qSettings.setValue("drmPF3Protection",drmPFArray[2].params.protection); qSettings.setValue("drmPF3Interleave",drmPFArray[2].params.interleaver); qSettings.setValue("drmPF3ReedSolomon",drmPFArray[2].params.reedSolomon); qSettings.endGroup(); } void drmProfileForm::getParams() { getValue(drmPFArray[0].name,ui->namePF1LineEdit); drmPFArray[0].params.callsign=myCallsign; getIndex(drmPFArray[0].params.robMode,ui->drmPF1ModeComboBox); getIndex(drmPFArray[0].params.qam,ui->drmPF1QAMComboBox); getIndex(drmPFArray[0].params.bandwith,ui->drmPF1BandwidthComboBox); getIndex(drmPFArray[0].params.protection,ui->drmPF1ProtectionComboBox); getIndex(drmPFArray[0].params.interleaver,ui->drmPF1InterleaveComboBox); getIndex(drmPFArray[0].params.reedSolomon,ui->drmPF1ReedSolomonComboBox); getValue(drmPFArray[1].name,ui->namePF2LineEdit); drmPFArray[1].params.callsign=myCallsign; getIndex(drmPFArray[1].params.robMode,ui->drmPF2ModeComboBox); getIndex(drmPFArray[1].params.qam,ui->drmPF2QAMComboBox); getIndex(drmPFArray[1].params.bandwith,ui->drmPF2BandwidthComboBox); getIndex(drmPFArray[1].params.protection,ui->drmPF2ProtectionComboBox); getIndex(drmPFArray[1].params.interleaver,ui->drmPF2InterleaveComboBox); getIndex(drmPFArray[1].params.reedSolomon,ui->drmPF2ReedSolomonComboBox); getValue(drmPFArray[2].name,ui->namePF3LineEdit); drmPFArray[2].params.callsign=myCallsign; getIndex(drmPFArray[2].params.robMode,ui->drmPF3ModeComboBox); getIndex(drmPFArray[2].params.qam,ui->drmPF3QAMComboBox); getIndex(drmPFArray[2].params.bandwith,ui->drmPF3BandwidthComboBox); getIndex(drmPFArray[2].params.protection,ui->drmPF3ProtectionComboBox); getIndex(drmPFArray[2].params.interleaver,ui->drmPF3InterleaveComboBox); getIndex(drmPFArray[2].params.reedSolomon,ui->drmPF3ReedSolomonComboBox); } void drmProfileForm::setParams() { setValue(drmPFArray[0].name,ui->namePF1LineEdit); setIndex(drmPFArray[0].params.robMode,ui->drmPF1ModeComboBox); setIndex(drmPFArray[0].params.qam,ui->drmPF1QAMComboBox); setIndex(drmPFArray[0].params.bandwith,ui->drmPF1BandwidthComboBox); setIndex(drmPFArray[0].params.protection,ui->drmPF1ProtectionComboBox); setIndex(drmPFArray[0].params.interleaver,ui->drmPF1InterleaveComboBox); setIndex(drmPFArray[0].params.reedSolomon,ui->drmPF1ReedSolomonComboBox); setValue(drmPFArray[1].name,ui->namePF2LineEdit); setIndex(drmPFArray[1].params.robMode,ui->drmPF2ModeComboBox); setIndex(drmPFArray[1].params.qam,ui->drmPF2QAMComboBox); setIndex(drmPFArray[1].params.bandwith,ui->drmPF2BandwidthComboBox); setIndex(drmPFArray[1].params.protection,ui->drmPF2ProtectionComboBox); setIndex(drmPFArray[1].params.interleaver,ui->drmPF2InterleaveComboBox); setIndex(drmPFArray[1].params.reedSolomon,ui->drmPF2ReedSolomonComboBox); setValue(drmPFArray[2].name,ui->namePF3LineEdit); setIndex(drmPFArray[2].params.robMode,ui->drmPF3ModeComboBox); setIndex(drmPFArray[2].params.qam,ui->drmPF3QAMComboBox); setIndex(drmPFArray[2].params.bandwith,ui->drmPF3BandwidthComboBox); setIndex(drmPFArray[2].params.protection,ui->drmPF3ProtectionComboBox); setIndex(drmPFArray[2].params.interleaver,ui->drmPF3InterleaveComboBox); setIndex(drmPFArray[2].params.reedSolomon,ui->drmPF3ReedSolomonComboBox); } bool drmProfileForm::getDRMParams(int idx,drmTxParams &d) { if((idx<0)||(idx>=NUMBEROFPROFILES)) { return false; } d=drmPFArray[idx].params; return true; } bool drmProfileForm::getName(int idx, QString &n) { if((idx<0)||(idx>=NUMBEROFPROFILES)) { return false; } n=drmPFArray[idx].name; return true; } qsstv_8.2.12/qsstv/drmprofileform.h000664 001750 001750 00000001233 12440612574 017352 0ustar00jomajoma000000 000000 #ifndef DRMPROFILEFORM_H #define DRMPROFILEFORM_H #include "drmtx/drmtransmitter.h" #include #define NUMBEROFPROFILES 3 struct sprofile { QString name; drmTxParams params; }; namespace Ui { class drmProfileForm; } class drmProfileForm : public QWidget { Q_OBJECT public: explicit drmProfileForm(QWidget *parent = 0); ~drmProfileForm(); void readSettings(); void writeSettings(); bool getDRMParams(int idx, drmTxParams &d); bool getName(int idx,QString &n); void setParams(); private: Ui::drmProfileForm *ui; sprofile drmPFArray[NUMBEROFPROFILES]; void getParams(); }; #endif // DRMPROFILEFORM_H qsstv_8.2.12/qsstv/drmprofileform.ui000664 001750 001750 00000055420 12440612574 017547 0ustar00jomajoma000000 000000 drmProfileForm 0 0 434 330 Form 0 Profile 1 Profile Name 30 0 Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false A B E 30 0 BW Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 2.2 KHz 2.5 KHz 30 0 QAM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 4 16 64 30 0 Interleave Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Short Long 30 0 Prot. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false High Low 30 0 Rs Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false None RS1 RS2 RS3 RS4 Profile 2 Profile Name 30 0 Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false A B E 30 0 BW Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 2.2 KHz 2.5 KHz 30 0 QAM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 4 16 64 30 0 Interleave Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Short Long 30 0 Prot. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false High Low 30 0 Rs Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false None RS1 RS2 RS3 RS4 Profile 3 Profile Name 30 0 Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false A B E 30 0 BW Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 2.2 KHz 2.5 KHz 30 0 QAM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 4 16 64 30 0 Interleave Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Short Long 30 0 Prot. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false High Low 30 0 Rs Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false None RS1 RS2 RS3 RS4 Qt::Vertical 20 121 qsstv_8.2.12/qsstv/gallerywidget.cpp000664 001750 001750 00000020023 12440612574 017517 0ustar00jomajoma000000 000000 #include "gallerywidget.h" #include "ui_gallerywidget.h" #include "utils/logging.h" #include "qsstvglobal.h" #include #include "dispatcher.h" #include #include #include "txwidget.h" galleryWidget *galleryWidgetPtr; galleryWidget::galleryWidget(QWidget *parent) : QWidget(parent), ui(new Ui::galleryWidget) { ui->setupUi(this); ui->tabWidget->setCurrentIndex(0); } galleryWidget::~galleryWidget() { writeSettings(false); addToLog ("deleting galleryWidget",LOGGALLERY); delete ui; addToLog ("ui deleted: galleryWidget",LOGGALLERY); } void galleryWidget::init() { initView(); readSettings(); } /*! reads the settings (saved images for tx,rx,templates) */ void galleryWidget::readSettings() { int i; QSettings qSettings; qSettings.beginGroup ("Gallery"); rxIndex=qSettings.value( "rxIndex",0 ).toInt(); qSettings.endGroup(); splashStr+=QString( "Loading RX images" ).rightJustified(25,' ')+"\n"; splashPtr->showMessage ( splashStr ,Qt::AlignLeft,Qt::white); qApp->processEvents(); for ( i=0;ireadThumbSettings ( &qSettings ); } splashStr+=QString( "Loading TX images" ).rightJustified(25,' ')+"\n"; splashPtr->showMessage ( splashStr ,Qt::AlignLeft,Qt::white); qApp->processEvents(); for ( i=0;ireadThumbSettings ( &qSettings ); } splashStr+=QString( "Loading Templates" ).rightJustified(25,' ')+"\n"; splashPtr->showMessage ( splashStr ,Qt::AlignLeft,Qt::white); qApp->processEvents(); for ( i=0;iprocessEvents(); templateThumbsArray[i]->readThumbSettings ( &qSettings ); } slotLayoutChanged(); } /*! writes the settings (saved images for tx,rx,templates) */ void galleryWidget::writeSettings(bool onlyRx) { int i; QSettings qSettings; qSettings.beginGroup ( "Gallery" ); qSettings.setValue ( "rxIndex",rxIndex ); qSettings.endGroup(); for ( i=0;iwriteThumbSettings ( &qSettings ); if(!onlyRx) { txThumbsArray[i]->writeThumbSettings ( &qSettings ); templateThumbsArray[i]->writeThumbSettings ( &qSettings ); } } } /*! setup of the user interface */ void galleryWidget::initView() { #define MINCOLSIZE 32 #define MINROWSIZE 26 #define MAXCOLSIZE 64 #define MAXROWSIZE 52 int i; rxThumbsArray[0]= ui->rximage1; rxThumbsArray[1]= ui->rximage2; rxThumbsArray[2]= ui->rximage3; rxThumbsArray[3]= ui->rximage4; rxThumbsArray[4]= ui->rximage5; rxThumbsArray[5]= ui->rximage6; rxThumbsArray[6]= ui->rximage7; rxThumbsArray[7]= ui->rximage8; rxThumbsArray[8]= ui->rximage9; rxThumbsArray[9]= ui->rximage10; rxThumbsArray[10]=ui->rximage11; rxThumbsArray[11]=ui->rximage12; txThumbsArray[0]= ui->tximage1; txThumbsArray[1]= ui->tximage2; txThumbsArray[2]= ui->tximage3; txThumbsArray[3]= ui->tximage4; txThumbsArray[4]= ui->tximage5; txThumbsArray[5]= ui->tximage6; txThumbsArray[6]= ui->tximage7; txThumbsArray[7]= ui->tximage8; txThumbsArray[8]= ui->tximage9; txThumbsArray[9]= ui->tximage10; txThumbsArray[10]=ui->tximage11; txThumbsArray[11]=ui->tximage12; templateThumbsArray[0]= ui->tmpimage1; templateThumbsArray[1]= ui->tmpimage2; templateThumbsArray[2]= ui->tmpimage3; templateThumbsArray[3]= ui->tmpimage4; templateThumbsArray[4]= ui->tmpimage5; templateThumbsArray[5]= ui->tmpimage6; templateThumbsArray[6]= ui->tmpimage7; templateThumbsArray[7]= ui->tmpimage8; templateThumbsArray[8]= ui->tmpimage9; templateThumbsArray[9]= ui->tmpimage10; templateThumbsArray[10]=ui->tmpimage11; templateThumbsArray[11]=ui->tmpimage12; for ( i=0;isetType ( imageViewer::RXTHUMB ); txThumbsArray[i]->setType ( imageViewer::TXTHUMB ); templateThumbsArray[i]->setType ( imageViewer::TEMPLATETHUMB ); connect( rxThumbsArray[i],SIGNAL(layoutChanged()),SLOT(slotLayoutChanged())); connect( txThumbsArray[i],SIGNAL(layoutChanged()),SLOT(slotLayoutChanged())); connect( templateThumbsArray[i],SIGNAL(layoutChanged()),SLOT(slotLayoutChanged())); } for (i=0;i<4;i++) { ui->gridLayout1->setColumnMinimumWidth(i,MINCOLSIZE); ui->gridLayout1->setColumnStretch(i,1); ui->gridLayout2->setColumnMinimumWidth(i,MINCOLSIZE); ui->gridLayout2->setColumnStretch(i,1); ui->gridLayout3->setColumnMinimumWidth(i,MINCOLSIZE); ui->gridLayout3->setColumnStretch(i,1); } for (i=0;i<3;i++) { ui->gridLayout1->setRowMinimumHeight(i,MINROWSIZE); ui->gridLayout1->setRowStretch(i,0); ui->gridLayout2->setRowMinimumHeight(i,MINROWSIZE); ui->gridLayout2->setRowStretch(i,0); ui->gridLayout3->setRowMinimumHeight(i,MINROWSIZE); ui->gridLayout3->setRowStretch(i,0); } } /*! closeEvent signals the dispatcher to initiate program exit. */ /*! get the filename of a template \param[in] tm index of template \return QString containing filename, check with QString.isNull for validity */ QString galleryWidget::getTemplateFileName ( int tm ) { if ( tmgetFilename(); } return QString(); } const QStringList &galleryWidget::getFilenames() { QString str; sl.clear(); int i; for(i=0;ishowMessage ( "Saved: "+fn ); shuffle(rxThumbsArray,rxIndex); // cleanup(rxThumbsArray,imageViewer::RXTHUMB); rxThumbsArray[rxIndex]->openImage(fn,false,false); addToLog (QString("adding item %1 fn: %2").arg(rxIndex).arg(fn),LOGGALLERY); if(rxIndexgetFilename(); } void galleryWidget::cleanup(imageViewer *array[],imageViewer::thumbType tp) { int i,j; bool found; for(i=0;igetFilename().isEmpty()) { addToLog (QString("empty item %1").arg(i),LOGGALLERY); array[i]->init(tp); for(j=i+1;jgetFilename().isEmpty()) { array[i]->copy(array[j]); array[j]->init(tp); found=true; break; } } if(!found) break; } else { addToLog (QString("item %1 fn: %2").arg(i).arg(array[i]->getFilename()),LOGGALLERY); } } } void galleryWidget::slotLayoutChanged() { int i; cleanup(rxThumbsArray,imageViewer::RXTHUMB); cleanup(txThumbsArray,imageViewer::TXTHUMB); cleanup(templateThumbsArray,imageViewer::TEMPLATETHUMB); rxIndex=NUMTHUMBS-1; for(i=0;igetFilename().isEmpty()) { rxIndex=i; break; } } txWidgetPtr->setupTemplatesComboBox(); } void galleryWidget::shuffle(imageViewer *ar[],int index) { int i,j; if(ar[rxIndex]->getFilename().isEmpty()) return; if(index>=NUMTHUMBS-1) { for(i=0,j=1;(i<(NUMTHUMBS-1))&&(jgetFilename().isEmpty()) { addToLog (QString("shuffling %1 fn: %2 to %3").arg(j).arg(ar[j]->getFilename()).arg(i),LOGGALLERY); ar[i]->copy(ar[j]); i++; } } ar[j-1]->clear(); } } qsstv_8.2.12/qsstv/gallerywidget.h000664 001750 001750 00000001706 12440612574 017173 0ustar00jomajoma000000 000000 #ifndef GALLERYWIDGET_H #define GALLERYWIDGET_H #include #include "widgets/imageviewer.h" #define NUMTHUMBS 12 namespace Ui { class galleryWidget; } class galleryWidget : public QWidget { Q_OBJECT public: explicit galleryWidget(QWidget *parent = 0); ~galleryWidget(); void init(); void writeSettings(bool onlyRx); void readSettings(); void putRxImage(QString fn); QString getTemplateFileName(int); const QStringList &getFilenames(); QString getLastRxImage(); public slots: void slotLayoutChanged(); private: Ui::galleryWidget *ui; void initView(); void cleanup(imageViewer *array[], imageViewer::thumbType tp); void shuffle(imageViewer *ar[], int idx); imageViewer *rxThumbsArray[NUMTHUMBS]; imageViewer *txThumbsArray[NUMTHUMBS]; imageViewer *templateThumbsArray[NUMTHUMBS]; int rxIndex; QStringList sl; }; extern galleryWidget *galleryWidgetPtr; #endif // GALLERYWIDGET_H qsstv_8.2.12/qsstv/gallerywidget.ui000664 001750 001750 00000016012 12440612574 017355 0ustar00jomajoma000000 000000 galleryWidget 0 0 562 376 Form 1 0 0 0 8 0 RX 1 1 QLayout::SetNoConstraint TX 1 1 Templates 1 1 imageViewer QWidget
widgets/imageviewer.h
1
qsstv_8.2.12/qsstv/main.cpp000664 001750 001750 00000005746 12474636301 015620 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include //#include #include "qsstvglobal.h" #include "mainwindow.h" #include "dsp/filterparam.h" #include "dsp/filter.h" #include #include #include QSplashScreen *splash; int main( int argc, char ** argv ) { int result=true; QTimer tm; tm.setSingleShot(true); QApplication::setColorSpec( QApplication::ManyColor ); QApplication app( argc, argv ); QCoreApplication::setOrganizationName(ORGANIZATION); QCoreApplication::setApplicationName(APPLICATION); QPixmap pixmap(":/icons/qsstvsplash.png"); QSplashScreen splash(pixmap,Qt::WindowStaysOnTopHint); splashPtr=&splash; QFont f; f.setBold(true); f.setPixelSize(18); splashPtr->setFont(f); splash.show(); splashStr="\n\n\n"; splashStr+=QString( "Starting %1").arg(qsstvVersion).rightJustified(25,' ')+"\n"; splash.showMessage (splashStr,Qt::AlignLeft,Qt::white); tm.start(500); globalInit(); mainWindowPtr=new mainWindow; mainWindowPtr->setWindowIcon(QPixmap(":/icons/qsstv.png")); while(1) { app.processEvents(); if(!tm.isActive()) break; } mainWindowPtr->init(); // this must follow show() because window has to be drawn first to determine fftframe window size mainWindowPtr->hide(); tm.start(3000); while(1) { app.processEvents(); if(!tm.isActive()) break; } splash.finish(mainWindowPtr); mainWindowPtr->show(); mainWindowPtr->startReceiving(); result=app.exec(); globalEnd(); return result; } qsstv_8.2.12/qsstv/mainwindow.cpp000664 001750 001750 00000024567 12474636163 017060 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "mainwindow.h" #include "qsstvglobal.h" #include "ui_mainwindow.h" #include "sound/soundio.h" #include "configdialog.h" #include "configparams.h" #ifndef QT_NO_DEBUG #include "scope/scopeview.h" #endif #include #include #include #include "dispatcher.h" #include "sound/calibration.h" #include "dsp/filterparam.h" #include "dsp/filter.h" #include "utils/supportfunctions.h" #include "utils/ftp.h" #include "rig/rigcontrol.h" #include "logbook/logbook.h" /** * @brief * * @param parent */ mainWindow::mainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { soundIOPtr=new soundIO; rigControllerR1=new rigControl(1); // rigControllerR2=new rigControl(2); rigController=rigControllerR1; confDiag=new configDialog(); #ifndef QT_NO_DEBUG scopeViewerData=new scopeView("Data Scope"); scopeViewerSync=new scopeView("Sync Scope"); scopeViewerData->setAlternativeScaleMultiplier(SUBSAMPLINGRATIO/rxClock); scopeViewerSync->setAlternativeScaleMultiplier(SUBSAMPLINGRATIO/rxClock); #endif // drmProfileComboBox->addItem("FAX"); wfTextPushButton=new QPushButton("WF Text",this); bsrPushButton=new QPushButton("BSR",this); idPushButton=new QPushButton("ID",this); greenPXM=new QPixmap(16,16); greenPXM->fill(Qt::green); redPXM=new QPixmap(16,16); redPXM->fill(Qt::red); pttText.setText(" PTT"); pttIcon=new QLabel(this); pttIcon->setFixedSize(16,16); pttIcon->setPixmap(*greenPXM); pttIcon->setFrameShape(QFrame::Panel); pttIcon->setFrameShadow(QFrame::Raised); pttIcon->setLineWidth(2); dispatcherPtr=NULL; setWindowIcon(QPixmap(":/icons/qsstv.png")); readSettings(); ui->setupUi(this); ui->maintabWidget->setCurrentIndex(0); ui->statusBar->addPermanentWidget(wfTextPushButton); ui->statusBar->addPermanentWidget(bsrPushButton); ui->statusBar->addPermanentWidget(idPushButton); ui->statusBar->addPermanentWidget(&pttText); ui->statusBar->addPermanentWidget(pttIcon); statusBarPtr=statusBar(); // must be after setup UI setWindowTitle(qsstvVersion); logBookPtr=new logBook; } /** * @brief * */ mainWindow::~mainWindow() { #ifndef QT_NO_DEBUG delete scopeViewerData; delete scopeViewerSync; #endif delete ui; } /** * @brief initialize sound device and dispatcher * */ void mainWindow::init() { QString ret; readSettings(); rxWidgetPtr=ui->rxWindow; txWidgetPtr=ui->txWindow; galleryWidgetPtr=ui->galleryWindow; if(!dispatcherPtr) dispatcherPtr=new dispatcher(); ret=dispatcherPtr->init(); if(!ret.isEmpty()) { splashStr+=ret.rightJustified(25,' ')+"\n"; splashPtr->showMessage(splashStr ,Qt::AlignLeft,Qt::white); } confDiag->readSettings(); connect(ui->actionExit,SIGNAL(triggered()),this, SLOT(slotExit())); connect(ui->actionConfigure,SIGNAL(triggered()),this, SLOT(slotConfigure())); connect(ui->actionCalibrate,SIGNAL(triggered()),this, SLOT(slotCalibrate())); connect(ui->actionAboutQSSTV, SIGNAL(triggered()),SLOT(slotAboutQSSTV())); connect(ui->actionAboutQt, SIGNAL(triggered()),SLOT(slotAboutQt())); connect(ui->actionUsersGuide, SIGNAL(triggered()),SLOT(slotDocumentation())); connect(idPushButton, SIGNAL(clicked()), this, SLOT(slotSendID())); connect(bsrPushButton, SIGNAL(clicked()), this, SLOT(slotSendBSR())); // connect(fixPushButton, SIGNAL(clicked()), this, SLOT(slotSendFIX())); connect(wfTextPushButton, SIGNAL(clicked()), this, SLOT(slotSendWfText())); #ifndef QT_NO_DEBUG // connect(ui->actionTest,SIGNAL(triggered()),this, SLOT(slotTest())); connect(ui->actionLogSettings, SIGNAL(triggered()),SLOT(slotLogSettings())); connect(ui->actionResetLog, SIGNAL(triggered()),SLOT(slotResetLog())); connect(ui->actionShowDataScope, SIGNAL(triggered()),SLOT(slotShowDataScope())); connect(ui->actionShowSyncScope, SIGNAL(triggered()),SLOT(slotShowSyncScope())); connect(ui->actionScopeOffset,SIGNAL(triggered()),this, SLOT(slotScopeOffset())); #else ui->menuOptions->removeAction(ui->actionTest); ui->menuOptions->removeAction(ui->actionLogSettings); ui->menuOptions->removeAction(ui->actionShowDataScope); ui->menuOptions->removeAction(ui->actionShowSyncScope); ui->menuOptions->removeAction(ui->actionLogSettings); ui->menuOptions->removeAction(ui->actionResetLog); ui->menuOptions->removeAction(ui->actionScopeOffset); #endif if(!soundIOPtr->init()) { splashStr+=QString("Soundcard error: %1").arg(*soundIOPtr->getLastError()).rightJustified(25,' ')+"\n";; splashPtr->showMessage(splashStr ,Qt::AlignLeft,Qt::white); } else { soundIOPtr->start(); } #ifndef QT_NO_DEBUG rxWidgetPtr->functionsPtr()->setOffset(dataScopeOffset,false); #endif } void mainWindow::startReceiving() { txWidgetPtr->setSettingsTab(); rxWidgetPtr->setSettingsTab(); rxWidgetPtr->start(true); } void mainWindow::readSettings() { QSettings qSettings; qSettings.beginGroup("MAIN"); int windowWidth = qSettings.value("windowWidth", 460 ).toInt(); int windowHeight = qSettings.value("windowHeight", 530 ).toInt(); int windowX = qSettings.value( "windowX", -1 ).toInt(); int windowY = qSettings.value( "windowY", -1 ).toInt(); resize( windowWidth, windowHeight ); if ( windowX != -1 || windowY != -1 ) move( windowX, windowY ); transmissionModeIndex=(etransmissionMode)qSettings.value("transmissionModeIndex",0).toInt(); dataScopeOffset=qSettings.value("dataScopeOffset",0).toUInt(); logfile->readSettings(qSettings); qSettings.endGroup(); } void mainWindow::writeSettings() { QSettings qSettings; qSettings.beginGroup("MAIN"); qSettings.setValue( "windowWidth", width() ); qSettings.setValue( "windowHeight", height() ); qSettings.setValue( "windowX", x() ); qSettings.setValue( "windowY", y() ); qSettings.setValue("dataScopeOffset",dataScopeOffset); qSettings.setValue("transmissionModeIndex",(int)transmissionModeIndex); logfile->writeSettings(qSettings); galleryWidgetPtr->writeSettings(false); qSettings.endGroup(); } /** *\todo fontselection */ void mainWindow::setNewFont() { // QFont fnt; // fnt.fromString(fontString); // setFont(fnt); // galMW->setFont(fnt); // rxMW->setFont(fnt); // txMW->setFont(fnt); } void mainWindow::slotExit() { int exit; exit=QMessageBox::information(this, tr("Quit..."), tr("Do your really want to quit QSSTV?"), QMessageBox::Ok, QMessageBox::Cancel); if(exit==QMessageBox::Ok) { dispatcherPtr->stopRXTX(); deleteFiles(rxImagesPath,"*.rs*"); deleteFiles(txImagesPath,"*.rs*"); soundIOPtr->stopAndWait(); QApplication::quit(); } writeSettings(); } void mainWindow::closeEvent ( QCloseEvent *e ) { slotExit(); e->ignore(); } void mainWindow::slotConfigure() { if(confDiag->exec()==QDialog::Accepted) { if(!soundIOPtr->init()) { QMessageBox::critical(this, tr("Soundcard error"),*soundIOPtr->getLastError()); } else { soundIOPtr->start(); } dispatcherPtr->init(); rxWidgetPtr->start(true); } } void mainWindow::slotLogSettings() { logfile->maskSelect(this); } void mainWindow::slotResetLog() { logfile->reset(); } void mainWindow::slotCalibrate() { calibration calib(this); if(calib.exec()==QDialog::Accepted) { rxClock=calib.getRXClock(); txClock=calib.getTXClock(); } } void mainWindow::slotAboutQSSTV() { QString temp=tr("QSSTV\nVersion: ") + MAJORVERSION + MINORVERSION ; temp += QString("\n http://users.telenet.be/on4qz \n(c) 2014-%1 -- Johan Maes - ON4QZ\n%2").arg(QDate::currentDate().toString("yyyy")).arg(shortText); // temp += "\n http://users.telenet.be/on4qz \n(c) 2000-20135-- Johan Maes - ON4QZ\n HAMDRM Software based on RX/TXAMADRM\n from PA0MBO"; QMessageBox::about(this,tr("About..."),temp); // QString temp=tr("QSSTV\nVersion: ") + MAJORVERSION + MINORVERSION; // temp += "\n http://users.telenet.be/on4qz \n(c) 2000-20135-- Johan Maes - ON4QZ\n HAMDRM Software based on RX/TXAMADRM\n from PA0MBO"; // QMessageBox::about(this,tr("About..."),temp); } void mainWindow::slotAboutQt() { QMessageBox::aboutQt(this,tr("About...")); } void mainWindow::setPTT(bool p) { if(p) pttIcon->setPixmap(*redPXM); else pttIcon->setPixmap(*greenPXM); } void mainWindow::slotSendBSR() { txWidgetPtr->sendBSR(); } void mainWindow::slotSendID() { txWidgetPtr->sendID(); } void mainWindow::slotSendWfText() { txWidgetPtr->sendWfText(); } void mainWindow::slotDocumentation() { QDesktopServices::openUrl(docURL); } void mainWindow::setBSRPushButton(bool b) { bsrPushButton->setEnabled(b); } #ifndef QT_NO_DEBUG void mainWindow::slotShowDataScope() { scopeViewerData->show(true,true,true,true); } void mainWindow::slotShowSyncScope() { scopeViewerSync->show(true,true,true,true); } void mainWindow::slotScopeOffset() { dataScopeOffset=rxWidgetPtr->functionsPtr()->setOffset(dataScopeOffset,true); } #endif qsstv_8.2.12/qsstv/mainwindow.h000664 001750 001750 00000002160 12440624161 016472 0ustar00jomajoma000000 000000 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include namespace Ui { class MainWindow; } class mainWindow : public QMainWindow { Q_OBJECT public: explicit mainWindow(QWidget *parent = 0); ~mainWindow(); void init(); void setNewFont(); void setPTT(bool p); void setBSRPushButton(bool b); void startReceiving(); private slots: void slotConfigure(); void slotExit(); void slotResetLog(); void slotLogSettings(); void slotCalibrate(); void slotAboutQt(); void slotAboutQSSTV(); void slotDocumentation(); void slotSendID(); void slotSendBSR(); void slotSendWfText(); #ifndef QT_NO_DEBUG void slotShowDataScope(); void slotShowSyncScope(); void slotScopeOffset(); #endif private: Ui::MainWindow *ui; void closeEvent ( QCloseEvent *e ); void readSettings(); void writeSettings(); QComboBox *transmissionModeComboBox; QPushButton *wfTextPushButton; QPushButton *fixPushButton; QPushButton *bsrPushButton; QPushButton *idPushButton; QLabel pttText; QLabel *pttIcon; }; #endif // MAINWINDOW_H qsstv_8.2.12/qsstv/mainwindow.ui000664 001750 001750 00000014754 12440612574 016701 0ustar00jomajoma000000 000000 MainWindow 0 0 831 566 8 50 false false MainWindow QTabWidget::Rounded 1 1 50 false false QTabWidget::Rounded 0 50 false Receive 1 1 Transmit 1 1 Gallery 1 1 0 0 831 21 50 false File Options Help 0 0 16777215 16777215 Exit Configuration Test :/icons/edit.png:/icons/edit.png Calibrate Show Data Scope Log Settings Reset Log About QSSTV About Qt Users Guide Show Sync Scope Scope Offset rxWidget QWidget
rxwidget.h
1
txWidget QWidget
txwidget.h
1
galleryWidget QWidget
gallerywidget.h
1
qsstv_8.2.12/qsstv/qsstv.pro000664 001750 001750 00000030607 12440612574 016063 0ustar00jomajoma000000 000000 #------------------------------------------------- # # Project created by QtCreator 2013-01-21T00:18:40 # #------------------------------------------------- QT += core gui xml network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = qsstv TEMPLATE = app QMAKE_CXXFLAGS_DEBUG += -g3 -O0 INCLUDEPATH += src widgets ../qwt SOURCES += \ drmrx/viterbi_decode.cpp \ drmrx/sourcedecoder.cpp \ drmrx/nrutil.cpp \ drmrx/newfft.cpp \ drmrx/msdhardmsc.cpp \ drmrx/msdhardfac.cpp \ drmrx/mkmscmap.cpp \ drmrx/mkfacmap.cpp \ drmrx/ludcmp.cpp \ drmrx/lubksb.cpp \ drmrx/getsymbolidx.cpp \ drmrx/getofdmsync.cpp \ drmrx/getofdm.cpp \ drmrx/getmode.cpp \ drmrx/getfoffsint.cpp \ drmrx/filter1c.cpp \ drmrx/filter1.cpp \ drmrx/drmstatusframe.cpp \ drmrx/drmdatainput.cpp \ drmrx/drmconstellationframe.cpp \ drmrx/drm.cpp \ drmrx/demodulator.cpp \ drmrx/deinterleaver.cpp \ drmrx/crc16_bytewise.cpp \ drmrx/crc8_c.cpp \ drmrx/channeldecode.cpp \ drmrx/bits2bytes.cpp \ drmtx/drmtransmitter.cpp \ drmtx/common/Parameter.cpp \ drmtx/common/OFDM.cpp \ drmtx/common/DrmTransmitter.cpp \ drmtx/common/DRMSignalIO.cpp \ drmtx/common/DataIO.cpp \ drmtx/common/csoundout.cpp \ drmtx/common/datadecoding/MOTSlideShow.cpp \ drmtx/common/datadecoding/DataDecoder.cpp \ drmtx/common/datadecoding/DABMOT.cpp \ drmtx/common/FAC/FAC.cpp \ drmtx/common/interleaver/SymbolInterleaver.cpp \ drmtx/common/interleaver/BlockInterleaver.cpp \ drmtx/common/matlib/MatlibStdToolbox.cpp \ drmtx/common/matlib/MatlibSigProToolbox.cpp \ drmtx/common/mlc/QAMMapping.cpp \ drmtx/common/mlc/MLC.cpp \ drmtx/common/mlc/EnergyDispersal.cpp \ drmtx/common/mlc/ConvEncoder.cpp \ drmtx/common/mlc/ChannelCode.cpp \ drmtx/common/mlc/BitInterleaver.cpp \ drmtx/common/ofdmcellmapping/OFDMCellMapping.cpp \ drmtx/common/ofdmcellmapping/CellMappingTable.cpp \ drmtx/common/SDC/SDCTransmit.cpp \ drmtx/common/sourcedecoders/AudioSourceDecoder.cpp \ drmtx/common/tables/TableFAC.cpp \ drmtx/common/util/Utilities.cpp \ drmtx/common/util/CRC.cpp \ dsp/synthes.cpp \ dsp/filterparam.cpp \ dsp/filter.cpp \ dsp/downsamplefilter.cpp \ editor/graphicitems.cpp \ editor/gradientdialog.cpp \ editor/editorview.cpp \ editor/editorscene.cpp \ editor/editor.cpp \ rig/rigcontrol.cpp \ sound/wavio.cpp \ sound/waterfalltext.cpp \ sound/soundio.cpp \ sound/soundcontrol.cpp \ sound/resampler.cpp \ sound/resamplefilter.cpp \ sound/calibration.cpp \ sstv/modes/moderobot2.cpp \ sstv/modes/moderobot1.cpp \ sstv/modes/modergb.cpp \ sstv/modes/modepd.cpp \ sstv/modes/modegbr2.cpp \ sstv/modes/modegbr.cpp \ sstv/modes/modebw.cpp \ sstv/modes/modebase.cpp \ sstv/modes/modeavt.cpp \ sstv/syncprocessor.cpp \ sstv/sstvparam.cpp \ sstv/cw.cpp \ utils/supportfunctions.cpp \ utils/rs.cpp \ utils/reedsolomoncoder.cpp \ utils/loggingparams.cpp \ utils/logging.cpp \ utils/ftp.cpp \ videocapt/videocapture.cpp \ widgets/waterfallform.cpp \ widgets/vumeter.cpp \ widgets/spectrumwidget.cpp \ widgets/qscale.cpp \ widgets/imageviewer.cpp \ widgets/fftdisplay.cpp \ widgets/cameracontrol.cpp \ widgets/blockview.cpp \ txwidget.cpp \ txfunctions.cpp \ rxwidget.cpp \ rxfunctions.cpp \ qsstvglobal.cpp \ mainwindow.cpp \ main.cpp \ gallerywidget.cpp \ dispatcher.cpp \ configparams.cpp \ configdialog.cpp \ drmrx/psdmean.cpp \ drmrx/psdcmean.cpp \ drmrx/drmpsdframe.cpp \ drmtx/bsrform.cpp \ drmrx/fixform.cpp \ rig/rigcontrolform.cpp \ utils/qurlinfo.cpp \ utils/qftp.cpp \ utils/qjp2io.cpp \ widgets/textdisplay.cpp \ rig/freqdisplay.cpp \ widgets/markerwidget.cpp \ utils/hybridcrypt.cpp \ utils/macroexpansion.cpp \ xmlrpc/maiaXmlRpcClient.cpp \ xmlrpc/maiaFault.cpp \ xmlrpc/maiaXmlRpcServer.cpp \ xmlrpc/maiaObject.cpp \ xmlrpc/maiaXmlRpcServerConnection.cpp \ xmlrpc/xmlinterface.cpp \ drmprofileform.cpp \ xmlrpc/ipcmessage.cpp \ logbook/logbook.cpp HEADERS += \ drmrx/viterbi_decode.h \ drmrx/structtemplates.h \ drmrx/sourcedecoder.h \ drmrx/resamplefilter.h \ drmrx/nrutil.h \ drmrx/msd_hard_sdc.h \ drmrx/msd_hard.h \ drmrx/drmstatusframe.h \ drmrx/drmproto.h \ drmrx/drmdefs.h \ drmrx/drmdatainput.h \ drmrx/drmconstellationframe.h \ drmrx/drm.h \ drmrx/demodulator.h \ drmtx/common/datadecoding/MOTSlideShow.h \ drmtx/common/datadecoding/DataDecoder.h \ drmtx/common/datadecoding/DABMOT.h \ drmtx/drmtransmitter.h \ drmtx/config.h \ drmtx/common/soundinterface.h \ drmtx/common/Parameter.h \ drmtx/common/OFDM.h \ drmtx/common/GlobalDefinitions.h \ drmtx/common/DrmTransmitter.h \ drmtx/common/DRMSignalIO.h \ drmtx/common/DataIO.h \ drmtx/common/csoundout.h \ drmtx/common/FAC/FAC.h \ drmtx/common/interleaver/SymbolInterleaver.h \ drmtx/common/interleaver/BlockInterleaver.h \ drmtx/common/matlib/MatlibStdToolbox.h \ drmtx/common/matlib/MatlibSigProToolbox.h \ drmtx/common/matlib/Matlib.h \ drmtx/common/mlc/QAMMapping.h \ drmtx/common/mlc/MLC.h \ drmtx/common/mlc/EnergyDispersal.h \ drmtx/common/mlc/ConvEncoder.h \ drmtx/common/mlc/ChannelCode.h \ drmtx/common/mlc/BitInterleaver.h \ drmtx/common/ofdmcellmapping/OFDMCellMapping.h \ drmtx/common/ofdmcellmapping/CellMappingTable.h \ drmtx/common/SDC/SDC.h \ drmtx/common/sourcedecoders/AudioSourceDecoder.h \ drmtx/common/tables/TableQAMMapping.h \ drmtx/common/tables/TableMLC.h \ drmtx/common/tables/TableFAC.h \ drmtx/common/tables/TableDRMGlobal.h \ drmtx/common/tables/TableCarrier.h \ drmtx/common/tables/TableCarMap.h \ drmtx/common/tables/TableAMSS.h \ drmtx/common/util/Utilities.h \ drmtx/common/util/Modul.h \ drmtx/common/util/CRC.h \ drmtx/common/util/Buffer.h \ dsp/synthes.h \ dsp/nco.h \ dsp/filterparam.h \ dsp/filter.h \ dsp/downsamplefilter.h \ editor/qdialog_p.h \ editor/graphicitems.h \ editor/gradientdialog.h \ editor/editorview.h \ editor/editorscene.h \ editor/editor.h \ rig/rigcontrol.h \ sound/wavio.h \ sound/waterfalltext.h \ sound/soundio.h \ sound/soundcontrol.h \ sound/resampler.h \ sound/resampler.cpp_new \ sound/resamplefilter.h \ sound/calibration.h \ sstv/modes/modes.h \ sstv/modes/moderobot2.h \ sstv/modes/moderobot1.h \ sstv/modes/modergb.h \ sstv/modes/modepd.h \ sstv/modes/modegbr2.h \ sstv/modes/modegbr.h \ sstv/modes/modebw.h \ sstv/modes/modebase.h \ sstv/modes/modeavt.h \ sstv/syncprocessor.h \ sstv/sstvparam.h \ sstv/cw.h \ utils/vector.h \ utils/supportfunctions.h \ utils/rs.h \ utils/reedsolomoncoder.h \ utils/loggingparams.h \ utils/logging.h \ utils/ftp.h \ utils/buffermanag.h \ videocapt/videocapture.h \ widgets/waterfallform.h \ widgets/vumeter.h \ widgets/spectrumwidget.h \ widgets/qscale.h \ widgets/imageviewer.h \ widgets/fftdisplay.h \ widgets/cameracontrol.h \ widgets/blockview.h \ txwidget.h \ txfunctions.h \ rxwidget.h \ rxfunctions.h \ qsstvglobal.h \ qsstvdefs.h \ mainwindow.h \ gallerywidget.h \ dispatchevents.h \ dispatcher.h \ configparams.h \ configdialog.h \ drmrx/drmpsdframe.h \ drmtx/bsrform.h \ drmrx/fixform.h \ rig/rigcontrolform.h \ drmrx/mkmap.h \ utils/qurlinfo.h \ utils/qftp.h \ utils/qjp2io.h \ widgets/textdisplay.h \ rig/freqdisplay.h \ rig/rigparams.h \ widgets/markerwidget.h \ utils/hybridcrypt.h \ utils/macroexpansion.h \ xmlrpc/maiaFault.h \ xmlrpc/maiaXmlRpcServer.h \ xmlrpc/maiaXmlRpcClient.h \ xmlrpc/maiaObject.h \ xmlrpc/maiaXmlRpcServerConnection.h \ xmlrpc/xmlinterface.h \ drmprofileform.h \ xmlrpc/ipcmessage.h \ logbook/logbook.h FORMS += \ drmrx/drmstatusframe.ui \ drmrx/drmpsdframe.ui \ drmrx/drmconstellationframe.ui \ editor/textform.ui \ editor/gradientform.ui \ editor/editorform.ui \ sound/soundcontrol.ui \ sound/calibrationform.ui \ sound/calibration.ui \ utils/loggingform.ui \ widgets/waterfallform.ui \ widgets/sweepform.ui \ widgets/spectrumwidget.ui \ widgets/freqform.ui \ widgets/cameracontrol.ui \ widgets/blockview.ui \ txwidget.ui \ rxwidget.ui \ mainwindow.ui \ gallerywidget.ui \ configform.ui \ drmtx/bsrform.ui \ drmrx/fixform.ui \ rig/rigcontrolform.ui \ widgets/textdisplay.ui \ rig/freqdisplay.ui \ drmprofileform.ui RESOURCES += \ qsstv.qrc OTHER_FILES += \ icons/transparency.png \ icons/tone.png \ icons/text.png \ icons/sweep.png \ icons/stop.png \ icons/start.png \ icons/replay.png \ icons/qsstvsplash.png \ icons/qsstv.png \ icons/line.png \ icons/image.png \ icons/gradient.png \ icons/frect.png \ icons/filesave.png \ icons/fileopen.png \ icons/filenew.png \ icons/fcircle.png \ icons/eraser.png \ icons/edit.png \ icons/doubletone.png \ icons/colorselector.png \ icons/colorpicker.png \ icons/colorline.png \ icons/colorfill.png \ icons/camera.png \ icons/arrow.png \ Documentation/manual/qsstv.css \ Documentation/manual/manual.txt \ Documentation/manual/manual.doxy \ Doxyfile \ COPYING \ icons/mgc.raw \ Documentation/manual/images/Gallery_rx.png \ Documentation/manual/images/tx-with-template.png \ Documentation/manual/images/Gallery_tx.png \ Documentation/manual/images/receivesstv.png \ Documentation/manual/images/transmitsstv.png \ Documentation/manual/images/waterfall.png \ Documentation/manual/images/receivedrm.png \ Documentation/manual/images/transmitdrm.png \ Documentation/manual/images/editor_3.png \ Documentation/manual/images/Gallery_template.png \ Documentation/manual/images/config4.png \ Documentation/manual/images/fix.png \ Documentation/manual/images/config2.png \ Documentation/manual/images/config3.png \ Documentation/manual/images/config6.png \ Documentation/manual/images/editor_2.png \ Documentation/manual/images/config7.png \ Documentation/manual/images/config10.png \ Documentation/manual/images/config1.png \ Documentation/manual/images/bsr_select.png \ Documentation/manual/images/config8.png \ Documentation/manual/images/config9.png \ Documentation/manual/images/editor_1.png \ Documentation/manual/images/config5.png \ Documentation/manual/images/wftextpopup.png \ Documentation/manual/images/config.png \ Documentation/manual/images/calibration.png \ Documentation/manual/images/bsr_nfy.png \ Documentation/manual/images/statusbar.png \ Documentation/manual/images/statusleds.png \ Documentation/manual/images/hybrid_checkbox.png \ Documentation/manual/images/hybrid_dis_checkbox.png \ Documentation/manual/images/config11.png \ Documentation/manual/images/flrig1.png \ Documentation/manual/images/rxdrm_constellation.png \ Documentation/manual/images/rxdrm_status.png \ Documentation/manual/images/rxdrm_segments.png \ Documentation/manual/images/txdrm_compression.png \ Documentation/manual/images/txdrm_options.png \ Documentation/manual/images/txdrm_status.png \ Documentation/manual/images/cqrlog1.png \ Documentation/manual/images/cqrlog2.png LIBS += -lasound \ -lhamlib \ -lfftw3f \ -lfftw3 \ -ljasper CONFIG(debug ,debug|release){ message(added debugging) SOURCES += scope/scopeoffset.cpp \ scope/scopeview.cpp \ scope/scopeplot.cpp HEADERS += scope/scopeoffset.h \ scope/scopeview.h \ scope/scopeplot.h FORMS += scope/scopeoffset.ui \ scope/plotform.ui INCLUDEPATH += /usr/include/qwt LIBS += ../qwt/libqwt.a } CONFIG(debug ,debug|release){ dox.commands = cd $$PWD/Documentation/manual ;doxygen manual.doxy; dox.depends= FORCE PRE_TARGETDEPS += dox message(dox will be generated) } dox.path=/usr/share/doc/$$TARGET dox.files= $$PWD/manual/* QMAKE_EXTRA_TARGETS += dox target.path = /usr/bin INSTALLS += target dox qsstv_8.2.12/qsstv/qsstv.qrc000664 001750 001750 00000002121 12440612574 016036 0ustar00jomajoma000000 000000 icons/fileopen.png icons/filesave.png icons/text.png icons/image.png icons/fcircle.png icons/frect.png icons/arrow.png icons/colorpicker.png icons/replay.png icons/qsstv.png icons/transparency.png icons/start.png icons/camera.png icons/tone.png icons/stop.png icons/edit.png icons/doubletone.png icons/sweep.png icons/qsstvsplash.png icons/colorfill.png icons/colorselector.png icons/eraser.png icons/filenew.png icons/gradient.png icons/mgc.raw icons/mgc2.raw icons/colorline.png qsstv_8.2.12/qsstv/qsstvdefs.h000664 001750 001750 00000001607 12440612574 016352 0ustar00jomajoma000000 000000 #include #include using namespace std; /* Because of the library: "complex" */ #ifndef QSSTVDEFS_H #define QSSTVDEFS_H #define RXSTRIPE 1024 #define TXSTRIPE 1024 #define SUBSAMPLINGRATIO 4 #define SAMPLINGSTRIPE (SUBSAMPLINGRATIO*RXSTRIPE) // 4 times oversampled #define MAXNUMCHANNELS 2 #define SOUNDFRAME quint32 #define BASESAMPLERATE 48000. #define SAMPLERATE (BASESAMPLERATE/SUBSAMPLINGRATIO) //typedef double DSPFLOAT; typedef float DSPFLOAT; typedef unsigned char byte; enum etransmissionMode {SSTV,DRM,NOMODE}; /* Define the application specific data-types ------------------------------- */ typedef double _REAL; typedef complex<_REAL> _COMPLEX; typedef short _SAMPLE; typedef unsigned char _BYTE; typedef bool _BOOLEAN; typedef unsigned char _BINARY; #ifndef false #define false false #define true true #endif #endif // QSSTVDEFS_H qsstv_8.2.12/qsstv/qsstvglobal.cpp000664 001750 001750 00000005645 12505545767 017245 0ustar00jomajoma000000 000000 /************************************************************************** * Copyright (C) 2000-2012 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "qsstvglobal.h" #include #include const QString MAJORVERSION = "8.2"; const QString CONFIGVERSION = "8.1"; const QString MINORVERSION = ".12"; const QString LOGVERSION = ("qsstv."+MAJORVERSION+MINORVERSION+".log"); const QString ORGANIZATION = "ON4QZ"; const QString APPLICATION = ("qsstv" +CONFIGVERSION); const QString qsstvVersion=QString("QSSTV " + MAJORVERSION+MINORVERSION); const QString shortText=QString("HAMDRM Software based on RX/TXAMADRM\n from PA0MBO") ; QByteArray *debugPtr; QStatusBar *statusBarPtr; configDialog *confDiag; #ifndef QT_NO_DEBUG scopeView *scopeViewerData; scopeView *scopeViewerSync; #endif mainWindow *mainWindowPtr; dispatcher *dispatcherPtr; waterfallText *waterfallPtr; QSplashScreen *splashPtr; QString splashStr; QCursor *cpCursor; logFile *logfile; // for DRM emscStatus msc_valid; int bodyTotalSegments; int rxSegments; int currentSegmentNumber; unsigned int rxTransportID; //unsigned int bitsPerSecond; QList drmBlockList; sourceDecoder srcDecoder; uint txTransportID; QList fixBlockList; bool stopDRM; float avgSNR; float lastAvgSNR; QPixmap *greenPXM; QPixmap *redPXM; logBook *logBookPtr; xmlInterface *xmlIntfPtr; void globalInit(void) { logfile=new logFile; logfile->open(LOGVERSION); QPixmap pm(":/icons/colorpicker.png"); cpCursor=new QCursor(pm,0,pm.height()-1); } void globalEnd(void) { logfile->close(); } qsstv_8.2.12/qsstv/qsstvglobal.h000664 001750 001750 00000003552 12474354470 016677 0ustar00jomajoma000000 000000 #ifndef SSTVGLOBAL_H #define SSTVGLOBAL_H #include #include #include "utils/logging.h" #include "drmrx/sourcedecoder.h" #include "qsstvdefs.h" class QSplashScreen; class QStatusBar; class logFile; class galleryWidget ; class configDialog; class dispatcher; class rxWidget; class txWidget; class imageViewer; class mainWindow; class waterfallText; class logBook; class xmlInterface; class synthesizer; extern const QString MAJORVERSION; extern const QString CONFIGVERSION; extern const QString MINORVERSION; extern const QString ORGANIZATION; extern const QString APPLICATION; extern const QString qsstvVersion; extern const QString shortText; #define MAGICNUMBER (('4'<<24)+('Q'<<16)+('Z'<<8)+'S') extern QSplashScreen *splashPtr; extern configDialog *confDiag; extern mainWindow *mainWindowPtr; extern waterfallText *waterfallPtr; extern QString splashStr; extern txWidget *txWidgetPtr; extern galleryWidget *galleryWidgetPtr; extern synthesizer *synthesPtr; extern dispatcher *dispatcherPtr; extern QStatusBar *statusBarPtr; // for DRM enum emscStatus {INVALID,VALID,ALREADYRECEIVED}; extern emscStatus msc_valid; extern int bodyTotalSegments; extern int rxSegments; extern int currentSegmentNumber; extern unsigned int rxTransportID; extern unsigned int bitsPerSecond; extern bool stopDRM; extern QList drmBlockList; extern uint txTransportID; extern QList fixBlockList; extern float avgSNR; extern float lastAvgSNR; extern QCursor *cpCursor; void globalInit(void); void globalEnd(void); extern logFile *logfile; extern logBook *logBookPtr; extern xmlInterface *xmlIntfPtr; #ifndef QT_NO_DEBUG class scopeView; extern scopeView *scopeViewerData; extern scopeView *scopeViewerSync; #endif extern QByteArray *debugPtr; extern sourceDecoder srcDecoder; extern QPixmap *greenPXM; extern QPixmap *redPXM; #endif qsstv_8.2.12/qsstv/rxfunctions.cpp000664 001750 001750 00000031574 12474570467 017266 0ustar00jomajoma000000 000000 #include "rxfunctions.h" #include "qsstvglobal.h" #include "configparams.h" #include "rxwidget.h" #include "sound/soundio.h" #include "dsp/filterparam.h" #include "dsp/filter.h" #include "dsp/downsamplefilter.h" #ifndef QT_NO_DEBUG #include "scope/scopeview.h" #include "scope/scopeoffset.h" #endif #include "configparams.h" #include "utils/supportfunctions.h" #include "dispatcher.h" #include "sstv/modes/modes.h" #include "drmrx/drm.h" #include "drmrx/drmproto.h" #include "drmrx/demodulator.h" #define DRMNEW const QString stateStr[rxFunctions::WAIT+1]= { "Hunting", "SlantAdjust", "Processing", "Restart", "Sync Lost", "End", "Wait" }; rxFunctions::rxFunctions(QObject *parent) : QThread(parent) { rxState=RXIDLE; downSampleFilter=NULL; rxFilter=NULL; syncFilter=NULL; dataInputPtr=new drmDataInput(RXSTRIPE); currentMode=0; #ifndef QT_NO_DEBUG scopeViewerData->setCurveName("Volume",SCDATA1); scopeViewerData->setCurveName("FM Demod",SCDATA2); scopeViewerData->setCurveName("raw Input",SCDATA3); scopeViewerData->setCurveName("none",SCDATA4); scopeViewerData->setAxisTitles("Samples","int","demod"); #endif demodulatorPtr=new demodulator; } rxFunctions::~rxFunctions() { if(downSampleFilter==NULL) delete downSampleFilter; if(rxFilter==NULL) delete rxFilter; if(syncFilter==NULL) delete syncFilter; } void rxFunctions::run() { addToLog("starting rxfunctions run",LOGRXFUNC); int count; bool done=false; init(); addToLog("end init rxfunctions run",LOGRXFUNC); abort=false; while(!abort) { switch(rxState) { case RXIDLE: msleep(200); break; case RXRUNNING: if((count=soundIOPtr->rxBuffer.count())isCapturing()) { rxState=RXINIT; } } else { // addToLog(QString("LoadTempBuf count=%1").arg(count),LOGRXFUNC); soundIOPtr->rxBuffer.copyNoCheck(tempBuf,SAMPLINGSTRIPE); // addToLog("LoadTempBuf",LOGRXFUNC); downSampleFilter->downSample4(tempBuf); displayFFTEvent* ce = new displayFFTEvent(downSampleFilter->filteredDataPtr()); ce->waitFor(&done); QApplication::postEvent(dispatcherPtr, ce); while(!done) {usleep(10);} switch (transmissionModeIndex) { case DRM: runDRM(); break; case SSTV: rxHoldingBuffer.putNoCheck(downSampleFilter->filteredDataPtr(),RXSTRIPE); bufferCounter++; getData(); processSSTV(); sampleCounter+=RXSTRIPE; rxHoldingBuffer.skip(RXSTRIPE); demodBuffer.skip(RXSTRIPE); break; // case FAX: // break; case NOMODE: break; } } break; case RXINIT: if(transmissionModeIndex==SSTV) syncProc.init(); //reset meters rxState=RXIDLE; break; } } abort=false; } void rxFunctions::init() { // rxMode=rxModeIndex; setFilters(rxWidgetPtr->getFilterIndex()); // setup SSTV Filters avgSNR=0; if(transmissionModeIndex==DRM) { n = DRMBUFSIZE; /* initialisations */ demodulatorPtr->init(); dataInputPtr->init(RXSTRIPE); initGetmode( n / 4); rRation = 1.000; samplerate_offset_estimation = 0.0; runstate = RUN_STATE_POWER_ON; /* POWER_ON */ channel_decoding(); runstate = RUN_STATE_INIT; /* INIT */ channel_decoding(); runstate = RUN_STATE_FIRST; /* FIRSTRUN */ runstate = RUN_STATE_NORMAL; /* NORMAL RUN */ } else { SSTVState=HUNTING; syncProc.init(); } if(downSampleFilter==NULL) downSampleFilter=new downsampleFilter(SAMPLINGSTRIPE,downSampleFilterParam,DSAMPLEFILTERLEN,false); else downSampleFilter->init(); sampleCounter=0; bufferCounter=0; rxHoldingBuffer.reset(); } void rxFunctions::getData() { // addToLog(QString("GetData readIndex: %1,sampleCounter: %2").arg(rxHoldingBuffer.getReadIndex()).arg(sampleCounter),LOGRXFUNC); rxFilter->processFM(rxHoldingBuffer.readPointer()); demodBuffer.putNoCheck(rxFilter->filteredDataPtr(),RXSTRIPE); syncFilter->processFM(rxHoldingBuffer.readPointer()); syncProc.process(); displaySyncEvent* ce; ce = new displaySyncEvent(syncProc.syncQuality,(rxFilter->volumePtr()[0]-500)/500); QApplication::postEvent(dispatcherPtr, ce); // addToLog("EndFilter",LOGPERFORM); #ifndef QT_NO_DEBUG scopeViewerData->addData(SCDATA3,rxHoldingBuffer.readPointer(),sampleCounter,RXSTRIPE); scopeViewerData->addData(SCDATA2,demodBuffer.readPointer(),sampleCounter,RXSTRIPE); scopeViewerData->addData(SCDATA1,rxFilter->volumePtr(),sampleCounter,RXSTRIPE); #endif } #ifndef QT_NO_DEBUG unsigned int rxFunctions::setOffset(unsigned int offset,bool ask) { if(ask) { scopeOffset so; so.setOffset(offset); if(so.exec()==QDialog::Accepted) { xOffset=so.getOffset()*1000; } } else { xOffset=offset*1000; } syncProc.setOffset(xOffset); scopeViewerData->setOffset(xOffset); syncProc.setOffset(xOffset); return xOffset/1000; } #endif void rxFunctions::processSSTV() { rxSSTVStatusEvent *stce; endImageRXEvent *endce; bool done=false; int block; unsigned long sampleCounterLatch; switch(SSTVState) { case HUNTING: if(syncProc.isInSync()==0) { stce= new rxSSTVStatusEvent(QString("No sync")); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done break; // no sync } if(!create(syncProc.getMode(),syncProc.getNewClock())) break; stce= new rxSSTVStatusEvent(QString("Receiving ")+getSSTVModeNameLong(syncProc.getMode())); lastUsedMode=getSSTVModeNameShort(syncProc.getMode()); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done case SLANTADJUST: syncPosition=syncProc.getSyncPosition(); if(syncProc.isInSync()==1) { syncPosition=currentMode->adjustSyncPosition(syncPosition); // only execute if no retrace addToLog(QString("rxFunctions: adjusted syncPosition= %1").arg(syncPosition),LOGRXFUNC); } sampleCounterLatch=sampleCounter; //remember where we've got addToLog(QString("rxFunctions: sampleCounterLatch= %1").arg(sampleCounterLatch),LOGRXFUNC); block=(syncPosition)/RXSTRIPE; demodBuffer.rewind(sampleCounter-block*RXSTRIPE); addToLog(QString("sc_rewind: block=%1,rewind= %2").arg(block).arg(sampleCounter-block*RXSTRIPE+RXSTRIPE),LOGRXFUNC); sampleCounter=block*RXSTRIPE; currentMode->setRxSampleCounter(sampleCounter); currentMode->redrawFast(true); currentMode->process(demodBuffer.readPointer(),syncPosition-sampleCounter,true); addToLog(QString("rxFunctions: currentMode pos:=%1").arg(syncPosition-sampleCounter),LOGRXFUNC); // addToLog(QString("after Current mode set: %1,sampleCounter: %2").arg(rxHoldingBuffer.getReadIndex()).arg(sampleCounter),LOGRXFUNC); while(sampleCounterprocess(demodBuffer.readPointer()); } addToLog(QString("end loop readIndex: %1,sampleCounter: %2").arg(rxHoldingBuffer.getReadIndex()).arg(sampleCounter),LOGRXFUNC); currentMode->redrawFast(false); setState(PROCESSING); break; case PROCESSING: if(currentMode->process(demodBuffer.readPointer())==modeBase::MBENDOFIMAGE) { setState(END); } if(syncProc.hasRetrace()) { setState(END); } if(syncProc.isInSync()==0) { setState(END); } else if(syncProc.hasNewClock()) { currentMode->init(syncProc.getNewClock()); setState(SLANTADJUST); } break; case RESTART: block=(int) ceil((rxClock*0.3)/RXSTRIPE)+1; // rewind to position before the last detected retrace, + one because we will skip 1 on return of getData() addToLog(QString("rxFunction: retraceVertical: count=%1").arg(block*RXSTRIPE),LOGRXFUNC); rxHoldingBuffer.rewind(block*RXSTRIPE); init(); sampleCounter=-RXSTRIPE; // will be incremented (will be 0) when returning from this function break; case SYNCLOST: addToLog(QString("rxFunction: synclost"),LOGRXFUNC); case END: addToLog("rxFunc state END",LOGRXFUNC); endce = new endImageRXEvent(); endce->waitFor(&done); QApplication::postEvent(dispatcherPtr, endce); while(!done) { msleep(10);} setState(RESTART); break; case WAIT: break; } } void rxFunctions::setFilters(int fIndex) { if(rxFilter==NULL) rxFilter= new filter(RXSTRIPE,filterStruct[fIndex].filterPtr,RXNUMTAPS,filterStruct[fIndex].centerFrequency,rxClock/SUBSAMPLINGRATIO,true,0.001); else rxFilter->setFilterParams(filterStruct[fIndex].filterPtr,RXNUMTAPS,filterStruct[fIndex].centerFrequency,rxClock/SUBSAMPLINGRATIO,true,0.001); if(syncFilter==NULL) syncFilter= new filter(RXSTRIPE,wide1200BP,RXNUMTAPS,1200,rxClock/SUBSAMPLINGRATIO,true,1); syncProc.setFilters(rxFilter,syncFilter); } void rxFunctions::stopAndWait() { if(!isRunning()) return; rxState=RXINIT; while(rxState!=RXIDLE) { if(!isRunning()) return; // to avoid race conditions qApp->processEvents(); } } bool rxFunctions::create(esstvMode m,DSPFLOAT clock) { bool done=false; if(currentMode) delete currentMode; currentMode=0; switch (m) { case M1: case M2: currentMode=new modeGBR(m,RXSTRIPE,false); break; case S1: case S2: case SDX: currentMode=new modeGBR2(m,RXSTRIPE,false); break; case R36: currentMode=new modeRobot1(m,RXSTRIPE,false); break; case R24: case R72: currentMode=new modeRobot2(m,RXSTRIPE,false); break; case SC2_60: case SC2_120: case SC2_180: case P3: case P5: case P7: currentMode=new modeRGB(m,RXSTRIPE,false); break; case FAX480: case BW8: case BW12: currentMode=new modeBW(m,RXSTRIPE,false); break; case AVT24: case AVT90: case AVT94: currentMode=new modeAVT(m,RXSTRIPE,false); break; case PD50: case PD90: case PD120: case PD160: case PD180: case PD240: case PD290: case MP73: case MP115: case MP140: case MP175: currentMode=new modePD(m,RXSTRIPE,false); break; default: m=NOTVALID; break; } if (m!=NOTVALID) { initializeSSTVParametersIndex(m,false); QString s=getSSTVModeNameLong(m); addToLog("rxFunction:create RX mode",LOGRXFUNC); currentMode->init(clock); startImageRXEvent* ce = new startImageRXEvent(QSize(currentMode->imagePixels(),currentMode->imageLines())); ce->waitFor(&done); QApplication::postEvent(dispatcherPtr, ce); while(!done) { msleep(10);} return true; } return false; } void rxFunctions::startRX() { init(); rxState=RXRUNNING; } void rxFunctions::setState(eSSTVState st) { addToLog(QString("rxfunc: set SSTVState: from %1 to %2").arg(stateStr[SSTVState]).arg (stateStr[st]),LOGRXFUNC); SSTVState=st; } void rxFunctions::retraceVertical(void) { setState(RESTART); } bool rxFunctions::saveOK() { if(currentMode==0) { addToLog("saveOK called with currentMode==0",LOGRXFUNC); return false; } if(currentMode->receivedLines()>(currentMode->imageLines()/3)) return true; return false; } #define RATIONAVG 0.01 void rxFunctions::runDRM() { bool done=false; DSPFLOAT temp; displayDRMStatEvent *ce1; displayDRMInfoEvent *ce2 ; temp=WMERFAC; if(temp<0) temp=0; if(demodulatorPtr->isFrameSync()) { avgSNR=(1-0.05)*avgSNR+0.05*temp; ce1 = new displayDRMStatEvent(avgSNR,downSampleFilter->avgVolume); } else { ce1 = new displayDRMStatEvent(0,downSampleFilter->avgVolume); } QApplication::postEvent(dispatcherPtr, ce1); while(input_samples_buffer_request ==0) { demodulatorPtr->demodulate(resamp_signal,0); } im=0; im=dataInputPtr->getData(downSampleFilter->filteredDataPtr(),resamp_signal,rRation); // arrayDump("resam",resamp_signal,RXSTRIPE,true); if(im==0) { msleep(10); return; } demodulatorPtr->demodulate(resamp_signal,im); ce2 = new displayDRMInfoEvent; ce2->waitFor(&done); QApplication::postEvent(dispatcherPtr, ce2); while(!done) { usleep(10);} } qsstv_8.2.12/qsstv/rxfunctions.h000664 001750 001750 00000003310 12450753733 016707 0ustar00jomajoma000000 000000 #ifndef RXFUNCTIONS_H #define RXFUNCTIONS_H #include #include "qsstvdefs.h" #include "sstv/syncprocessor.h" #include "utils/buffermanag.h" #include "drmrx/drmdefs.h" #include "drmrx/drmdatainput.h" #include "drmrx/sourcedecoder.h" class filter; class downsampleFilter; class modeBase; class demodulator; class rxFunctions : public QThread { Q_OBJECT public: enum erxState {RXIDLE,RXRUNNING,RXINIT}; enum eSSTVState {HUNTING,SLANTADJUST,PROCESSING,RESTART,SYNCLOST,END,WAIT}; explicit rxFunctions(QObject *parent = 0); ~rxFunctions(); void init(); void run(); void stopAndWait(); void retraceVertical(void); void startRX(); QString getModeString (void){ return lastUsedMode;} bool saveOK(); #ifndef QT_NO_DEBUG unsigned int setOffset(unsigned int offset, bool ask); #endif signals: public slots: private: downsampleFilter *downSampleFilter; filter *rxFilter; filter *syncFilter; unsigned int sampleCounter; void setFilters(int index); void setState(eSSTVState st); void getData(); void processSSTV(); bool create(esstvMode m,DSPFLOAT clock); void runDRM(); unsigned int bufferCounter; syncProcessor syncProc; erxState rxState; eSSTVState SSTVState; modeBase *currentMode; bool abort; QString lastUsedMode; unsigned long syncPosition; buffer rxHoldingBuffer; // 2^22= 4194304, divided by samplingrate 12000 gives 349 seconds buffering buffer demodBuffer; // 2^22= 4194304, divided by samplingrate 12000 gives 349 seconds buffering unsigned int xOffset; // DRM float rRation; float resamp_signal[2 * DRMBUFSIZE]; int n,im; drmDataInput *dataInputPtr; short int tempBuf[SAMPLINGSTRIPE]; }; #endif // RXFUNCTIONS_H qsstv_8.2.12/qsstv/rxwidget.cpp000664 001750 001750 00000014641 12474601537 016526 0ustar00jomajoma000000 000000 #include "rxwidget.h" #include "txwidget.h" #include "qsstvglobal.h" #include "utils/supportfunctions.h" #include "ui_rxwidget.h" #include "sstv/sstvparam.h" #include "dsp/filterparam.h" #include "sound/soundio.h" #include "configparams.h" #include "dispatcher.h" #include "mainwindow.h" rxWidget *rxWidgetPtr; spectrumWidget *rxWidget::fftDisplayPtr() { return ui->spectrumFrame; } vuMeter *rxWidget::vMeterPtr() { return ui->vuWidget; } vuMeter *rxWidget::sMeterPtr() { return ui->syncWidget; } rxWidget::rxWidget(QWidget *parent) : QWidget(parent), ui(new Ui::rxWidget) { int i; ui->setupUi(this); rxFunctionsPtr=new rxFunctions(); ui->syncWidget->setHorizontal(false); ui->syncWidget->setColors(Qt::red,QColor(255,165,0),Qt::green); ui->syncWidget->setMaximum(10.); ui->syncWidget->setValue(0.); ui->syncWidget->setLabelText("S"); ui->vuWidget->setHorizontal(true); ui->vuWidget->setLabelText("V"); ui->vuWidget->setColors(QColor(255,50,0),Qt::green,Qt::red); ui->vuWidget->setMaximum(10.); ui->vuWidget->setValue(0.); imageViewerPtr=ui->imageFrame; imageViewerPtr->createImage(QSize(320,256),QColor(0,0,128)); imageViewerPtr->setType(imageViewer::RXIMG); ui->sstvModeComboBox->addItem("Auto"); for(i=0;isstvModeComboBox->addItem(getSSTVModeNameLong((esstvMode)i)); } for(i=0;ifilterComboBox->addItem(filterStruct[i].filterName); } for(i=0;isquelchComboBox->addItem(squelchStr[i]); } connect(ui->startToolButton, SIGNAL(clicked()),SLOT(slotStart())); connect(ui->stopToolButton, SIGNAL(clicked()),SLOT(slotStop())); connect(ui->autoSlantAdjustCheckBox,SIGNAL(clicked()),SLOT(slotGetParams())); connect(ui->autoSaveCheckBox,SIGNAL(clicked()),SLOT(slotGetParams())); connect(ui->saveToolButton, SIGNAL(clicked()),SLOT(slotSaveImage())); connect(ui->squelchComboBox,SIGNAL(currentIndexChanged(int)),SLOT(slotGetParams())); connect(ui->settingsTableWidget,SIGNAL(currentChanged(int)),this, SLOT(slotTransmissionMode(int))); } rxWidget::~rxWidget() { rxFunctionsPtr->stopAndWait(); delete ui; } void rxWidget::init() { splashStr+=QString( "Setting up RX" ).rightJustified(25,' ')+"\n"; splashPtr->showMessage ( splashStr ,Qt::AlignLeft,Qt::white); qApp->processEvents(); readSettings(); rxFunctionsPtr->start(); } void rxWidget::slotStart() { getParams(); dispatcherPtr->startRX(true); } void rxWidget::slotStop() { dispatcherPtr->startRX(false); } void rxWidget::start(bool st) { if(st) { rxFunctionsPtr->stopAndWait(); soundIOPtr->startCapture(); rxFunctionsPtr->startRX(); addToLog("starting rxfunction run",LOGRXMAIN); } else { soundIOPtr->idle(); writeSettings(); ui->spectrumFrame->writeSettings(); rxFunctionsPtr->stopAndWait(); } } void rxWidget::readSettings() { QSettings qSettings; qSettings.beginGroup("RX"); useVIS=qSettings.value("useVIS",false).toBool(); autoSlantAdjust=qSettings.value("autoSlantAdjust",false).toBool(); autoSave=qSettings.value("autoSave",true).toBool(); squelch=qSettings.value("squelch",1).toInt(); filterIndex=(qSettings.value("filterIndex",0)).toInt(); setParams(); qSettings.endGroup(); } void rxWidget::writeSettings() { QSettings qSettings; qSettings.beginGroup("RX"); getParams(); qSettings.setValue( "useVIS",useVIS); qSettings.setValue( "autoSlantAdjust",autoSlantAdjust); qSettings.setValue( "autoSave",autoSave); qSettings.setValue( "squelch",squelch); qSettings.setValue( "filterIndex", filterIndex); qSettings.endGroup(); } void rxWidget::getParams() { getValue(useVIS,ui->useVISCheckBox); getValue(autoSlantAdjust,ui->autoSlantAdjustCheckBox); getValue(autoSave,ui->autoSaveCheckBox); getIndex(squelch,ui->squelchComboBox); getIndex(filterIndex,ui->filterComboBox); if(filterIndex<0) filterIndex=0; } void rxWidget::setParams() { setValue(useVIS,ui->useVISCheckBox); setValue(autoSlantAdjust,ui->autoSlantAdjustCheckBox); setValue(autoSave,ui->autoSaveCheckBox); setIndex(squelch,ui->squelchComboBox); setIndex(filterIndex,ui->filterComboBox); } void rxWidget::setSSTVStatusText(QString txt) { ui->sstvStatusLineEdit->setText(txt); } void rxWidget::setDRMStatusText(QString txt) { ui->drmStatusLineEdit->setText(txt); } void rxWidget::setFilterIndex(int index) { ui->filterComboBox->setCurrentIndex(index); } int rxWidget::getFilterIndex() { return ui->filterComboBox->currentIndex(); } void rxWidget::slotGetParams() { getParams(); } void rxWidget::setSettingsTab() { int i; if((transmissionModeIndex>=0)&&(transmissionModeIndexsettingsTableWidget->widget(i)->setEnabled(false); } ui->settingsTableWidget->widget(transmissionModeIndex)->setEnabled(true); ui->settingsTableWidget->setCurrentIndex(transmissionModeIndex); } if(transmissionModeIndex==DRM) { ui->syncWidget->setColors(QColor(0,90,0),QColor(0,190,0),Qt::green); ui->syncWidget->setMaximum(25.); ui->syncWidget->setMinimum(5.); ui->syncWidget->setValue(0.); ui->vuWidget->setColors(QColor(255,50,0),Qt::green,Qt::red); ui->vuWidget->setMaximum(40.); ui->vuWidget->setMinimum(18.); ui->vuWidget->setValue(0.); ui->spectrumFrame->displaySettings(true,true); } else { ui->syncWidget->setColors(Qt::red,QColor(255,165,0),Qt::green); ui->syncWidget->setMaximum(10.); ui->syncWidget->setMinimum(0.); ui->syncWidget->setValue(0.); ui->vuWidget->setColors(QColor(255,50,0),Qt::green,Qt::red); ui->vuWidget->setMaximum(10.); ui->vuWidget->setMinimum(0.); ui->vuWidget->setValue(0.); ui->spectrumFrame->displaySettings(false,false); } } void rxWidget::slotTransmissionMode(int rxtxMode) { transmissionModeIndex=(etransmissionMode)rxtxMode; start(false); setSettingsTab(); txWidgetPtr->setSettingsTab(); if(transmissionModeIndex==DRM) { mainWindowPtr->setBSRPushButton(true); } else { mainWindowPtr->setBSRPushButton(true); } start(true); } void rxWidget::slotSaveImage() { dirDialog dd(this); QString filename; filename=dd.saveFileName(rxImagesPath,"*",defaultImageFormat); if(filename.isEmpty()) return; imageViewerPtr->save(filename,defaultImageFormat,true); } qsstv_8.2.12/qsstv/rxwidget.h000664 001750 001750 00000002571 12473446772 016201 0ustar00jomajoma000000 000000 #ifndef RXWIDGET_H #define RXWIDGET_H #include #include #include "rxfunctions.h" #include "ui_rxwidget.h" class imageViewer; class spectrumWidget; class vuMeter; namespace Ui { class rxWidget; } class rxWidget : public QWidget { Q_OBJECT public: explicit rxWidget(QWidget *parent = 0); ~rxWidget(); void init(); void start(bool st); void readSettings(); void writeSettings(); void setFilterIndex(int index); int getFilterIndex(); void setSettingsTab(); rxFunctions *functionsPtr() {return rxFunctionsPtr;} imageViewer *getImageViewerPtr(){ return imageViewerPtr;} spectrumWidget *fftDisplayPtr(); vuMeter *vMeterPtr(); vuMeter *sMeterPtr(); void setSSTVStatusText(QString txt); void setDRMStatusText(QString txt); // drmPSDFrame *psdWdg() {return ui->drmPSDWidget;} drmConstellationFrame *mscWdg() {return ui->drmMSCWidget;} drmConstellationFrame *facWdg() {return ui->drmFACWidget;} // drmPSDFrame *psdWdg() {return ui->drmPSDWidget;} drmStatusFrame *statusWdg() {return ui->drmStatusWidget;} private slots: void slotStart(); void slotStop(); void slotGetParams(); void slotTransmissionMode(int rxtxMode); void slotSaveImage(); private: Ui::rxWidget *ui; void getParams(); void setParams(); rxFunctions *rxFunctionsPtr; imageViewer *imageViewerPtr; }; extern rxWidget *rxWidgetPtr; #endif // RXWIDGET_H qsstv_8.2.12/qsstv/rxwidget.ui000664 001750 001750 00000072354 12474600210 016351 0ustar00jomajoma000000 000000 rxWidget 0 0 914 494 Ubuntu Mono 9 50 false false Form Start receiver Status Start receiver ... :/icons/start.png:/icons/start.png Stop receiver Stop receiver ... :/icons/stop.png:/icons/stop.png Restart receiver Restart receiver ... :/icons/replay.png:/icons/replay.png Save image Save Image ... :/icons/filesave.png:/icons/filesave.png Qt::Horizontal 40 20 1 1 580 360 1200 800 2 18 0 18 16777215 18 0 18 16777215 1 0 true 0 0 16777215 16777215 0 SSTV 1 1 1 1 1 2 Use VIS Code to start Use VIS Code to start Use VIS Filter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 110 0 Reception filter Reception filter Correct slant automatically Correct slant automatically Auto Slant Sensitivity - Higher is more sensitive Sensitivity - Higher is more sensitive Sensitivity Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Save image when complete Save image when complete Autosave Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 25 QFrame::Panel QFrame::Sunken 3 Qt::Vertical 17 0 DRM 1 1 1 1 1 1 QFrame::StyledPanel QFrame::Raised 0 20 8 QFrame::Panel QFrame::Sunken 2 1 FAC Qt::AlignCenter 0 80 16777215 120 76 76 76 197 197 197 0 0 0 60 60 60 76 76 76 76 76 76 197 197 197 0 0 0 60 60 60 76 76 76 0 0 0 197 197 197 0 0 0 0 0 0 0 0 0 QFrame::Panel QFrame::Sunken 3 1 MSC Qt::AlignCenter 0 80 16777215 120 76 76 76 197 197 197 0 0 0 60 60 60 76 76 76 76 76 76 197 197 197 0 0 0 60 60 60 76 76 76 0 0 0 197 197 197 0 0 0 0 0 0 0 0 0 QFrame::Panel QFrame::Sunken 3 0 0 100 80 1000 1000 imageViewer QWidget
widgets/imageviewer.h
1
vuMeter QWidget
widgets/vumeter.h
1
spectrumWidget QWidget
widgets/spectrumwidget.h
1
drmStatusFrame QFrame
drmrx/drmstatusframe.h
1
drmConstellationFrame QFrame
drmrx/drmconstellationframe.h
1
qsstv_8.2.12/qsstv/txfunctions.cpp000664 001750 001750 00000044702 12450753733 017256 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "txfunctions.h" #include "qsstvglobal.h" #include "configparams.h" #include //#include "imagecoder.h" #include "dsp/synthes.h" #include "sstv/modes/modes.h" #include "dispatcher.h" #include "sstv/cw.h" #include #include #include "txwidget.h" #include "sound/soundio.h" #include "sound/waterfalltext.h" #include "utils/hybridcrypt.h" #include "rig/rigcontrol.h" #define SILENCEDELAY 0.600 // send silence after transmission QMutex txMutex; esstvMode modeIndexTx; int templateIndex; bool useTemplate; bool useCW; bool useVOX; txFunctions::txFunctions() { synthesPtr=new synthesizer(txClock); currentMode=0; oldMode=NOTVALID; txState=TXIDLE; started=false; txDRM=new drmTransmitter; txList.clear(); useHybrid=false; } txFunctions::~txFunctions() { delete synthesPtr; if(currentMode) delete currentMode; } void txFunctions::run() { abort=false; init(); while(!abort) { progressTXEvent *ce; started=true; switch (txState) { case TXIDLE: msleep(10); break; case TXACTIVE: msleep(1); break; case TXSENDTONE: waitTxOn(); addToLog("txFunc: entered TXSENDTONE",LOGTXFUNC); synthesPtr->sendTone(toneDuration,toneLowerFrequency,toneUpperFrequency,false); addToLog("txFunc: TXSENDTONE waiting for end",LOGTXFUNC); waitEnd(); txState=TXIDLE; break; case TXSENDDRM: waitTxOn(); // synthesPtr->sendTone(5,1900,1900,false); waterfallTime=waterfallPtr->getDuration(endPicWF); waterfallTime+=waterfallPtr->getDuration(startPicWF); initDRMImage(); ce=new progressTXEvent(calcTxTime(true,waterfallTime)); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done addToLog("start of wf",LOGTXFUNC); waterfallPtr->setText(startPicWF); synthesPtr->sendWFText(); addToLog("start of txDrm",LOGTXFUNC); txDRM->start(true); addToLog("end of txDrm",LOGTXFUNC); if(txState==TXSENDDRM) // abort if txState is idle { waterfallPtr->setText(endPicWF); synthesPtr->sendWFText(); addToLog("end of wf",LOGTXFUNC); addToLog("txFunc: TXSENDDRM waiting for end",LOGTXFUNC); waitEnd(); } txState=TXIDLE; break; case TXSENDDRMBSR: waitTxOn(); waterfallTime=waterfallPtr->getDuration(bsrWF); ce=new progressTXEvent(calcTxTime(true,waterfallTime)); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done synthesPtr->sendWFText(); txDRM->start(true); addToLog("txFunc: TXSENDDRMBSR waiting for end",LOGTXFUNC); waitEnd(); txState=TXIDLE; break; case TXSENDDRMFIX: waitTxOn(); waterfallTime=waterfallPtr->getDuration(fixWF); ce=new progressTXEvent(calcTxTime(true,waterfallTime)); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done synthesPtr->sendWFText(); txDRM->start(true); addToLog("txFunc: TXSENDDRMFIX waiting for end",LOGTXFUNC); if(txState==TXSENDDRMFIX) // abort if txState is idle { waterfallPtr->setText(endPicWF); synthesPtr->sendWFText(); addToLog("end of wf",LOGTXFUNC); addToLog("txFunc: TXSENDDRM waiting for end",LOGTXFUNC); waitEnd(); } txState=TXIDLE; break; case TXSENDDRMTXT: waitTxOn(); break; case TXSENDID: waitTxOn(); addToLog("txFunc: entered TXSENDID",LOGTXFUNC); ce=new progressTXEvent(waterfallPtr->getDuration(NULL)); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done synthesPtr->sendWFText(); addToLog("txFunc: TXSENDID waiting for end",LOGTXFUNC); waitEnd(); txState=TXIDLE; break; case TXFAXSTART: waitTxOn(); addToLog("txFunc: TXFAXSTART",LOGTXFUNC); // initSSTVImage(); faxStart(); addToLog("txFunc: TXFAXSTART waiting for end",LOGTXFUNC); waitEnd(); txState=TXIDLE; break; case TXSSTVIMAGE: waitTxOn(); addToLog("txFunc: entered TXIMAGE",LOGTXFUNC); // initSSTVImage(); ce=new progressTXEvent(calcTxTime(false,0)); QApplication::postEvent( dispatcherPtr, ce ); // Qt will delete it when done if(txSSTVParam.mode==FAX480) { for (int i=0;i<1220;i++) { synthesPtr->sendTone(0.00205,1500,0,true); synthesPtr->sendTone(0.00205,2300,0,true); } } else { sendPreamble(); sendVIS(); } addToLog("txFunc: sendImage",LOGTXFUNC); sendImage(); addToLog("txFunc: endImage",LOGTXFUNC); txState=TXSSTVPOST; break; case TXSSTVPOST: addToLog("txFunc: TXSSTVPOST ",LOGTXFUNC); if (useCW) { sendCW(); } else { sendFSKID(); } waitEnd(); txState=TXIDLE; break; case TXTEST: sendTestPattern(); break; } } started=false; addToLog("txFunc stopped",LOGTXFUNC); abort=false; } void txFunctions::init() { txState=TXIDLE; addToLog("txFunc: Init",LOGTXFUNC); sampleCounter=0; } void txFunctions::waitTxOn() { double txDelay; txDelay=rigController->getTxDelay(); if(txDelay!=0) { synthesPtr->sendSilence(txDelay); } } void txFunctions::stopAndWait() { stopDRM=true; if(!isRunning()) return; if(currentMode) currentMode->abort(); addToLog("txFunc: stop initiated",LOGTXFUNC); logStatus(); txState=TXIDLE; while(txState!=TXIDLE) { if(!isRunning()) return; qApp->processEvents(); } addToLog("txFunc: stop executed",LOGTXFUNC); stopTXEvent *ce = new stopTXEvent(); QApplication::postEvent(dispatcherPtr, ce); } bool txFunctions::create(esstvMode m,DSPFLOAT clock) { if(oldMode==m) { currentMode->init(clock); return true; } oldMode=m; if(currentMode) delete currentMode; currentMode=0; switch (m) { case M1: case M2: currentMode=new modeGBR(m,TXSTRIPE,true); break; case S1: case S2: case SDX: currentMode=new modeGBR2(m,TXSTRIPE,true); break; case R36: currentMode=new modeRobot1(m,TXSTRIPE,true); break; case R24: case R72: currentMode=new modeRobot2(m,TXSTRIPE,true); break; case SC2_60: case SC2_120: case SC2_180: case P3: case P5: case P7: currentMode=new modeRGB(m,TXSTRIPE,true); break; case FAX480: case BW8: case BW12: currentMode=new modeBW(m,TXSTRIPE,true); break; case AVT24: case AVT90: case AVT94: currentMode=new modeAVT(m,TXSTRIPE,true); break; case PD50: case PD90: case PD120: case PD160: case PD180: case PD240: case PD290: case MP73: case MP115: case MP140: case MP175: currentMode=new modePD(m,TXSTRIPE,true); break; default: m=NOTVALID; break; } if (m!=NOTVALID) { initializeSSTVParametersIndex(m,true); QString s=getSSTVModeNameLong(m); addToLog("create: create TX mode",LOGTXFUNC); assert(currentMode); currentMode->init(clock); return true; } return false; } void txFunctions::sendTestPattern() { if(patternNumber==TPBURST) syncBurst(); } /** send a burst of syncs */ /* void txFunctions::syncBurst() { // we will send 5msec 1200Hz followed by 50 msec silence // synthesPtr->sendTone(0.005,1200.); for (int i=300;i<3000;i++) { synthesPtr->sendTone(0.005,(double) i); } synthesPtr->sendSilence(0.100);; } */ /** send a burst of syncs */ void txFunctions::syncBurst() { // send 5msec 1200Hz followed by 50 msec silence // synthesPtr->sendTone(0.005,1200.); for (int i=0;i<50;i++) { synthesPtr->sendTone(0.005,1200,0,true); synthesPtr->sendTone(0.020,1700,0,true); } synthesPtr->sendSilence(0.100);; } void txFunctions::faxStart() { // send 300Hz modulated 1500Hz/2300Hz tone // synthesPtr->sendTone(0.005,1200.); for (int i=0;i<100;i++) { synthesPtr->sendTone(0.0333,1500,0,true); synthesPtr->sendTone(0.0333,2300,0,true); } synthesPtr->sendSilence(0.100); } void txFunctions::startTestPattern(uint tpnum) { patternNumber=tpnum; txState=TXTEST; } //void txFunctions:: initSSTVImage() //{ // create(modeIndexTx,txClock); //} void txFunctions:: sendPreamble() { addToLog("txFunc:sendPreamble",LOGTXFUNC); if(useVOX) synthesPtr->sendTone(1.,1700.,0,false); synthesPtr->sendTone(0.1,1900.,0,true); synthesPtr->sendTone(0.1,1500.,0,true); synthesPtr->sendTone(0.1,1900.,0,true); synthesPtr->sendTone(0.1,1500.,0,true); synthesPtr->sendTone(0.1,2300.,0,true); synthesPtr->sendTone(0.1,1500.,0,true); synthesPtr->sendTone(0.1,2300.,0,true); synthesPtr->sendTone(0.1,1500.,0,true); synthesPtr->sendTone(0.3,1900.,0,true); synthesPtr->sendTone(0.01,1200.,0,true); synthesPtr->sendTone(0.3,1900.,0,true); } void txFunctions:: sendVIS() { int i,l; int t=txSSTVParam.VISCode; addToLog("txFunc:sendVis",LOGTXFUNC); if ((t&0xFF)==0x23) l=16; else l=8; synthesPtr->sendTone(0.030,1200,0,false); // startbit for (i=0;isendTone(0.030,1100,0,true); else synthesPtr->sendTone(0.030,1300,0,true); t>>=1; } synthesPtr->sendTone(0.030,1200,0,true); // stopbit } void txFunctions::sendCW() { addToLog("txFunc:sendCW",LOGTXFUNC); float tone; float duration; initCW(cwText); synthesPtr->sendSilence(0.5); while(sendTextCW(tone,duration)) { synthesPtr->sendTone(duration,tone,0,true); } } void txFunctions::waitEnd() { synthesPtr->sendTone(SILENCEDELAY,00,0,false); // send silence addToLog("waitEnd() posting endTXImage",LOGTXFUNC); endImageTXEvent *ce=new endImageTXEvent; QApplication::postEvent(dispatcherPtr, ce ); // Qt will delete it when done } double txFunctions::calcTxTime(bool isDRM,int overheadTime) { double tim=0; float tone; float duration; tim= soundIOPtr->getPlaybackStartupTime(); tim+=SILENCEDELAY; if(!isDRM) { initializeSSTVParametersIndex(modeIndexTx,true); int t=txSSTVParam.VISCode; initCW(cwText); tim+=1.41; //preamble; if ((t&0xFF)==0x23) tim+=18.*0.03; else tim+=10.*0.03; tim+=txSSTVParam.imageTime; tim+=0.5 ;//CW silence gap if(useCW) { while(sendTextCW(tone,duration)) { tim+=duration; } } tim+=0.3; // trailer; } else { tim+=overheadTime; tim+=txDRM->getDuration(); } addToLog(QString("txFunc: calcTimeTx %1").arg(tim),LOGTXFUNC); return tim; } void txFunctions::sendImage() { addToLog("txFunc: sendImage",LOGTXFUNC); currentMode->transmitImage(txWidgetPtr->getImageViewerPtr()); } void txFunctions::initDRMImage() { eRSType rsType; reedSolomonCoder rsd; QString fn; QString ext; QFileInfo finf; hybridCrypt hc; // we need to save it as a jpg file if(!useHybrid) { finf.setFile(txWidgetPtr->getImageViewerPtr()->getFilename()); fn=QDateTime::currentDateTime().toUTC().toString("yyyyMMddHHmmss"); fn+="-"+finf.baseName(); ext=finf.suffix(); } else { finf.setFile(hybridFilename); fn= finf.baseName(); ext=finf.suffix(); } fixBlockList.clear(); if(txList.count()>5) txList.removeFirst(); txList.append(txSession()); txList.last().filename=fn; txList.last().extension=ext; if(!useHybrid) { txList.last().drmParams=drmTxParameters; txWidgetPtr->getImageViewerPtr()->copyToBuffer(&(txList.last().ba)); rsType=(eRSType)txList.last().drmParams.reedSolomon; baDRM=txList.last().ba; if(rsType!=RSTNONE) { rsd.encode(baDRM,txList.last().extension,rsType); txDRM->init(&baDRM,txList.last().filename,rsTypeStr[rsType],txList.last().drmParams); } else { txDRM->init(&baDRM,txList.last().filename,txList.last().extension,txList.last().drmParams); } } else { txList.last().drmParams.bandwith=1; // bw 2.2 txList.last().drmParams.robMode=2; // mode E txList.last().drmParams.interleaver=0; // long txList.last().drmParams.protection=0; // high txList.last().drmParams.qam=0; // 4bit QAM txList.last().drmParams.callsign=myCallsign; // we have to fill in the body txList.last().ba.clear(); hc.enCrypt(&txList.last().ba); txDRM->init(&txList.last().ba,txList.last().filename,txList.last().extension,txList.last().drmParams); } // transportID is set txList.last().transportID=txTransportID; } void txFunctions::initDRMBSR(QByteArray *ba) { baDRM=*ba; fixBlockList.clear(); txDRM->init(&baDRM,"bsr","bin",drmTxParameters); addToLog(QString("bsr.bin send %1").arg(baDRM.size()),LOGPERFORM); } bool txFunctions::initDRMFIX(QString fileName,QString extension,eRSType rsType,int mode) { reedSolomonCoder rsd; QFile fi(fileName); if(fi.open(QIODevice::ReadOnly)<=0) return false; baDRM=fi.readAll(); if(rsType!=RSTNONE) { rsd.encode(baDRM,extension,rsType); txDRM->init(&baDRM,fileName,rsTypeStr[rsType],modeToParams(mode)); } else { txDRM->init(&baDRM,fileName,extension,modeToParams(mode)); } return true; } bool txFunctions::initDRMFIX(txSession *sessionPtr) { reedSolomonCoder rsd; eRSType rsType; rsType=(eRSType)sessionPtr->drmParams.reedSolomon; baDRM=sessionPtr->ba; if(rsType!=RSTNONE) { rsd.encode(baDRM,sessionPtr->extension,rsType); txDRM->init(&baDRM,sessionPtr->filename,rsTypeStr[rsType],sessionPtr->drmParams); } else { txDRM->init(&baDRM,sessionPtr->filename,sessionPtr->extension,sessionPtr->drmParams); } return true; } void txFunctions::sendDRMFIX() { // QByteArray ba; // QFile fi(rxImagesPath+"/bsr.bin"); // if(fi.open(QIODevice::ReadOnly)<=0) return; // ba=fi.readAll(); // txDRM->init(&ba,"bsr","bin",drmTxParameters); // addToLog(QString("bsr.bin send").arg(ba.size()),LOGPERFORM); // txDRM->start(); } void txFunctions::logStatus() { QString stat,statr; if(isRunning()) statr="true"; else statr="false"; addToLog(QString("TX Is running %1").arg(statr),LOGDISPAT); stat="TX state: "; switch (txState) { case TXIDLE: stat+="IDLE"; break; case TXACTIVE: stat+="ACTIVE"; break; case TXSENDTONE: stat+="SENDTONE"; break; case TXSENDID: stat+="SENDID"; break; case TXSENDDRM: stat+="SENDDRM"; break; case TXSENDDRMBSR: stat+="SENDDRMBSR"; break; case TXSENDDRMFIX: stat+="SENDDRMFIX"; break; case TXSENDDRMTXT: stat+="SENDDRMTXT"; break; case TXSSTVIMAGE: stat+="SSTVIMAGE"; break; case TXSSTVPOST: stat+="SSTVPOST"; break; case TXFAXSTART: stat+="FAXSTART"; break; case TXTEST: stat+="TEST"; break; } addToLog(stat,LOGTXFUNC); } txSession *txFunctions::getSessionPtr(uint transportID) { int i; for(i=0;i> 1; if (TxBit == 0x01) synthesPtr->sendTone(0.022,1900.,0,true); else synthesPtr->sendTone(0.022,2100.,0,true); } } // sendFSKID by DL3YAP void txFunctions:: sendFSKID() { int idx; int l; int IDChar; int Checksum; if (myCallsign.isEmpty()) return; // addToLog("txFunc:sendFSKID",LOGFSKID); QTextStream out(stdout); l=myCallsign.size(); idx=0; Checksum=0; // synthesPtr->sendTone(2.0,00,0,false); synthesPtr->sendTone(0.3,1500.,0,false); synthesPtr->sendTone(0.1,2100.,0,true); synthesPtr->sendTone(0.022,1900.,0,true); IDChar = 0x2A; sendFSKChar(IDChar); QChar IDText= QChar(myCallsign[idx]); IDChar=int(IDText.toLatin1()); IDChar = (IDChar - 0x20); Checksum = IDChar; while (idx < l) { sendFSKChar(IDChar); idx++; QChar IDText=QChar(myCallsign[idx]); IDChar=int(IDText.toLatin1()); IDChar = (IDChar - 0x20); if (idx < l) { Checksum = Checksum ^ IDChar; } } IDChar = 0x01; sendFSKChar(IDChar); IDChar = Checksum & 0x3F ; sendFSKChar(IDChar); // synthesPtr->sendTone(0.022,2100.,0,true); synthesPtr->sendTone(0.1,1900.,0,true); } qsstv_8.2.12/qsstv/txfunctions.h000664 001750 001750 00000010503 12440612574 016707 0ustar00jomajoma000000 000000 /*************************************************************************** * Copyright (C) 2000-2008 by Johan Maes * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef TXFUNC_H #define TXFUNC_H #include #include "dsp/filterparam.h" #include "sstv/sstvparam.h" #include "sstv/modes/modebase.h" #include "drmtx/drmtransmitter.h" #include "utils/reedsolomoncoder.h" class imageCoder; #define TPBURST 0 extern esstvMode modeIndexTx; extern int templateIndex; extern bool useTemplate; extern bool useCW; extern bool useVOX; class drmTransmitter; struct txSession { drmTxParams drmParams; QByteArray ba; // contains the image data in jpg, jp2 .... format uint transportID; QString filename; QString extension; }; class txFunctions: public QThread { public: enum etxState { TXIDLE, //!< in idle loop TXACTIVE, TXSENDTONE, TXSENDID, TXSENDDRM, TXSENDDRMBSR, TXSENDDRMFIX, TXSENDDRMTXT, TXSSTVIMAGE, TXSSTVPOST, TXFAXSTART, TXTEST }; public: txFunctions(); ~txFunctions(); bool create(esstvMode m,DSPFLOAT clock); modeBase *currentMode; void run(); void stopAndWait(); bool hasStarted() {return started;} void setTXState(etxState d) { txState=d;} etxState getTXState() { return txState;} void syncBurst(); void faxStart(); void setDRMTxParams(drmTxParams params) { drmTxParameters=params; } txSession *getSessionPtr(uint transportID); void enableNoise(bool en,double level=0.) { if (level==0) { noiseEnabled=en; } } void setFilter(efilterType filterType); void startTestPattern(uint tpnum); // void setCall(const QString &str); // void setToOperator(const QString &str); // void setRSV(const QString &str); void setToneParam(double duration,double lowerFreq,double upperFreq=0) { toneDuration=duration; toneLowerFrequency=lowerFreq; toneUpperFrequency=upperFreq; } double calcTxTime(bool isDRM, int overheadTime); void logStatus(); void initDRMBSR(QByteArray *ba); bool initDRMFIX(QString fileName, QString extension, eRSType rsType, int mode); bool initDRMFIX(txSession *sessionPtr); void setHybrid(bool h,QString hbfn=QString::Null()) { useHybrid=h; hybridFilename=hbfn; } private: bool abort; void init(); unsigned long sampleCounter; bool noiseEnabled; short int filter(double sample); void write(double sample); etxState txState; uint patternNumber; void sendTestPattern(); void sendPreamble(); void sendVIS(); void sendImage(); void initDRMImage(); void sendDRMFIX(); void sendCW(); void sendFSKChar(int IDChar); void sendFSKID(); void waitTxOn(); // void initSSTVImage(); void waitEnd(); double toneDuration; double toneLowerFrequency; double toneUpperFrequency; esstvMode oldMode; bool started; drmTransmitter *txDRM; drmTxParams drmTxParameters; QByteArray baDRM; double waterfallTime; QList txList; bool useHybrid; QString hybridFilename; }; #endif qsstv_8.2.12/qsstv/txwidget.cpp000664 001750 001750 00000047336 12440612574 016533 0ustar00jomajoma000000 000000 #include "txwidget.h" #include #include "ui_txwidget.h" #include #include "configparams.h" #include "dispatcher.h" #include "utils/supportfunctions.h" #include "gallerywidget.h" #include "ui_freqform.h" #include "ui_sweepform.h" #include "widgets/cameracontrol.h" #include "videocapt/videocapture.h" #include "sound/soundio.h" #include "widgets/waterfallform.h" #include "drmtx/bsrform.h" #include "drmrx/fixform.h" #include "mainwindow.h" txWidget *txWidgetPtr; txWidget::txWidget(QWidget *parent) : QWidget(parent), ui(new Ui::txWidget) { int i; QString tmp; ui->setupUi(this); txFunctionsPtr=new txFunctions(); imageViewerPtr=ui->imageFrame; imageViewerPtr->createImage(QSize(320,256),QColor(0,0,128)); imageViewerPtr->displayImage(false); readSettings(); setProfileNames(); for(i=0;isstvModeComboBox->addItem(getSSTVModeNameLong((esstvMode)i)); } connect(ui->sstvModeComboBox,SIGNAL(activated(int)),SLOT(slotModeChanged(int ))); connect(ui->templatesComboBox,SIGNAL(currentIndexChanged(int)),SLOT(slotGetParams())); connect(ui->templateCheckBox,SIGNAL(toggled(bool)),SLOT(slotGetParams())); connect(ui->cwCheckBox,SIGNAL(toggled(bool)),SLOT(slotGetParams())); connect(ui->voxCheckBox,SIGNAL(toggled(bool)),SLOT(slotGetParams())); connect(ui->toCallLineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->operatorLineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->rsvLineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->comment1LineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->comment2LineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->comment3LineEdit,SIGNAL(editingFinished ()),SLOT(slotGetParams())); connect(ui->startToolButton, SIGNAL(clicked()), this, SLOT(slotStart())); // connect(ui->hybridCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotHybridStart(bool))); connect(ui->stopToolButton, SIGNAL(clicked()), this, SLOT(slotStop())); connect(ui->drmProfileComboBox,SIGNAL(activated(int)),SLOT(slotProfileChanged(int ))); connect(ui->generateToneToolButton, SIGNAL(clicked()), this, SLOT(slotGenerateSignal())); connect(ui->sweepToneToolButton, SIGNAL(clicked()), this, SLOT(slotSweepSignal())); connect(ui->repeaterToneToolButton, SIGNAL(clicked()), this, SLOT(slotGenerateRepeaterTone())); connect(ui->openToolButton, SIGNAL(clicked()), this, SLOT(slotFileOpen())); // connect(ui->actionAlignement, SIGNAL(triggered()), this, SLOT(slotAlignementSignal())); connect(ui->editToolButton, SIGNAL(clicked()), this, SLOT(slotEdit())); // connect(ui->actionReplay, SIGNAL(triggered()), this, SLOT(slotReplay())); connect(ui->snapshotToolButton, SIGNAL(clicked()), this, SLOT(slotSnapshot())); connect(imageViewerPtr, SIGNAL(imageChanged()), this, SLOT(slotGetParams())); connect(ui->sizeSlider,SIGNAL(valueChanged(int)),SLOT(slotSize(int))); connect(ui->sizeSlider,SIGNAL(sliderReleased()),SLOT(slotSizeApply())); connect(ui->settingsTableWidget,SIGNAL(currentChanged(int)),this, SLOT(slotTransmissionMode(int))); connect(ui->imageFrame,SIGNAL(imageChanged()),SLOT(slotImageChanged())); currentTXMode=NOMODE; } txWidget::~txWidget() { delete ui; } void txWidget::init() { splashStr+=QString( "Setting up TX" ).rightJustified(25,' ')+"\n"; splashPtr->showMessage ( splashStr ,Qt::AlignLeft,Qt::white); qApp->processEvents(); ed=NULL; repeaterIndex=0; initView(); repeaterTimer=new QTimer(this); connect(repeaterTimer,SIGNAL(timeout()),SLOT(slotRepeaterTimer())); repeaterTimer->start(60000*repeaterImageInterval); imageViewerPtr->setType(imageViewer::TXIMG); slotModeChanged(modeIndexTx); slotSize(sizeRatio); txFunctionsPtr->start(); } void txWidget::readSettings() { QSettings qSettings; qSettings.beginGroup("TX"); modeIndexTx=((esstvMode)qSettings.value("modeIndexTx",0).toInt()); templateIndex=qSettings.value("templateIndex",0).toInt(); useTemplate=qSettings.value("useTemplate",false).toBool(); useCW=qSettings.value("useCW",false).toBool(); useVOX=qSettings.value("useVOX",false).toBool(); useHybrid=qSettings.value("useHybrid",false).toBool(); sizeRatio=qSettings.value("sizeRatio",25).toInt(); drmParams.bandwith=qSettings.value("drmBandWith",0).toInt(); drmParams.interleaver=qSettings.value("drmInterLeaver",0).toInt(); drmParams.protection=qSettings.value("drmProtection",0).toInt(); drmParams.qam=qSettings.value("drmQAM",0).toInt(); drmParams.robMode=qSettings.value("drmRobMode",0).toInt(); drmParams.reedSolomon=qSettings.value("drmReedSolomon",0).toInt(); qSettings.endGroup(); setParams(); } void txWidget::writeSettings() { QSettings qSettings; slotGetParams(); qSettings.beginGroup("TX"); qSettings.setValue( "modeIndexTx", modeIndexTx); qSettings.setValue( "templateIndex", templateIndex); qSettings.setValue( "useTemplate", useTemplate); qSettings.setValue( "useVOX", useVOX); qSettings.setValue( "useCW", useCW); qSettings.setValue( "useHybrid", useHybrid); qSettings.setValue("drmBandWith",drmParams.bandwith); qSettings.setValue("drmInterLeaver",drmParams.interleaver); qSettings.setValue("drmProtection",drmParams.protection); qSettings.setValue("drmQAM",drmParams.qam); qSettings.setValue("drmRobMode",drmParams.robMode); qSettings.setValue("drmReedSolomon",drmParams.reedSolomon); qSettings.setValue("sizeRatio",sizeRatio); qSettings.endGroup(); } void txWidget::slotGetParams() { int temp=modeIndexTx; getIndex(temp,ui->sstvModeComboBox); modeIndexTx=esstvMode(temp); getIndex(templateIndex,ui->templatesComboBox); getValue(useTemplate,ui->templateCheckBox); getValue(useVOX,ui->voxCheckBox); getValue(useCW,ui->cwCheckBox); getValue(useHybrid,ui->hybridCheckBox); getValue(imageViewerPtr->toCall,ui->toCallLineEdit); getValue(imageViewerPtr->toOperator,ui->operatorLineEdit); getValue(imageViewerPtr->rsv,ui->rsvLineEdit); getValue(imageViewerPtr->comment1,ui->comment1LineEdit); getValue(imageViewerPtr->comment2,ui->comment2LineEdit); getValue(imageViewerPtr->comment3,ui->comment3LineEdit); getIndex(drmParams.bandwith,ui->drmTxBandwidthComboBox); getIndex(drmParams.interleaver,ui->drmTxInterleaveComboBox); getIndex(drmParams.protection,ui->drmTxProtectionComboBox); getIndex(drmParams.qam,ui->drmTxQAMComboBox); getIndex(drmParams.robMode,ui->drmTxModeComboBox); getIndex(drmParams.reedSolomon,ui->drmTxReedSolomonComboBox); getValue(sizeRatio,ui->sizeSlider); drmParams.callsign=myCallsign; // if(!txFunctionsPtr->isRunning()) if(txFunctionsPtr->getTXState()==txFunctions::TXIDLE) { applyTemplate(); } } void txWidget::setParams() { setIndex(((int)modeIndexTx),ui->sstvModeComboBox); setIndex(templateIndex,ui->templatesComboBox); setValue(useTemplate,ui->templateCheckBox); setValue(useVOX,ui->voxCheckBox); setValue(useCW,ui->cwCheckBox); setValue(useHybrid,ui->hybridCheckBox); setIndex(drmParams.bandwith,ui->drmTxBandwidthComboBox); setIndex(drmParams.interleaver,ui->drmTxInterleaveComboBox); setIndex(drmParams.protection,ui->drmTxProtectionComboBox); setIndex(drmParams.qam,ui->drmTxQAMComboBox); setIndex(drmParams.robMode,ui->drmTxModeComboBox); setIndex(drmParams.reedSolomon,ui->drmTxReedSolomonComboBox); setValue(sizeRatio,ui->sizeSlider); } void txWidget::copyProfile(drmTxParams d) { drmParams=d; setIndex(drmParams.bandwith,ui->drmTxBandwidthComboBox); setIndex(drmParams.interleaver,ui->drmTxInterleaveComboBox); setIndex(drmParams.protection,ui->drmTxProtectionComboBox); setIndex(drmParams.qam,ui->drmTxQAMComboBox); setIndex(drmParams.robMode,ui->drmTxModeComboBox); setIndex(drmParams.reedSolomon,ui->drmTxReedSolomonComboBox); } void txWidget::initView() { ui->sstvModeComboBox->setCurrentIndex((int)modeIndexTx); setupTemplatesComboBox(); ui->progressBar->setRange(0,100); } void txWidget::setupTemplatesComboBox() { QStringList sl; int i; ui->templatesComboBox->clear(); sl=galleryWidgetPtr->getFilenames(); for(i=0;itemplatesComboBox->insertItem(i,sl.at(i)); } ui->templatesComboBox->setCurrentIndex(templateIndex); } void txWidget::setPreviewWidget(QString fn) { ui->previewWidget->openImage(fn,false,false); } void txWidget::start(bool st,bool check) { if(st) { slotGetParams(); if(check) { if(!imageViewerPtr->hasValidImage()) { QMessageBox::warning(this,"TX Error","No image loaded"); return; } } soundIOPtr->startPlayback(); } else { writeSettings(); txFunctionsPtr->stopAndWait(); } } void txWidget::slotStart() { // start(true); QFileInfo finf; QString fn; slotGetParams(); switch(currentTXMode) { case SSTV: dispatcherPtr->startSSTVTx(); break; case DRM: txFunctionsPtr->setDRMTxParams(drmParams); if(ui->hybridCheckBox->isChecked()) { finf.setFile(txWidgetPtr->getImageViewerPtr()->getFilename()); fn="de_"+myCallsign+"-1-"+finf.baseName()+"."+finf.suffix(); txFunctionsPtr->setHybrid(true,fn); dispatcherPtr->startDRMHybridTx(fn); } else { txFunctionsPtr->setHybrid(false); dispatcherPtr->startDRMTx(); } break; // case FAX: // break; case NOMODE: break; } } void txWidget::sendBSR() { QByteArray *p; bsrForm::eResult res; bsrForm bsrf; bsrf.init(); res=(bsrForm::eResult)bsrf.exec(); if(res==bsrForm::CANCEL) return; p=bsrf.getBA(res==bsrForm::COMPAT); drmParams=bsrf.getDRMParams(); txFunctionsPtr->setDRMTxParams(drmParams); dispatcherPtr->startDRMBSRTx(p); } void txWidget::sendID() { dispatcherPtr->sendWF(myCallsign); } void txWidget::sendWfText() { waterfallForm wf; if((wf.exec()==QDialog::Accepted)&&(!wf.text().isEmpty())) { dispatcherPtr->sendWF(wf.text()); } } void txWidget::slotStop() { // qDebug() << "slotStop tx"; soundIOPtr->abortPlayback(); start(false); dispatcherPtr->restartRX(); } void txWidget::slotDisplayStatusMessage(QString s) { statusBarPtr->showMessage(s); } //void txWidget::slotReplay() //{ // QString fn; // QImage *im=NULL; // fn=galleryWidgetPtr->getLastRxImage(); // editorScene scene(0); // QFile f(fn); // if(!scene.load(f)) // { // QMessageBox::warning(this,"Image Properties","Error while loading\n" + fn); // return; // } // im=scene.renderImage(); // dispatcherPtr->setTXImage(im); // slotStartTX(); //} void txWidget::slotFileOpen() { QString fileName; imageViewerPtr->openImage(fileName,txImagesPath,true,true,true); } void txWidget::slotGenerateSignal() { QDialog qd; Ui::freqForm *ff=new Ui::freqForm; ff->setupUi(&qd); int freq; int duration; if(qd.exec()) { getValue(freq,ff->frequencySpinBox); getValue(duration,ff->durationSpinBox); dispatcherPtr->sendTone((double)duration,(double)freq); } } void txWidget::slotSweepSignal() { QDialog qd; Ui::sweepForm *ff=new Ui::sweepForm; ff->setupUi(&qd); int upperFreq; int lowerFreq; int duration; if(qd.exec()) { getValue(lowerFreq,ff->lowerFrequencySpinBox); getValue(upperFreq,ff->upperFrequencySpinBox); getValue(duration,ff->durationSpinBox); dispatcherPtr->sendSweepTone((double)duration,(double)lowerFreq,(double)upperFreq); } } void txWidget::slotGenerateRepeaterTone() { addToLog(QString("start of buffer %1").arg(soundIOPtr->txBuffer.count()),LOGTXMAIN); dispatcherPtr->sendTone(3.,1750); } void txWidget::slotEdit() { if (ed!=NULL) delete ed; ed=new editor(this); if(txFunctionsPtr->isRunning()) { QMessageBox::warning(this,"Editor","Transmission busy, editor not available"); return; } connect(ed,SIGNAL(imageAvailable(QImage *)),SLOT(setImage(QImage *))); ed->setImage(imageViewerPtr->getImagePtr()); ed->show(); } void txWidget::slotModeChanged(int m) { addToLog("slotModeChange",LOGTXMAIN); modeIndexTx=(esstvMode)m; // txFunctionsPtr->create(modeIndexTx,txClock/SUBSAMPLINGRATIO); applyTemplate(); } /** \todo implement repeater */ void txWidget::applyTemplate() { if(currentTXMode!=DRM) { txFunctionsPtr->create(modeIndexTx,txClock/SUBSAMPLINGRATIO); imageViewerPtr->applyTemplate(galleryWidgetPtr->getTemplateFileName(ui->templatesComboBox->currentIndex()),useTemplate, txSSTVParam.numberOfPixels,txSSTVParam.numberOfDisplayLines); } else { slotSize(sizeRatio); imageViewerPtr->applyTemplate(galleryWidgetPtr->getTemplateFileName(ui->templatesComboBox->currentIndex()),useTemplate); } } void txWidget::setImage(QImage *im) { if(imageViewerPtr->openImage(*im)) { applyTemplate(); } } void txWidget::setImage(QString fn) { imageViewerPtr->openImage(fn,true,true); } void txWidget::setProgress(uint prg) { ui->progressBar->setValue(prg); } /** \todo implement repeater */ // void txWidget::repeat(QImage *im,esstvMode sm) void txWidget::repeat(QImage *,esstvMode ) { /* setValue((int)sm,ui->modeComboBox); txf->setModeIndex((sstvMode)sm); // slotModeChanged(sm); txf->setImage(im); dsp->setCaptureSource(true,NULL,false); txf->process();*/ } void txWidget::slotRepeaterTimer() { QString fn; QFile fi; if(txFunctionsPtr->isRunning()) repeaterTimer->start(60000*repeaterImageInterval); else if ((rxWidgetPtr->functionsPtr()->isRunning()) || (!repeaterEnable)) { // wait 10 seconds and check if busy or repeaterEnable has changed repeaterTimer->start(10000); } else { switch(repeaterIndex) { case 0: fn=repeaterImage1; break; case 1: fn=repeaterImage2; break; case 2: fn=repeaterImage3; break; case 3: fn=repeaterImage4; break; default: fn=repeaterImage1; break; } fi.setFileName(fn); if (fi.exists()) { slotModeChanged(repeaterTxMode); setImage(fn); } repeaterIndex++; if(repeaterIndex>3) repeaterIndex=0; repeaterTimer->start(60000*repeaterImageInterval); //QApplication::processEvents(); startAutoRepeaterEvent* ce = new startAutoRepeaterEvent(); QApplication::postEvent(dispatcherPtr, ce ); } } void txWidget::slotSnapshot() { cameraControl cc(this); if(cc.exec()) { setImage(cc.getImage()); } } //void txWidget::test() //{ //} void txWidget::setSettingsTab() { int i; currentTXMode=transmissionModeIndex; { if(currentTXMode==DRM) { ui->hybridCheckBox->setEnabled(true); } else { ui->hybridCheckBox->setEnabled(false); } } if((transmissionModeIndex>=0)&&(transmissionModeIndexsettingsTableWidget->widget(i)->setEnabled(false); } ui->settingsTableWidget->widget(transmissionModeIndex)->setEnabled(true); ui->settingsTableWidget->setCurrentIndex(transmissionModeIndex); } applyTemplate(); } bool txWidget::prepareFIX(QByteArray bsrByteArray) { int i,j; displayMBoxEvent *stce; // unsigned int mode=0; // eRSType rsType; bool inSeries; QString fileName,extension; txSession *sessionPtr; bool extended,done; int block; unsigned short trID,lastBlock; fixBlockList.clear(); txFunctionsPtr->setHybrid(true); QString str(bsrByteArray); str.replace("\r",""); // information is in the QByteArray ba QStringList sl; sl=str.split("\n",QString::SkipEmptyParts); if(sl.at(1)!="H_OK") { return false; } trID=sl.at(0).toUInt(); lastBlock=sl.at(3).toUInt(); fixBlockList.append(lastBlock++); inSeries=false; done=false; extended=false; for(i=4;(!done)&&igetSessionPtr(trID); if ((sessionPtr==NULL) && (!extended)) { stce= new displayMBoxEvent("BSR Received","This BSR is not for you"); QApplication::postEvent( dispatcherPtr, stce ); // Qt will delete it when done return false; } else if (sessionPtr!=NULL) { // take it from the transmitlist fx.setInfoInternal(paramsToMode(sessionPtr->drmParams),sessionPtr->filename,fixBlockList.count(),&sessionPtr->ba); if(fx.exec()==QDialog::Rejected) return false; txFunctionsPtr->initDRMFIX(sessionPtr); } else { QMessageBox *mbox = new QMessageBox(this); mbox->setWindowTitle(tr("BSR Received")); mbox->setText("This BSR is not for you"); mbox->show(); QTimer::singleShot(4000, mbox, SLOT(hide())); return false; } return true; } //bool txWidget::prepareHybrid(QString fn) //{ // txFunctionsPtr->setHybrid(true); // return true; //} bool txWidget::prepareText(QString ) { txFunctionsPtr->setHybrid(false); // QString fn; // QDateTime dt(QDateTime::currentDateTime().toUTC()); //this is compatible with QT 4.6 // dt.setTimeSpec(Qt::UTC); // dt // int intdate=dt.date().year()*10000+dt.date().month()*100+dt.date().day(); // int inttime=dt.time().hour()*10000+100*dt.time().minute()+dt.time().second(); // s.sprintf("%s_%d_%d",rxWidgetPtr->functionsPtr()->getModeString().toLatin1().data(),intdate,inttime); // fileName=rxImagesPath+"/"+s+"."+defaultImageFormat; // QFile fo("de ON4QZ") return true; } void txWidget::slotSize(int v) { QString t; if(sizeRatio!=v) { sizeRatioChanged=true; sizeRatio=v; ui->sizeKbLabel->setText( QString::number(imageViewerPtr->calcSize(v))+ "kB"); } } void txWidget::slotSizeApply() { QApplication::setOverrideCursor(Qt::WaitCursor); sizeRatioChanged=false; imageViewerPtr->setSizeRatio(sizeRatio); imageViewerPtr->displayImage(currentTXMode==DRM); QApplication::restoreOverrideCursor(); } void txWidget::slotTransmissionMode(int rxtxMode) { transmissionModeIndex=(etransmissionMode)rxtxMode; start(false); rxWidgetPtr->setSettingsTab(); setSettingsTab(); if(transmissionModeIndex==DRM) { ui->sizeLabel->setEnabled(true); ui->sizeSlider->setEnabled(true); ui->sizeKbLabel->setEnabled(true); // ui->sizeApplyPushButton->setEnabled(true); mainWindowPtr->setBSRPushButton(true); } else { ui->sizeLabel->setEnabled(false); ui->sizeSlider->setEnabled(false); ui->sizeKbLabel->setEnabled(false); // ui->sizeApplyPushButton->setEnabled(false); mainWindowPtr->setBSRPushButton(false); } } void txWidget::slotProfileChanged(int i) { drmProfilePtr->getDRMParams(i,drmParams); setParams(); } void txWidget::setProfileNames() { QString tmp; ui->drmProfileComboBox->clear(); if(drmProfilePtr->getName(0,tmp)) { ui->drmProfileComboBox->addItem(tmp); } if(drmProfilePtr->getName(1,tmp)) { ui->drmProfileComboBox->addItem(tmp); } if(drmProfilePtr->getName(2,tmp)) { ui->drmProfileComboBox->addItem(tmp); } } void txWidget::slotImageChanged() { int sz=sizeRatio; sizeRatio=0; slotSize(sz); slotSizeApply(); } qsstv_8.2.12/qsstv/txwidget.h000664 001750 001750 00000004033 12440612574 016163 0ustar00jomajoma000000 000000 #ifndef TXWIDGET_H #define TXWIDGET_H #include #include "widgets/imageviewer.h" #include "sstv/sstvparam.h" #include "txfunctions.h" #include "drmtx/drmtransmitter.h" class drmTransmitter; namespace Ui { class txWidget; } class txWidget : public QWidget { Q_OBJECT public: explicit txWidget(QWidget *parent = 0); ~txWidget(); void init(); void start(bool st, bool check=true); void writeSettings(); void readSettings(); imageViewer *getImagePtr(); void repeat(QImage *im,esstvMode sm); void setImage(QImage *ima); void setImage(QString fn); void setProgress(uint prg); void setupTemplatesComboBox(); void setPreviewWidget(QString fn); void setSettingsTab(); txFunctions *functionsPtr() {return txFunctionsPtr;} imageViewer *getImageViewerPtr(){ return imageViewerPtr;} bool prepareFIX(QByteArray bsrByteArray); // bool prepareHybrid(QString fn); bool prepareText(QString txt); void copyProfile(drmTxParams d); void setProfileNames(); // void test(); // void sendFIX(); void sendBSR(); void sendWfText(); void sendID(); public slots: void slotGetParams(); void slotStart(); void slotStop(); void slotDisplayStatusMessage(QString); void slotGenerateSignal(); void slotSweepSignal(); void slotGenerateRepeaterTone(); void slotEdit(); // void slotReplay(); void slotRepeaterTimer(); void slotFileOpen(); void slotModeChanged(int); void slotSnapshot(); void slotSize(int); void slotSizeApply(); void slotTransmissionMode(int rxtxMode); void slotProfileChanged(int ); void slotImageChanged(); private: Ui::txWidget *ui; txFunctions *txFunctionsPtr; void initView(); void setParams(); editor *ed; QTimer *repeaterTimer; int repeaterIndex; QImage origImage; QImage resultImage; void applyTemplate(); imageViewer *imageViewerPtr; etransmissionMode currentTXMode; drmTxParams drmParams; int sizeRatio; bool sizeRatioChanged; int drmProfileIdx; }; extern txWidget *txWidgetPtr; #endif // TXWIDGET_H qsstv_8.2.12/qsstv/txwidget.ui000664 001750 001750 00000126676 12440612574 016373 0ustar00jomajoma000000 000000 txWidget 0 0 840 529 8 Form 2 Start transmit Start transmit ... :/icons/start.png:/icons/start.png Stop transmit Stop transmit ... :/icons/stop.png:/icons/stop.png Send repeater tone Send repeater tone ... :/icons/tone.png:/icons/tone.png Load image Load image ... :/icons/fileopen.png:/icons/fileopen.png Edit image Edit image ... :/icons/edit.png:/icons/edit.png Camera snapshot Camera snapshot ... :/icons/camera.png:/icons/camera.png Hybrid Qt::Horizontal 40 20 Send tone Send tone ... :/icons/doubletone.png:/icons/doubletone.png Send sweep tones Send sweep tones ... :/icons/sweep.png:/icons/sweep.png 580 360 1200 800 Size 1 100 10 25 Qt::Horizontal QSlider::TicksBelow 80 0 80 16777215 QFrame::StyledPanel QFrame::Sunken 3 1 1 0 0 0 0 0 0 0 211 221 238 255 255 255 233 238 246 105 110 119 140 147 158 0 0 0 255 255 255 0 0 0 255 255 255 215 229 238 0 0 0 0 0 128 255 255 255 0 0 0 0 0 0 0 0 0 211 221 238 255 255 255 244 248 255 105 110 119 140 147 158 0 0 0 255 255 255 0 0 0 255 255 255 215 229 238 0 0 0 0 0 128 255 255 255 0 0 192 128 0 128 128 128 128 211 221 238 255 255 255 244 248 255 105 110 119 140 147 158 128 128 128 255 255 255 128 128 128 255 255 255 215 229 238 0 0 0 0 0 128 255 255 255 0 0 192 128 0 128 1 SSTV Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Transmit mode Transmit mode Qt::Vertical 20 40 DRM 1 1 0 30 0 QAM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false None RS1 RS2 RS3 RS4 30 0 Mode Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 30 0 Rs Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 30 0 Prot. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 2.2 KHz 2.5 KHz A B E Short Long High Low 30 0 BW Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 30 0 Interleave Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 30 0 Instances Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 4 16 64 Profile Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 0 2 TX Progress Qt::AlignCenter false 0 1 0 Send leading tone Send leading tone VOX Send CW at end Send CW at end CW Use Template Select template Select template 0 1 120 25 208 25 Template info Template info 10 0 z false 120 25 208 25 Template info Template info 50 25 50 25 Template info Template info 120 25 120 25 Template info Template info 30 0 RSV false Qt::Horizontal 40 20 30 0 To: false 10 0 y false 126 25 208 25 Template info Template info 10 0 x false 120 25 120 25 Template info Template info 30 0 Op: false Qt::Horizontal 40 20 4 Qt::Horizontal 40 20 100 80 Qt::Horizontal 40 20 Qt::Vertical 20 0 imageViewer QWidget
widgets/imageviewer.h
1
qsstv_8.2.12/qwt/qwt_plot_renderer.cpp000664 001750 001750 00000062531 12440612574 020060 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_renderer.h" #include "qwt_plot.h" #include "qwt_painter.h" #include "qwt_plot_layout.h" #include "qwt_abstract_legend.h" #include "qwt_scale_widget.h" #include "qwt_scale_engine.h" #include "qwt_text.h" #include "qwt_text_label.h" #include "qwt_math.h" #include #include #include #include #include #include #include #include #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #include #endif #endif static QPainterPath qwtCanvasClip( const QWidget* canvas, const QRectF &canvasRect ) { // The clip region is calculated in integers // To avoid too much rounding errors better // calculate it in target device resolution int x1 = qCeil( canvasRect.left() ); int x2 = qFloor( canvasRect.right() ); int y1 = qCeil( canvasRect.top() ); int y2 = qFloor( canvasRect.bottom() ); const QRect r( x1, y1, x2 - x1 - 1, y2 - y1 - 1 ); QPainterPath clipPath; ( void ) QMetaObject::invokeMethod( const_cast< QWidget *>( canvas ), "borderPath", Qt::DirectConnection, Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, r ) ); return clipPath; } class QwtPlotRenderer::PrivateData { public: PrivateData(): discardFlags( QwtPlotRenderer::DiscardNone ), layoutFlags( QwtPlotRenderer::DefaultLayout ) { } QwtPlotRenderer::DiscardFlags discardFlags; QwtPlotRenderer::LayoutFlags layoutFlags; }; /*! Constructor \param parent Parent object */ QwtPlotRenderer::QwtPlotRenderer( QObject *parent ): QObject( parent ) { d_data = new PrivateData; } //! Destructor QwtPlotRenderer::~QwtPlotRenderer() { delete d_data; } /*! Change a flag, indicating what to discard from rendering \param flag Flag to change \param on On/Off \sa DiscardFlag, testDiscardFlag(), setDiscardFlags(), discardFlags() */ void QwtPlotRenderer::setDiscardFlag( DiscardFlag flag, bool on ) { if ( on ) d_data->discardFlags |= flag; else d_data->discardFlags &= ~flag; } /*! \return True, if flag is enabled. \param flag Flag to be tested \sa DiscardFlag, setDiscardFlag(), setDiscardFlags(), discardFlags() */ bool QwtPlotRenderer::testDiscardFlag( DiscardFlag flag ) const { return d_data->discardFlags & flag; } /*! Set the flags, indicating what to discard from rendering \param flags Flags \sa DiscardFlag, setDiscardFlag(), testDiscardFlag(), discardFlags() */ void QwtPlotRenderer::setDiscardFlags( DiscardFlags flags ) { d_data->discardFlags = flags; } /*! \return Flags, indicating what to discard from rendering \sa DiscardFlag, setDiscardFlags(), setDiscardFlag(), testDiscardFlag() */ QwtPlotRenderer::DiscardFlags QwtPlotRenderer::discardFlags() const { return d_data->discardFlags; } /*! Change a layout flag \param flag Flag to change \param on On/Off \sa LayoutFlag, testLayoutFlag(), setLayoutFlags(), layoutFlags() */ void QwtPlotRenderer::setLayoutFlag( LayoutFlag flag, bool on ) { if ( on ) d_data->layoutFlags |= flag; else d_data->layoutFlags &= ~flag; } /*! \return True, if flag is enabled. \param flag Flag to be tested \sa LayoutFlag, setLayoutFlag(), setLayoutFlags(), layoutFlags() */ bool QwtPlotRenderer::testLayoutFlag( LayoutFlag flag ) const { return d_data->layoutFlags & flag; } /*! Set the layout flags \param flags Flags \sa LayoutFlag, setLayoutFlag(), testLayoutFlag(), layoutFlags() */ void QwtPlotRenderer::setLayoutFlags( LayoutFlags flags ) { d_data->layoutFlags = flags; } /*! \return Layout flags \sa LayoutFlag, setLayoutFlags(), setLayoutFlag(), testLayoutFlag() */ QwtPlotRenderer::LayoutFlags QwtPlotRenderer::layoutFlags() const { return d_data->layoutFlags; } /*! Render a plot to a file The format of the document will be auto-detected from the suffix of the file name. \param plot Plot widget \param fileName Path of the file, where the document will be stored \param sizeMM Size for the document in millimeters. \param resolution Resolution in dots per Inch (dpi) */ void QwtPlotRenderer::renderDocument( QwtPlot *plot, const QString &fileName, const QSizeF &sizeMM, int resolution ) { renderDocument( plot, fileName, QFileInfo( fileName ).suffix(), sizeMM, resolution ); } /*! Render a plot to a file Supported formats are: - pdf\n Portable Document Format PDF - ps\n Postcript - svg\n Scalable Vector Graphics SVG - all image formats supported by Qt\n see QImageWriter::supportedImageFormats() Scalable vector graphic formats like PDF or SVG are superior to raster graphics formats. \param plot Plot widget \param fileName Path of the file, where the document will be stored \param format Format for the document \param sizeMM Size for the document in millimeters. \param resolution Resolution in dots per Inch (dpi) \sa renderTo(), render(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::renderDocument( QwtPlot *plot, const QString &fileName, const QString &format, const QSizeF &sizeMM, int resolution ) { if ( plot == NULL || sizeMM.isEmpty() || resolution <= 0 ) return; QString title = plot->title().text(); if ( title.isEmpty() ) title = "Plot Document"; const double mmToInch = 1.0 / 25.4; const QSizeF size = sizeMM * mmToInch * resolution; const QRectF documentRect( 0.0, 0.0, size.width(), size.height() ); const QString fmt = format.toLower(); if ( fmt == "pdf" ) { } else if ( fmt == "ps" ) { } else if ( fmt == "svg" ) { #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #if QT_VERSION >= 0x040500 QSvgGenerator generator; generator.setTitle( title ); generator.setFileName( fileName ); generator.setResolution( resolution ); generator.setViewBox( documentRect ); QPainter painter( &generator ); render( plot, &painter, documentRect ); #endif #endif #endif } else { if ( QImageWriter::supportedImageFormats().indexOf( format.toLatin1() ) >= 0 ) { const QRect imageRect = documentRect.toRect(); const int dotsPerMeter = qRound( resolution * mmToInch * 1000.0 ); QImage image( imageRect.size(), QImage::Format_ARGB32 ); image.setDotsPerMeterX( dotsPerMeter ); image.setDotsPerMeterY( dotsPerMeter ); image.fill( QColor( Qt::white ).rgb() ); QPainter painter( &image ); render( plot, &painter, imageRect ); painter.end(); image.save( fileName, format.toLatin1() ); } } } /*! \brief Render the plot to a \c QPaintDevice This function renders the contents of a QwtPlot instance to \c QPaintDevice object. The target rectangle is derived from its device metrics. \param plot Plot to be rendered \param paintDevice device to paint on, f.e a QImage \sa renderDocument(), render(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::renderTo( QwtPlot *plot, QPaintDevice &paintDevice ) const { int w = paintDevice.width(); int h = paintDevice.height(); QPainter p( &paintDevice ); render( plot, &p, QRectF( 0, 0, w, h ) ); } /*! \brief Render the plot to a QPrinter This function renders the contents of a QwtPlot instance to \c QPaintDevice object. The size is derived from the printer metrics. \param plot Plot to be rendered \param printer Printer to paint on \sa renderDocument(), render(), QwtPainter::setRoundingAlignment() */ /*! Paint the contents of a QwtPlot instance into a given rectangle. \param plot Plot to be rendered \param painter Painter \param plotRect Bounding rectangle \sa renderDocument(), renderTo(), QwtPainter::setRoundingAlignment() */ void QwtPlotRenderer::render( QwtPlot *plot, QPainter *painter, const QRectF &plotRect ) const { if ( painter == 0 || !painter->isActive() || !plotRect.isValid() || plot->size().isNull() ) { return; } if ( !( d_data->discardFlags & DiscardBackground ) ) QwtPainter::drawBackgound( painter, plotRect, plot ); /* The layout engine uses the same methods as they are used by the Qt layout system. Therefore we need to calculate the layout in screen coordinates and paint with a scaled painter. */ QTransform transform; transform.scale( double( painter->device()->logicalDpiX() ) / plot->logicalDpiX(), double( painter->device()->logicalDpiY() ) / plot->logicalDpiY() ); QRectF layoutRect = transform.inverted().mapRect( plotRect ); if ( !( d_data->discardFlags & DiscardBackground ) ) { // subtract the contents margins int left, top, right, bottom; plot->getContentsMargins( &left, &top, &right, &bottom ); layoutRect.adjust( left, top, -right, -bottom ); } QwtPlotLayout *layout = plot->plotLayout(); int baseLineDists[QwtPlot::axisCnt]; int canvasMargins[QwtPlot::axisCnt]; for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { canvasMargins[ axisId ] = layout->canvasMargin( axisId ); if ( d_data->layoutFlags & FrameWithScales ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) { baseLineDists[axisId] = scaleWidget->margin(); scaleWidget->setMargin( 0 ); } if ( !plot->axisEnabled( axisId ) ) { int left = 0; int right = 0; int top = 0; int bottom = 0; // When we have a scale the frame is painted on // the position of the backbone - otherwise we // need to introduce a margin around the canvas switch( axisId ) { case QwtPlot::yLeft: layoutRect.adjust( 1, 0, 0, 0 ); break; case QwtPlot::yRight: layoutRect.adjust( 0, 0, -1, 0 ); break; case QwtPlot::xTop: layoutRect.adjust( 0, 1, 0, 0 ); break; case QwtPlot::xBottom: layoutRect.adjust( 0, 0, 0, -1 ); break; default: break; } layoutRect.adjust( left, top, right, bottom ); } } } // Calculate the layout for the document. QwtPlotLayout::Options layoutOptions = QwtPlotLayout::IgnoreScrollbars; if ( ( d_data->layoutFlags & FrameWithScales ) || ( d_data->discardFlags & DiscardCanvasFrame ) ) { layoutOptions |= QwtPlotLayout::IgnoreFrames; } if ( d_data->discardFlags & DiscardLegend ) layoutOptions |= QwtPlotLayout::IgnoreLegend; if ( d_data->discardFlags & DiscardTitle ) layoutOptions |= QwtPlotLayout::IgnoreTitle; if ( d_data->discardFlags & DiscardFooter ) layoutOptions |= QwtPlotLayout::IgnoreFooter; layout->activate( plot, layoutRect, layoutOptions ); // canvas QwtScaleMap maps[QwtPlot::axisCnt]; buildCanvasMaps( plot, layout->canvasRect(), maps ); if ( updateCanvasMargins( plot, layout->canvasRect(), maps ) ) { // recalculate maps and layout, when the margins // have been changed layout->activate( plot, layoutRect, layoutOptions ); buildCanvasMaps( plot, layout->canvasRect(), maps ); } // now start painting painter->save(); painter->setWorldTransform( transform, true ); renderCanvas( plot, painter, layout->canvasRect(), maps ); if ( !( d_data->discardFlags & DiscardTitle ) && ( !plot->titleLabel()->text().isEmpty() ) ) { renderTitle( plot, painter, layout->titleRect() ); } if ( !( d_data->discardFlags & DiscardFooter ) && ( !plot->footerLabel()->text().isEmpty() ) ) { renderFooter( plot, painter, layout->footerRect() ); } if ( !( d_data->discardFlags & DiscardLegend ) && plot->legend() && !plot->legend()->isEmpty() ) { renderLegend( plot, painter, layout->legendRect() ); } for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) { int baseDist = scaleWidget->margin(); int startDist, endDist; scaleWidget->getBorderDistHint( startDist, endDist ); renderScale( plot, painter, axisId, startDist, endDist, baseDist, layout->scaleRect( axisId ) ); } } painter->restore(); // restore all setting to their original attributes. for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { if ( d_data->layoutFlags & FrameWithScales ) { QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget ) scaleWidget->setMargin( baseLineDists[axisId] ); } layout->setCanvasMargin( canvasMargins[axisId] ); } layout->invalidate(); } /*! Render the title into a given rectangle. \param plot Plot widget \param painter Painter \param rect Bounding rectangle */ void QwtPlotRenderer::renderTitle( const QwtPlot *plot, QPainter *painter, const QRectF &rect ) const { painter->setFont( plot->titleLabel()->font() ); const QColor color = plot->titleLabel()->palette().color( QPalette::Active, QPalette::Text ); painter->setPen( color ); plot->titleLabel()->text().draw( painter, rect ); } /*! Render the footer into a given rectangle. \param plot Plot widget \param painter Painter \param rect Bounding rectangle */ void QwtPlotRenderer::renderFooter( const QwtPlot *plot, QPainter *painter, const QRectF &rect ) const { painter->setFont( plot->footerLabel()->font() ); const QColor color = plot->footerLabel()->palette().color( QPalette::Active, QPalette::Text ); painter->setPen( color ); plot->footerLabel()->text().draw( painter, rect ); } /*! Render the legend into a given rectangle. \param plot Plot widget \param painter Painter \param rect Bounding rectangle */ void QwtPlotRenderer::renderLegend( const QwtPlot *plot, QPainter *painter, const QRectF &rect ) const { if ( plot->legend() ) { bool fillBackground = !( d_data->discardFlags & DiscardBackground ); plot->legend()->renderLegend( painter, rect, fillBackground ); } } /*! \brief Paint a scale into a given rectangle. Paint the scale into a given rectangle. \param plot Plot widget \param painter Painter \param axisId Axis \param startDist Start border distance \param endDist End border distance \param baseDist Base distance \param rect Bounding rectangle */ void QwtPlotRenderer::renderScale( const QwtPlot *plot, QPainter *painter, int axisId, int startDist, int endDist, int baseDist, const QRectF &rect ) const { if ( !plot->axisEnabled( axisId ) ) return; const QwtScaleWidget *scaleWidget = plot->axisWidget( axisId ); if ( scaleWidget->isColorBarEnabled() && scaleWidget->colorBarWidth() > 0 ) { scaleWidget->drawColorBar( painter, scaleWidget->colorBarRect( rect ) ); baseDist += scaleWidget->colorBarWidth() + scaleWidget->spacing(); } painter->save(); QwtScaleDraw::Alignment align; double x, y, w; switch ( axisId ) { case QwtPlot::yLeft: { x = rect.right() - 1.0 - baseDist; y = rect.y() + startDist; w = rect.height() - startDist - endDist; align = QwtScaleDraw::LeftScale; break; } case QwtPlot::yRight: { x = rect.left() + baseDist; y = rect.y() + startDist; w = rect.height() - startDist - endDist; align = QwtScaleDraw::RightScale; break; } case QwtPlot::xTop: { x = rect.left() + startDist; y = rect.bottom() - 1.0 - baseDist; w = rect.width() - startDist - endDist; align = QwtScaleDraw::TopScale; break; } case QwtPlot::xBottom: { x = rect.left() + startDist; y = rect.top() + baseDist; w = rect.width() - startDist - endDist; align = QwtScaleDraw::BottomScale; break; } default: return; } scaleWidget->drawTitle( painter, align, rect ); painter->setFont( scaleWidget->font() ); QwtScaleDraw *sd = const_cast( scaleWidget->scaleDraw() ); const QPointF sdPos = sd->pos(); const double sdLength = sd->length(); sd->move( x, y ); sd->setLength( w ); QPalette palette = scaleWidget->palette(); palette.setCurrentColorGroup( QPalette::Active ); sd->draw( painter, palette ); // reset previous values sd->move( sdPos ); sd->setLength( sdLength ); painter->restore(); } /*! Render the canvas into a given rectangle. \param plot Plot widget \param painter Painter \param map Maps mapping between plot and paint device coordinates \param canvasRect Canvas rectangle */ void QwtPlotRenderer::renderCanvas( const QwtPlot *plot, QPainter *painter, const QRectF &canvasRect, const QwtScaleMap *map ) const { const QWidget *canvas = plot->canvas(); QRectF r = canvasRect.adjusted( 0.0, 0.0, -1.0, -1.0 ); if ( d_data->layoutFlags & FrameWithScales ) { painter->save(); r.adjust( -1.0, -1.0, 1.0, 1.0 ); painter->setPen( QPen( Qt::black ) ); if ( !( d_data->discardFlags & DiscardCanvasBackground ) ) { const QBrush bgBrush = canvas->palette().brush( plot->backgroundRole() ); painter->setBrush( bgBrush ); } QwtPainter::drawRect( painter, r ); painter->restore(); painter->save(); painter->setClipRect( canvasRect ); plot->drawItems( painter, canvasRect, map ); painter->restore(); } else if ( canvas->testAttribute( Qt::WA_StyledBackground ) ) { QPainterPath clipPath; painter->save(); if ( !( d_data->discardFlags & DiscardCanvasBackground ) ) { QwtPainter::drawBackgound( painter, r, canvas ); clipPath = qwtCanvasClip( canvas, canvasRect ); } painter->restore(); painter->save(); if ( clipPath.isEmpty() ) painter->setClipRect( canvasRect ); else painter->setClipPath( clipPath ); plot->drawItems( painter, canvasRect, map ); painter->restore(); } else { QPainterPath clipPath; int frameWidth = 0; if ( !( d_data->discardFlags & DiscardCanvasFrame ) ) { const QVariant fw = canvas->property( "frameWidth" ); if ( fw.type() == QVariant::Int ) frameWidth = fw.toInt(); clipPath = qwtCanvasClip( canvas, canvasRect ); } QRectF innerRect = canvasRect.adjusted( frameWidth, frameWidth, -frameWidth, -frameWidth ); painter->save(); if ( clipPath.isEmpty() ) { painter->setClipRect( innerRect ); } else { painter->setClipPath( clipPath ); } if ( !( d_data->discardFlags & DiscardCanvasBackground ) ) { QwtPainter::drawBackgound( painter, innerRect, canvas ); } plot->drawItems( painter, innerRect, map ); painter->restore(); if ( frameWidth > 0 ) { painter->save(); const int frameStyle = canvas->property( "frameShadow" ).toInt() | canvas->property( "frameShape" ).toInt(); const int frameWidth = canvas->property( "frameWidth" ).toInt(); const QVariant borderRadius = canvas->property( "borderRadius" ); if ( borderRadius.type() == QVariant::Double && borderRadius.toDouble() > 0.0 ) { const double r = borderRadius.toDouble(); QwtPainter::drawRoundedFrame( painter, canvasRect, r, r, canvas->palette(), frameWidth, frameStyle ); } else { const int midLineWidth = canvas->property( "midLineWidth" ).toInt(); QwtPainter::drawFrame( painter, canvasRect, canvas->palette(), canvas->foregroundRole(), frameWidth, midLineWidth, frameStyle ); } painter->restore(); } } } /*! Calculated the scale maps for rendering the canvas \param plot Plot widget \param canvasRect Target rectangle \param maps Scale maps to be calculated */ void QwtPlotRenderer::buildCanvasMaps( const QwtPlot *plot, const QRectF &canvasRect, QwtScaleMap maps[] ) const { for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { maps[axisId].setTransformation( plot->axisScaleEngine( axisId )->transformation() ); const QwtScaleDiv &scaleDiv = plot->axisScaleDiv( axisId ); maps[axisId].setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() ); double from, to; if ( plot->axisEnabled( axisId ) ) { const int sDist = plot->axisWidget( axisId )->startBorderDist(); const int eDist = plot->axisWidget( axisId )->endBorderDist(); const QRectF scaleRect = plot->plotLayout()->scaleRect( axisId ); if ( axisId == QwtPlot::xTop || axisId == QwtPlot::xBottom ) { from = scaleRect.left() + sDist; to = scaleRect.right() - eDist; } else { from = scaleRect.bottom() - eDist; to = scaleRect.top() + sDist; } } else { int margin = 0; if ( !plot->plotLayout()->alignCanvasToScale( axisId ) ) margin = plot->plotLayout()->canvasMargin( axisId ); if ( axisId == QwtPlot::yLeft || axisId == QwtPlot::yRight ) { from = canvasRect.bottom() - margin; to = canvasRect.top() + margin; } else { from = canvasRect.left() + margin; to = canvasRect.right() - margin; } } maps[axisId].setPaintInterval( from, to ); } } bool QwtPlotRenderer::updateCanvasMargins( QwtPlot *plot, const QRectF &canvasRect, const QwtScaleMap maps[] ) const { double margins[QwtPlot::axisCnt]; plot->getCanvasMarginsHint( maps, canvasRect, margins[QwtPlot::yLeft], margins[QwtPlot::xTop], margins[QwtPlot::yRight], margins[QwtPlot::xBottom] ); bool marginsChanged = false; for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) { if ( margins[axisId] >= 0.0 ) { const int m = qCeil( margins[axisId] ); plot->plotLayout()->setCanvasMargin( m, axisId); marginsChanged = true; } } return marginsChanged; } /*! \brief Execute a file dialog and render the plot to the selected file \param plot Plot widget \param documentName Default document name \param sizeMM Size for the document in millimeters. \param resolution Resolution in dots per Inch (dpi) \return True, when exporting was successful \sa renderDocument() */ bool QwtPlotRenderer::exportTo( QwtPlot *plot, const QString &documentName, const QSizeF &sizeMM, int resolution ) { if ( plot == NULL ) return false; QString fileName = documentName; // What about translation #ifndef QT_NO_FILEDIALOG const QList imageFormats = QImageWriter::supportedImageFormats(); QStringList filter; #ifndef QT_NO_PRINTER filter += QString( "PDF " ) + tr( "Documents" ) + " (*.pdf)"; #endif #ifndef QWT_NO_SVG filter += QString( "SVG " ) + tr( "Documents" ) + " (*.svg)"; #endif #ifndef QT_NO_PRINTER filter += QString( "Postscript " ) + tr( "Documents" ) + " (*.ps)"; #endif if ( imageFormats.size() > 0 ) { QString imageFilter( tr( "Images" ) ); imageFilter += " ("; for ( int i = 0; i < imageFormats.size(); i++ ) { if ( i > 0 ) imageFilter += " "; imageFilter += "*."; imageFilter += imageFormats[i]; } imageFilter += ")"; filter += imageFilter; } fileName = QFileDialog::getSaveFileName( NULL, tr( "Export File Name" ), fileName, filter.join( ";;" ), NULL, QFileDialog::DontConfirmOverwrite ); #endif if ( fileName.isEmpty() ) return false; renderDocument( plot, fileName, sizeMM, resolution ); return true; } qsstv_8.2.12/qwt/qwt_wheel.h000664 001750 001750 00000011412 12440612574 015755 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_WHEEL_H #define QWT_WHEEL_H #include "qwt_global.h" #include /*! \brief The Wheel Widget The wheel widget can be used to change values over a very large range in very small steps. Using the setMass() member, it can be configured as a flying wheel. The default range of the wheel is [0.0, 100.0] \sa The radio example. */ class QWT_EXPORT QwtWheel: public QWidget { Q_OBJECT Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ) Q_PROPERTY( double value READ value WRITE setValue ) Q_PROPERTY( double minimum READ minimum WRITE setMinimum ) Q_PROPERTY( double maximum READ maximum WRITE setMaximum ) Q_PROPERTY( double singleStep READ singleStep WRITE setSingleStep ) Q_PROPERTY( int pageStepCount READ pageStepCount WRITE setPageStepCount ) Q_PROPERTY( bool stepAlignment READ stepAlignment WRITE setStepAlignment ) Q_PROPERTY( bool tracking READ isTracking WRITE setTracking ) Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping ) Q_PROPERTY( bool inverted READ isInverted WRITE setInverted ) Q_PROPERTY( double mass READ mass WRITE setMass ) Q_PROPERTY( int updateInterval READ updateInterval WRITE setUpdateInterval ) Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle ) Q_PROPERTY( double viewAngle READ viewAngle WRITE setViewAngle ) Q_PROPERTY( int tickCount READ tickCount WRITE setTickCount ) Q_PROPERTY( int wheelWidth READ wheelWidth WRITE setWheelWidth ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) Q_PROPERTY( int wheelBorderWidth READ wheelBorderWidth WRITE setWheelBorderWidth ) public: explicit QwtWheel( QWidget *parent = NULL ); virtual ~QwtWheel(); double value() const; void setOrientation( Qt::Orientation ); Qt::Orientation orientation() const; double totalAngle() const; double viewAngle() const; void setTickCount( int ); int tickCount() const; void setWheelWidth( int ); int wheelWidth() const; void setWheelBorderWidth( int ); int wheelBorderWidth() const; void setBorderWidth( int ); int borderWidth() const; void setInverted( bool tf ); bool isInverted() const; void setWrapping( bool tf ); bool wrapping() const; void setSingleStep( double ); double singleStep() const; void setPageStepCount( int ); int pageStepCount() const; void setStepAlignment( bool on ); bool stepAlignment() const; void setRange( double vmin, double vmax ); void setMinimum( double min ); double minimum() const; void setMaximum( double max ); double maximum() const; void setUpdateInterval( int ); int updateInterval() const; void setTracking( bool enable ); bool isTracking() const; double mass() const; public Q_SLOTS: void setValue( double ); void setTotalAngle ( double ); void setViewAngle( double ); void setMass( double ); Q_SIGNALS: /*! \brief Notify a change of value. When tracking is enabled this signal will be emitted every time the value changes. \param value new value \sa setTracking() */ void valueChanged( double value ); /*! This signal is emitted when the user presses the the wheel with the mouse */ void wheelPressed(); /*! This signal is emitted when the user releases the mouse */ void wheelReleased(); /*! This signal is emitted when the user moves the wheel with the mouse. \param value new value */ void wheelMoved( double value ); protected: virtual void paintEvent( QPaintEvent * ); virtual void mousePressEvent( QMouseEvent * ); virtual void mouseReleaseEvent( QMouseEvent * ); virtual void mouseMoveEvent( QMouseEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void wheelEvent( QWheelEvent * ); virtual void timerEvent( QTimerEvent * ); void stopFlying(); QRect wheelRect() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void drawTicks( QPainter *, const QRectF & ); virtual void drawWheelBackground( QPainter *, const QRectF & ); virtual double valueAt( const QPoint & ) const; private: double alignedValue( double ) const; double boundedValue( double ) const; class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_renderer.h000664 001750 001750 00000010635 12440612574 017523 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_RENDERER_H #define QWT_PLOT_RENDERER_H #include "qwt_global.h" #include #include class QwtPlot; class QwtScaleMap; class QRectF; class QPainter; class QPaintDevice; #ifndef QT_NO_PRINTER class QPrinter; #endif #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB class QSvgGenerator; #endif #endif /*! \brief Renderer for exporting a plot to a document, a printer or anything else, that is supported by QPainter/QPaintDevice */ class QWT_EXPORT QwtPlotRenderer: public QObject { Q_OBJECT public: //! Disard flags enum DiscardFlag { //! Render all components of the plot DiscardNone = 0x00, //! Don't render the background of the plot DiscardBackground = 0x01, //! Don't render the title of the plot DiscardTitle = 0x02, //! Don't render the legend of the plot DiscardLegend = 0x04, //! Don't render the background of the canvas DiscardCanvasBackground = 0x08, //! Don't render the footer of the plot DiscardFooter = 0x10, /*! Don't render the frame of the canvas \note This flag has no effect when using style sheets, where the frame is part of the background */ DiscardCanvasFrame = 0x20 }; //! Disard flags typedef QFlags DiscardFlags; /*! \brief Layout flags \sa setLayoutFlag(), testLayoutFlag() */ enum LayoutFlag { //! Use the default layout as on screen DefaultLayout = 0x00, /*! Instead of the scales a box is painted around the plot canvas, where the scale ticks are aligned to. */ FrameWithScales = 0x01 }; //! Layout flags typedef QFlags LayoutFlags; explicit QwtPlotRenderer( QObject * = NULL ); virtual ~QwtPlotRenderer(); void setDiscardFlag( DiscardFlag flag, bool on = true ); bool testDiscardFlag( DiscardFlag flag ) const; void setDiscardFlags( DiscardFlags flags ); DiscardFlags discardFlags() const; void setLayoutFlag( LayoutFlag flag, bool on = true ); bool testLayoutFlag( LayoutFlag flag ) const; void setLayoutFlags( LayoutFlags flags ); LayoutFlags layoutFlags() const; void renderDocument( QwtPlot *, const QString &fileName, const QSizeF &sizeMM, int resolution = 85 ); void renderDocument( QwtPlot *, const QString &fileName, const QString &format, const QSizeF &sizeMM, int resolution = 85 ); #ifndef QWT_NO_SVG #ifdef QT_SVG_LIB #if QT_VERSION >= 0x040500 void renderTo( QwtPlot *, QSvgGenerator & ) const; #endif #endif #endif #ifndef QT_NO_PRINTER void renderTo( QwtPlot *, QPrinter & ) const; #endif void renderTo( QwtPlot *, QPaintDevice &p ) const; virtual void render( QwtPlot *, QPainter *, const QRectF &rect ) const; virtual void renderTitle( const QwtPlot *, QPainter *, const QRectF & ) const; virtual void renderFooter( const QwtPlot *, QPainter *, const QRectF & ) const; virtual void renderScale( const QwtPlot *, QPainter *, int axisId, int startDist, int endDist, int baseDist, const QRectF & ) const; virtual void renderCanvas( const QwtPlot *, QPainter *, const QRectF &canvasRect, const QwtScaleMap* maps ) const; virtual void renderLegend( const QwtPlot *, QPainter *, const QRectF & ) const; bool exportTo( QwtPlot *, const QString &documentName, const QSizeF &sizeMM = QSizeF( 300, 200 ), int resolution = 85 ); private: void buildCanvasMaps( const QwtPlot *, const QRectF &, QwtScaleMap maps[] ) const; bool updateCanvasMargins( QwtPlot *, const QRectF &, const QwtScaleMap maps[] ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotRenderer::DiscardFlags ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotRenderer::LayoutFlags ) #endif qsstv_8.2.12/qwt/qwt_widget_overlay.cpp000664 001750 001750 00000020376 12440612574 020241 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_widget_overlay.h" #include "qwt_painter.h" #include #include #include #include static QImage::Format qwtMaskImageFormat() { if ( QwtPainter::isX11GraphicsSystem() ) return QImage::Format_ARGB32; return QImage::Format_ARGB32_Premultiplied; } static QRegion qwtAlphaMask( const QImage& image, const QVector rects ) { const int w = image.width(); const int h = image.height(); QRegion region; QRect rect; for ( int i = 0; i < rects.size(); i++ ) { int x1, x2, y1, y2; rects[i].getCoords( &x1, &y1, &x2, &y2 ); x1 = qMax( x1, 0 ); x2 = qMin( x2, w - 1 ); y1 = qMax( y1, 0 ); y2 = qMin( y2, h - 1 ); for ( int y = y1; y <= y2; ++y ) { bool inRect = false; int rx0 = -1; const uint *line = reinterpret_cast ( image.scanLine( y ) ) + x1; for ( int x = x1; x <= x2; x++ ) { const bool on = ( ( *line++ >> 24 ) != 0 ); if ( on != inRect ) { if ( inRect ) { rect.setCoords( rx0, y, x - 1, y ); region += rect; } else { rx0 = x; } inRect = on; } } if ( inRect ) { rect.setCoords( rx0, y, x2, y ); region = region.united( rect ); } } } return region; } class QwtWidgetOverlay::PrivateData { public: PrivateData(): maskMode( QwtWidgetOverlay::MaskHint ), renderMode( QwtWidgetOverlay::AutoRenderMode ), rgbaBuffer( NULL ) { } ~PrivateData() { resetRgbaBuffer(); } void resetRgbaBuffer() { if ( rgbaBuffer ) { ::free( rgbaBuffer ); rgbaBuffer = NULL; } } MaskMode maskMode; RenderMode renderMode; uchar *rgbaBuffer; }; /*! \brief Constructor \param widget Parent widget, where the overlay is aligned to */ QwtWidgetOverlay::QwtWidgetOverlay( QWidget* widget ): QWidget( widget ) { d_data = new PrivateData; setAttribute( Qt::WA_TransparentForMouseEvents ); setAttribute( Qt::WA_NoSystemBackground ); setFocusPolicy( Qt::NoFocus ); if ( widget ) { resize( widget->size() ); widget->installEventFilter( this ); } } //! Destructor QwtWidgetOverlay::~QwtWidgetOverlay() { delete d_data; } /*! \brief Specify how to find the mask for the overlay \param mode New mode \sa maskMode() */ void QwtWidgetOverlay::setMaskMode( MaskMode mode ) { if ( mode != d_data->maskMode ) { d_data->maskMode = mode; d_data->resetRgbaBuffer(); } } /*! \return Mode how to find the mask for the overlay \sa setMaskMode() */ QwtWidgetOverlay::MaskMode QwtWidgetOverlay::maskMode() const { return d_data->maskMode; } /*! Set the render mode \param mode Render mode \sa RenderMode, renderMode() */ void QwtWidgetOverlay::setRenderMode( RenderMode mode ) { d_data->renderMode = mode; } /*! \return Render mode \sa RenderMode, setRenderMode() */ QwtWidgetOverlay::RenderMode QwtWidgetOverlay::renderMode() const { return d_data->renderMode; } /*! Recalculate the mask and repaint the overlay */ void QwtWidgetOverlay::updateOverlay() { updateMask(); update(); } void QwtWidgetOverlay::updateMask() { d_data->resetRgbaBuffer(); QRegion mask; if ( d_data->maskMode == QwtWidgetOverlay::MaskHint ) { mask = maskHint(); } else if ( d_data->maskMode == QwtWidgetOverlay::AlphaMask ) { // TODO: the image doesn't need to be larger than // the bounding rectangle of the hint !! QRegion hint = maskHint(); if ( hint.isEmpty() ) hint += QRect( 0, 0, width(), height() ); // A fresh buffer from calloc() is usually faster // than reinitializing an existing one with // QImage::fill( 0 ) or memset() d_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 ); QImage image( d_data->rgbaBuffer, width(), height(), qwtMaskImageFormat() ); QPainter painter( &image ); draw( &painter ); painter.end(); mask = qwtAlphaMask( image, hint.rects() ); if ( d_data->renderMode == QwtWidgetOverlay::DrawOverlay ) { // we don't need the buffer later d_data->resetRgbaBuffer(); } } // A bug in Qt initiates a full repaint of the widget // when we change the mask, while we are visible ! setVisible( false ); if ( mask.isEmpty() ) clearMask(); else setMask( mask ); setVisible( true ); } /*! Paint event \param event Paint event \sa drawOverlay() */ void QwtWidgetOverlay::paintEvent( QPaintEvent* event ) { const QRegion clipRegion = event->region(); QPainter painter( this ); bool useRgbaBuffer = false; if ( d_data->renderMode == QwtWidgetOverlay::CopyAlphaMask ) { useRgbaBuffer = true; } else if ( d_data->renderMode == QwtWidgetOverlay::AutoRenderMode ) { if ( painter.paintEngine()->type() == QPaintEngine::Raster ) useRgbaBuffer = true; } if ( d_data->rgbaBuffer && useRgbaBuffer ) { const QImage image( d_data->rgbaBuffer, width(), height(), qwtMaskImageFormat() ); QVector rects; if ( clipRegion.rects().size() > 2000 ) { // the region is to complex painter.setClipRegion( clipRegion ); rects += clipRegion.boundingRect(); } else { rects = clipRegion.rects(); } for ( int i = 0; i < rects.size(); i++ ) { const QRect r = rects[i]; painter.drawImage( r.topLeft(), image, r ); } } else { painter.setClipRegion( clipRegion ); draw( &painter ); } } /*! Resize event \param event Resize event */ void QwtWidgetOverlay::resizeEvent( QResizeEvent* event ) { Q_UNUSED( event ); d_data->resetRgbaBuffer(); } void QwtWidgetOverlay::draw( QPainter *painter ) const { QWidget *widget = const_cast< QWidget *>( parentWidget() ); if ( widget ) { painter->setClipRect( parentWidget()->contentsRect() ); // something special for the plot canvas QPainterPath clipPath; ( void )QMetaObject::invokeMethod( widget, "borderPath", Qt::DirectConnection, Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, rect() ) ); if (!clipPath.isEmpty()) { painter->setClipPath( clipPath, Qt::IntersectClip ); } } drawOverlay( painter ); } /*! \brief Calculate an approximation for the mask - MaskHint The hint is used as mask. - AlphaMask The hint is used to speed up the algorithm for calculating a mask from non transparent pixels - NoMask The hint is unused. The default implementation returns an invalid region indicating no hint. \return Hint for the mask */ QRegion QwtWidgetOverlay::maskHint() const { return QRegion(); } /*! \brief Event filter Resize the overlay according to the size of the parent widget. \param object Object to be filtered \param event Event \return See QObject::eventFilter() */ bool QwtWidgetOverlay::eventFilter( QObject* object, QEvent* event ) { if ( object == parent() && event->type() == QEvent::Resize ) { QResizeEvent *resizeEvent = static_cast( event ); resize( resizeEvent->size() ); } return QObject::eventFilter( object, event ); } qsstv_8.2.12/qwt/qwt_plot_rescaler.cpp000664 001750 001750 00000035761 12440612574 020057 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_rescaler.h" #include "qwt_plot.h" #include "qwt_scale_div.h" #include "qwt_interval.h" #include "qwt_plot_canvas.h" #include #include class QwtPlotRescaler::AxisData { public: AxisData(): aspectRatio( 1.0 ), expandingDirection( QwtPlotRescaler::ExpandUp ) { } double aspectRatio; QwtInterval intervalHint; QwtPlotRescaler::ExpandingDirection expandingDirection; mutable QwtScaleDiv scaleDiv; }; class QwtPlotRescaler::PrivateData { public: PrivateData(): referenceAxis( QwtPlot::xBottom ), rescalePolicy( QwtPlotRescaler::Expanding ), isEnabled( false ), inReplot( 0 ) { } int referenceAxis; RescalePolicy rescalePolicy; QwtPlotRescaler::AxisData axisData[QwtPlot::axisCnt]; bool isEnabled; mutable int inReplot; }; /*! Constructor \param canvas Canvas \param referenceAxis Reference axis, see RescalePolicy \param policy Rescale policy \sa setRescalePolicy(), setReferenceAxis() */ QwtPlotRescaler::QwtPlotRescaler( QWidget *canvas, int referenceAxis, RescalePolicy policy ): QObject( canvas ) { d_data = new PrivateData; d_data->referenceAxis = referenceAxis; d_data->rescalePolicy = policy; setEnabled( true ); } //! Destructor QwtPlotRescaler::~QwtPlotRescaler() { delete d_data; } /*! \brief En/disable the rescaler When enabled is true an event filter is installed for the canvas, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPlotRescaler::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = canvas(); if ( w ) { if ( d_data->isEnabled ) w->installEventFilter( this ); else w->removeEventFilter( this ); } } } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPlotRescaler::isEnabled() const { return d_data->isEnabled; } /*! Change the rescale policy \param policy Rescale policy \sa rescalePolicy() */ void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy ) { d_data->rescalePolicy = policy; } /*! \return Rescale policy \sa setRescalePolicy() */ QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const { return d_data->rescalePolicy; } /*! Set the reference axis ( see RescalePolicy ) \param axis Axis index ( QwtPlot::Axis ) \sa referenceAxis() */ void QwtPlotRescaler::setReferenceAxis( int axis ) { d_data->referenceAxis = axis; } /*! \return Reference axis ( see RescalePolicy ) \sa setReferenceAxis() */ int QwtPlotRescaler::referenceAxis() const { return d_data->referenceAxis; } /*! Set the direction in which all axis should be expanded \param direction Direction \sa expandingDirection() */ void QwtPlotRescaler::setExpandingDirection( ExpandingDirection direction ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) setExpandingDirection( axis, direction ); } /*! Set the direction in which an axis should be expanded \param axis Axis index ( see QwtPlot::AxisId ) \param direction Direction \sa expandingDirection() */ void QwtPlotRescaler::setExpandingDirection( int axis, ExpandingDirection direction ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].expandingDirection = direction; } /*! \return Direction in which an axis should be expanded \param axis Axis index ( see QwtPlot::AxisId ) \sa setExpandingDirection() */ QwtPlotRescaler::ExpandingDirection QwtPlotRescaler::expandingDirection( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].expandingDirection; return ExpandBoth; } /*! Set the aspect ratio between the scale of the reference axis and the other scales. The default ratio is 1.0 \param ratio Aspect ratio \sa aspectRatio() */ void QwtPlotRescaler::setAspectRatio( double ratio ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) setAspectRatio( axis, ratio ); } /*! Set the aspect ratio between the scale of the reference axis and another scale. The default ratio is 1.0 \param axis Axis index ( see QwtPlot::AxisId ) \param ratio Aspect ratio \sa aspectRatio() */ void QwtPlotRescaler::setAspectRatio( int axis, double ratio ) { if ( ratio < 0.0 ) ratio = 0.0; if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].aspectRatio = ratio; } /*! \return Aspect ratio between an axis and the reference axis. \param axis Axis index ( see QwtPlot::AxisId ) \sa setAspectRatio() */ double QwtPlotRescaler::aspectRatio( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].aspectRatio; return 0.0; } /*! Set an interval hint for an axis In Fitting mode, the hint is used as minimal interval that always needs to be displayed. \param axis Axis, see QwtPlot::Axis \param interval Axis \sa intervalHint(), RescalePolicy */ void QwtPlotRescaler::setIntervalHint( int axis, const QwtInterval &interval ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->axisData[axis].intervalHint = interval; } /*! \param axis Axis, see QwtPlot::Axis \return Interval hint \sa setIntervalHint(), RescalePolicy */ QwtInterval QwtPlotRescaler::intervalHint( int axis ) const { if ( axis >= 0 && axis < QwtPlot::axisCnt ) return d_data->axisData[axis].intervalHint; return QwtInterval(); } //! \return plot canvas QWidget *QwtPlotRescaler::canvas() { return qobject_cast( parent() ); } //! \return plot canvas const QWidget *QwtPlotRescaler::canvas() const { return qobject_cast( parent() ); } //! \return plot widget QwtPlot *QwtPlotRescaler::plot() { QWidget *w = canvas(); if ( w ) w = w->parentWidget(); return qobject_cast( w ); } //! \return plot widget const QwtPlot *QwtPlotRescaler::plot() const { const QWidget *w = canvas(); if ( w ) w = w->parentWidget(); return qobject_cast( w ); } //! Event filter for the plot canvas bool QwtPlotRescaler::eventFilter( QObject *object, QEvent *event ) { if ( object && object == canvas() ) { switch ( event->type() ) { case QEvent::Resize: { canvasResizeEvent( static_cast( event ) ); break; } case QEvent::PolishRequest: { rescale(); break; } default:; } } return false; } /*! Event handler for resize events of the plot canvas \param event Resize event \sa rescale() */ void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event ) { int left, top, right, bottom; canvas()->getContentsMargins( &left, &top, &right, &bottom ); const QSize marginSize( left + right, top + bottom ); const QSize newSize = event->size() - marginSize; const QSize oldSize = event->oldSize() - marginSize; rescale( oldSize, newSize ); } //! Adjust the plot axes scales void QwtPlotRescaler::rescale() const { const QSize size = canvas()->contentsRect().size(); rescale( size, size ); } /*! Adjust the plot axes scales \param oldSize Previous size of the canvas \param newSize New size of the canvas */ void QwtPlotRescaler::rescale( const QSize &oldSize, const QSize &newSize ) const { if ( newSize.isEmpty() ) return; QwtInterval intervals[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) intervals[axis] = interval( axis ); const int refAxis = referenceAxis(); intervals[refAxis] = expandScale( refAxis, oldSize, newSize ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( aspectRatio( axis ) > 0.0 && axis != refAxis ) intervals[axis] = syncScale( axis, intervals[refAxis], newSize ); } updateScales( intervals ); } /*! Calculate the new scale interval of a plot axis \param axis Axis index ( see QwtPlot::AxisId ) \param oldSize Previous size of the canvas \param newSize New size of the canvas \return Calculated new interval for the axis */ QwtInterval QwtPlotRescaler::expandScale( int axis, const QSize &oldSize, const QSize &newSize ) const { const QwtInterval oldInterval = interval( axis ); QwtInterval expanded = oldInterval; switch ( rescalePolicy() ) { case Fixed: { break; // do nothing } case Expanding: { if ( !oldSize.isEmpty() ) { double width = oldInterval.width(); if ( orientation( axis ) == Qt::Horizontal ) width *= double( newSize.width() ) / oldSize.width(); else width *= double( newSize.height() ) / oldSize.height(); expanded = expandInterval( oldInterval, width, expandingDirection( axis ) ); } break; } case Fitting: { double dist = 0.0; for ( int ax = 0; ax < QwtPlot::axisCnt; ax++ ) { const double d = pixelDist( ax, newSize ); if ( d > dist ) dist = d; } if ( dist > 0.0 ) { double width; if ( orientation( axis ) == Qt::Horizontal ) width = newSize.width() * dist; else width = newSize.height() * dist; expanded = expandInterval( intervalHint( axis ), width, expandingDirection( axis ) ); } break; } } return expanded; } /*! Synchronize an axis scale according to the scale of the reference axis \param axis Axis index ( see QwtPlot::AxisId ) \param reference Interval of the reference axis \param size Size of the canvas \return New interval for axis */ QwtInterval QwtPlotRescaler::syncScale( int axis, const QwtInterval& reference, const QSize &size ) const { double dist; if ( orientation( referenceAxis() ) == Qt::Horizontal ) dist = reference.width() / size.width(); else dist = reference.width() / size.height(); if ( orientation( axis ) == Qt::Horizontal ) dist *= size.width(); else dist *= size.height(); dist /= aspectRatio( axis ); QwtInterval intv; if ( rescalePolicy() == Fitting ) intv = intervalHint( axis ); else intv = interval( axis ); intv = expandInterval( intv, dist, expandingDirection( axis ) ); return intv; } /*! \return Orientation of an axis \param axis Axis index ( see QwtPlot::AxisId ) */ Qt::Orientation QwtPlotRescaler::orientation( int axis ) const { if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) return Qt::Vertical; return Qt::Horizontal; } /*! \param axis Axis index ( see QwtPlot::AxisId ) \return Normalized interval of an axis */ QwtInterval QwtPlotRescaler::interval( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) return QwtInterval(); return plot()->axisScaleDiv( axis ).interval().normalized(); } /*! Expand the interval \param interval Interval to be expanded \param width Distance to be added to the interval \param direction Direction of the expand operation \return Expanded interval */ QwtInterval QwtPlotRescaler::expandInterval( const QwtInterval &interval, double width, ExpandingDirection direction ) const { QwtInterval expanded = interval; switch ( direction ) { case ExpandUp: expanded.setMinValue( interval.minValue() ); expanded.setMaxValue( interval.minValue() + width ); break; case ExpandDown: expanded.setMaxValue( interval.maxValue() ); expanded.setMinValue( interval.maxValue() - width ); break; case ExpandBoth: default: expanded.setMinValue( interval.minValue() + interval.width() / 2.0 - width / 2.0 ); expanded.setMaxValue( expanded.minValue() + width ); } return expanded; } double QwtPlotRescaler::pixelDist( int axis, const QSize &size ) const { const QwtInterval intv = intervalHint( axis ); double dist = 0.0; if ( !intv.isNull() ) { if ( axis == referenceAxis() ) dist = intv.width(); else { const double r = aspectRatio( axis ); if ( r > 0.0 ) dist = intv.width() * r; } } if ( dist > 0.0 ) { if ( orientation( axis ) == Qt::Horizontal ) dist /= size.width(); else dist /= size.height(); } return dist; } /*! Update the axes scales \param intervals Scale intervals */ void QwtPlotRescaler::updateScales( QwtInterval intervals[QwtPlot::axisCnt] ) const { if ( d_data->inReplot >= 5 ) { return; } QwtPlot *plt = const_cast( plot() ); const bool doReplot = plt->autoReplot(); plt->setAutoReplot( false ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( axis == referenceAxis() || aspectRatio( axis ) > 0.0 ) { double v1 = intervals[axis].minValue(); double v2 = intervals[axis].maxValue(); if ( !plt->axisScaleDiv( axis ).isIncreasing() ) qSwap( v1, v2 ); if ( d_data->inReplot >= 1 ) d_data->axisData[axis].scaleDiv = plt->axisScaleDiv( axis ); if ( d_data->inReplot >= 2 ) { QList ticks[QwtScaleDiv::NTickTypes]; for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) ticks[i] = d_data->axisData[axis].scaleDiv.ticks( i ); plt->setAxisScaleDiv( axis, QwtScaleDiv( v1, v2, ticks ) ); } else { plt->setAxisScale( axis, v1, v2 ); } } } QwtPlotCanvas *canvas = qobject_cast( plt->canvas() ); bool immediatePaint = false; if ( canvas ) { immediatePaint = canvas->testPaintAttribute( QwtPlotCanvas::ImmediatePaint ); canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false ); } plt->setAutoReplot( doReplot ); d_data->inReplot++; plt->replot(); d_data->inReplot--; if ( canvas && immediatePaint ) { canvas->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, true ); } } qsstv_8.2.12/qwt/qwt_widget_overlay.h000664 001750 001750 00000007761 12440612574 017711 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_WIDGET_OVERLAY_H #define QWT_WIDGET_OVERLAY_H #include "qwt_global.h" #include #include class QPainter; /*! \brief An overlay for a widget The main use case of an widget overlay is to avoid heavy repaint operation of the widget below. F.e. in combination with the plot canvas an overlay avoid replots as the content of the canvas can be restored from its backing store. QwtWidgetOverlay is an abstract base class. Deriving classes are supposed to reimplement the following methods: - drawOverlay() - maskHint() Internally QwtPlotPicker uses overlays for displaying the rubber band and the tracker text. \sa QwtPlotCanvas::BackingStore */ class QWT_EXPORT QwtWidgetOverlay: public QWidget { public: /*! \brief Mask mode When using masks the widget below gets paint events for the masked regions of the overlay only. Otherwise Qt triggers full repaints. On less powerful hardware ( f.e embedded systems ) - or when using the raster paint engine on a remote desktop - bit blitting is a noticeable operation, that needs to be avoided. If and how to mask depends on how expensive the calculation of the mask is and how many pixels can be excluded by the mask. The default setting is MaskHint. \sa setMaskMode(), maskMode() */ enum MaskMode { //! Don't use a mask. NoMask, /*! \brief Use maskHint() as mask For many situations a fast approximation is good enough and it is not necessary to build a more detailed mask ( f.e the bounding rectangle of a text ). */ MaskHint, /*! \brief Calculate a mask by checking the alpha values Sometimes it is not possible to give a fast approximation and the mask needs to be calculated by drawing the overlay and testing the result. When a valid maskHint() is available only pixels inside this approximation are checked. */ AlphaMask }; /*! \brief Render mode For calculating the alpha mask the overlay has already been painted to a temporary QImage. Instead of rendering the overlay twice this buffer can be copied for drawing the overlay. On graphic systems using the raster paint engine ( QWS, Windows ) it means usually copying some memory only. On X11 it results in an expensive operation building a pixmap and for simple overlays it might not be recommended. \note The render mode has no effect, when maskMode() != AlphaMask. */ enum RenderMode { //! Copy the buffer, when using the raster paint engine. AutoRenderMode, //! Always copy the buffer CopyAlphaMask, //! Never copy the buffer DrawOverlay }; QwtWidgetOverlay( QWidget* ); virtual ~QwtWidgetOverlay(); void setMaskMode( MaskMode ); MaskMode maskMode() const; void setRenderMode( RenderMode ); RenderMode renderMode() const; void updateOverlay(); virtual bool eventFilter( QObject *, QEvent *); protected: virtual void paintEvent( QPaintEvent* event ); virtual void resizeEvent( QResizeEvent* event ); virtual QRegion maskHint() const; /*! Draw the widget overlay \param painter Painter */ virtual void drawOverlay( QPainter *painter ) const = 0; private: void updateMask(); void draw( QPainter * ) const; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_rescaler.h000664 001750 001750 00000007440 12440612574 017515 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_RESCALER_H #define QWT_PLOT_RESCALER_H 1 #include "qwt_global.h" #include "qwt_interval.h" #include "qwt_plot.h" #include class QwtPlot; class QResizeEvent; /*! \brief QwtPlotRescaler takes care of fixed aspect ratios for plot scales QwtPlotRescaler auto adjusts the axes of a QwtPlot according to fixed aspect ratios. */ class QWT_EXPORT QwtPlotRescaler: public QObject { public: /*! The rescale policy defines how to rescale the reference axis and their depending axes. \sa ExpandingDirection, setIntervalHint() */ enum RescalePolicy { /*! The interval of the reference axis remains unchanged, when the geometry of the canvas changes. All other axes will be adjusted according to their aspect ratio. */ Fixed, /*! The interval of the reference axis will be shrunk/expanded, when the geometry of the canvas changes. All other axes will be adjusted according to their aspect ratio. The interval, that is represented by one pixel is fixed. */ Expanding, /*! The intervals of the axes are calculated, so that all axes include their interval hint. */ Fitting }; /*! When rescalePolicy() is set to Expanding its direction depends on ExpandingDirection */ enum ExpandingDirection { //! The upper limit of the scale is adjusted ExpandUp, //! The lower limit of the scale is adjusted ExpandDown, //! Both limits of the scale are adjusted ExpandBoth }; explicit QwtPlotRescaler( QWidget *canvas, int referenceAxis = QwtPlot::xBottom, RescalePolicy = Expanding ); virtual ~QwtPlotRescaler(); void setEnabled( bool ); bool isEnabled() const; void setRescalePolicy( RescalePolicy ); RescalePolicy rescalePolicy() const; void setExpandingDirection( ExpandingDirection ); void setExpandingDirection( int axis, ExpandingDirection ); ExpandingDirection expandingDirection( int axis ) const; void setReferenceAxis( int axis ); int referenceAxis() const; void setAspectRatio( double ratio ); void setAspectRatio( int axis, double ratio ); double aspectRatio( int axis ) const; void setIntervalHint( int axis, const QwtInterval& ); QwtInterval intervalHint( int axis ) const; QWidget *canvas(); const QWidget *canvas() const; QwtPlot *plot(); const QwtPlot *plot() const; virtual bool eventFilter( QObject *, QEvent * ); void rescale() const; protected: virtual void canvasResizeEvent( QResizeEvent * ); virtual void rescale( const QSize &oldSize, const QSize &newSize ) const; virtual QwtInterval expandScale( int axis, const QSize &oldSize, const QSize &newSize ) const; virtual QwtInterval syncScale( int axis, const QwtInterval& reference, const QSize &size ) const; virtual void updateScales( QwtInterval intervals[QwtPlot::axisCnt] ) const; Qt::Orientation orientation( int axis ) const; QwtInterval interval( int axis ) const; QwtInterval expandInterval( const QwtInterval &, double width, ExpandingDirection ) const; private: double pixelDist( int axis, const QSize & ) const; class AxisData; class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_system_clock.h000664 001750 001750 00000002464 12440612574 017357 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SYSTEM_CLOCK_H #define QWT_SYSTEM_CLOCK_H #include "qwt_global.h" /*! \brief QwtSystemClock provides high resolution clock time functions. Sometimes the resolution offered by QTime ( millisecond ) is not accurate enough for implementing time measurements ( f.e. sampling ). QwtSystemClock offers a subset of the QTime functionality using higher resolution timers ( if possible ). Precision and time intervals are multiples of milliseconds (ms). \note The implementation uses high-resolution performance counter on Windows, mach_absolute_time() on the Mac or POSIX timers on other systems. If none is available it falls back on QTimer. */ class QWT_EXPORT QwtSystemClock { public: QwtSystemClock(); virtual ~QwtSystemClock(); bool isNull() const; void start(); double restart(); double elapsed() const; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_scaleitem.cpp000664 001750 001750 00000025511 12440612574 020215 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_scaleitem.h" #include "qwt_plot.h" #include "qwt_scale_map.h" #include "qwt_interval.h" #include #include class QwtPlotScaleItem::PrivateData { public: PrivateData(): position( 0.0 ), borderDistance( -1 ), scaleDivFromAxis( true ), scaleDraw( new QwtScaleDraw() ) { } ~PrivateData() { delete scaleDraw; } void updateBorders( const QRectF &, const QwtScaleMap &, const QwtScaleMap & ); QPalette palette; QFont font; double position; int borderDistance; bool scaleDivFromAxis; QwtScaleDraw *scaleDraw; QRectF canvasRectCache; }; void QwtPlotScaleItem::PrivateData::updateBorders( const QRectF &canvasRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap ) { QwtInterval interval; if ( scaleDraw->orientation() == Qt::Horizontal ) { interval.setMinValue( xMap.invTransform( canvasRect.left() ) ); interval.setMaxValue( xMap.invTransform( canvasRect.right() - 1 ) ); } else { interval.setMinValue( yMap.invTransform( canvasRect.bottom() - 1 ) ); interval.setMaxValue( yMap.invTransform( canvasRect.top() ) ); } QwtScaleDiv scaleDiv = scaleDraw->scaleDiv(); scaleDiv.setInterval( interval ); scaleDraw->setScaleDiv( scaleDiv ); } /*! \brief Constructor for scale item at the position pos. \param alignment In case of QwtScaleDraw::BottomScale or QwtScaleDraw::TopScale the scale item is corresponding to the xAxis(), otherwise it corresponds to the yAxis(). \param pos x or y position, depending on the corresponding axis. \sa setPosition(), setAlignment() */ QwtPlotScaleItem::QwtPlotScaleItem( QwtScaleDraw::Alignment alignment, const double pos ): QwtPlotItem( QwtText( "Scale" ) ) { d_data = new PrivateData; d_data->position = pos; d_data->scaleDraw->setAlignment( alignment ); setItemInterest( QwtPlotItem::ScaleInterest, true ); setZ( 11.0 ); } //! Destructor QwtPlotScaleItem::~QwtPlotScaleItem() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotScale int QwtPlotScaleItem::rtti() const { return QwtPlotItem::Rtti_PlotScale; } /*! \brief Assign a scale division When assigning a scaleDiv the scale division won't be synchronized with the corresponding axis anymore. \param scaleDiv Scale division \sa scaleDiv(), setScaleDivFromAxis(), isScaleDivFromAxis() */ void QwtPlotScaleItem::setScaleDiv( const QwtScaleDiv& scaleDiv ) { d_data->scaleDivFromAxis = false; d_data->scaleDraw->setScaleDiv( scaleDiv ); } //! \return Scale division const QwtScaleDiv& QwtPlotScaleItem::scaleDiv() const { return d_data->scaleDraw->scaleDiv(); } /*! Enable/Disable the synchronization of the scale division with the corresponding axis. \param on true/false \sa isScaleDivFromAxis() */ void QwtPlotScaleItem::setScaleDivFromAxis( bool on ) { if ( on != d_data->scaleDivFromAxis ) { d_data->scaleDivFromAxis = on; if ( on ) { const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( plt->axisScaleDiv( xAxis() ), plt->axisScaleDiv( yAxis() ) ); itemChanged(); } } } } /*! \return True, if the synchronization of the scale division with the corresponding axis is enabled. \sa setScaleDiv(), setScaleDivFromAxis() */ bool QwtPlotScaleItem::isScaleDivFromAxis() const { return d_data->scaleDivFromAxis; } /*! Set the palette \sa QwtAbstractScaleDraw::draw(), palette() */ void QwtPlotScaleItem::setPalette( const QPalette &palette ) { if ( palette != d_data->palette ) { d_data->palette = palette; legendChanged(); itemChanged(); } } /*! \return palette \sa setPalette() */ QPalette QwtPlotScaleItem::palette() const { return d_data->palette; } /*! Change the tick label font \sa font() */ void QwtPlotScaleItem::setFont( const QFont &font ) { if ( font != d_data->font ) { d_data->font = font; itemChanged(); } } /*! \return tick label font \sa setFont() */ QFont QwtPlotScaleItem::font() const { return d_data->font; } /*! \brief Set a scale draw \param scaleDraw object responsible for drawing scales. The main use case for replacing the default QwtScaleDraw is to overload QwtAbstractScaleDraw::label, to replace or swallow tick labels. \sa scaleDraw() */ void QwtPlotScaleItem::setScaleDraw( QwtScaleDraw *scaleDraw ) { if ( scaleDraw == NULL ) return; if ( scaleDraw != d_data->scaleDraw ) delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( plt->axisScaleDiv( xAxis() ), plt->axisScaleDiv( yAxis() ) ); } itemChanged(); } /*! \return Scale draw \sa setScaleDraw() */ const QwtScaleDraw *QwtPlotScaleItem::scaleDraw() const { return d_data->scaleDraw; } /*! \return Scale draw \sa setScaleDraw() */ QwtScaleDraw *QwtPlotScaleItem::scaleDraw() { return d_data->scaleDraw; } /*! Change the position of the scale The position is interpreted as y value for horizontal axes and as x value for vertical axes. The border distance is set to -1. \param pos New position \sa position(), setAlignment() */ void QwtPlotScaleItem::setPosition( double pos ) { if ( d_data->position != pos ) { d_data->position = pos; d_data->borderDistance = -1; itemChanged(); } } /*! \return Position of the scale \sa setPosition(), setAlignment() */ double QwtPlotScaleItem::position() const { return d_data->position; } /*! \brief Align the scale to the canvas If distance is >= 0 the scale will be aligned to a border of the contents rectangle of the canvas. If alignment() is QwtScaleDraw::LeftScale, the scale will be aligned to the right border, if it is QwtScaleDraw::TopScale it will be aligned to the bottom (and vice versa), If distance is < 0 the scale will be at the position(). \param distance Number of pixels between the canvas border and the backbone of the scale. \sa setPosition(), borderDistance() */ void QwtPlotScaleItem::setBorderDistance( int distance ) { if ( distance < 0 ) distance = -1; if ( distance != d_data->borderDistance ) { d_data->borderDistance = distance; itemChanged(); } } /*! \return Distance from a canvas border \sa setBorderDistance(), setPosition() */ int QwtPlotScaleItem::borderDistance() const { return d_data->borderDistance; } /*! Change the alignment of the scale The alignment sets the orientation of the scale and the position of the ticks: - QwtScaleDraw::BottomScale: horizontal, ticks below - QwtScaleDraw::TopScale: horizontal, ticks above - QwtScaleDraw::LeftScale: vertical, ticks left - QwtScaleDraw::RightScale: vertical, ticks right For horizontal scales the position corresponds to QwtPlotItem::yAxis(), otherwise to QwtPlotItem::xAxis(). \sa scaleDraw(), QwtScaleDraw::alignment(), setPosition() */ void QwtPlotScaleItem::setAlignment( QwtScaleDraw::Alignment alignment ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->alignment() != alignment ) { sd->setAlignment( alignment ); itemChanged(); } } /*! \brief Draw the scale */ void QwtPlotScaleItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( d_data->scaleDivFromAxis ) { if ( canvasRect != d_data->canvasRectCache ) { d_data->updateBorders( canvasRect, xMap, yMap ); d_data->canvasRectCache = canvasRect; } } QPen pen = painter->pen(); pen.setStyle( Qt::SolidLine ); painter->setPen( pen ); QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->orientation() == Qt::Horizontal ) { double y; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::BottomScale ) y = canvasRect.top() + d_data->borderDistance; else { y = canvasRect.bottom() - d_data->borderDistance; } } else { y = yMap.transform( d_data->position ); } if ( y < canvasRect.top() || y > canvasRect.bottom() ) return; sd->move( canvasRect.left(), y ); sd->setLength( canvasRect.width() - 1 ); QwtTransform *transform = NULL; if ( xMap.transformation() ) transform = xMap.transformation()->copy(); sd->setTransformation( transform ); } else // == Qt::Vertical { double x; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::RightScale ) x = canvasRect.left() + d_data->borderDistance; else { x = canvasRect.right() - d_data->borderDistance; } } else { x = xMap.transform( d_data->position ); } if ( x < canvasRect.left() || x > canvasRect.right() ) return; sd->move( x, canvasRect.top() ); sd->setLength( canvasRect.height() - 1 ); QwtTransform *transform = NULL; if ( yMap.transformation() ) transform = yMap.transformation()->copy(); sd->setTransformation( transform ); } painter->setFont( d_data->font ); sd->draw( painter, d_data->palette ); } /*! \brief Update the item to changes of the axes scale division In case of isScaleDivFromAxis(), the scale draw is synchronized to the correspond axis. \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes() */ void QwtPlotScaleItem::updateScaleDiv( const QwtScaleDiv& xScaleDiv, const QwtScaleDiv& yScaleDiv ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( d_data->scaleDivFromAxis && sd ) { sd->setScaleDiv( sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv ); const QwtPlot *plt = plot(); if ( plt != NULL ) { d_data->updateBorders( plt->canvas()->contentsRect(), plt->canvasMap( xAxis() ), plt->canvasMap( yAxis() ) ); d_data->canvasRectCache = QRect(); } } } qsstv_8.2.12/qwt/qwt_plot_scaleitem.h000664 001750 001750 00000005062 12440612574 017661 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_SCALE_ITEM_H #define QWT_PLOT_SCALE_ITEM_H #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_scale_draw.h" class QPalette; /*! \brief A class which draws a scale inside the plot canvas QwtPlotScaleItem can be used to draw an axis inside the plot canvas. It might by synchronized to one of the axis of the plot, but can also display its own ticks and labels. It is allowed to synchronize the scale item with a disabled axis. In plots with vertical and horizontal scale items, it might be necessary to remove ticks at the intersections, by overloading updateScaleDiv(). The scale might be at a specific position (f.e 0.0) or it might be aligned to a canvas border. \par Example The following example shows how to replace the left axis, by a scale item at the x position 0.0. \verbatim QwtPlotScaleItem *scaleItem = new QwtPlotScaleItem(QwtScaleDraw::RightScale, 0.0); scaleItem->setFont(plot->axisWidget(QwtPlot::yLeft)->font()); scaleItem->attach(plot); plot->enableAxis(QwtPlot::yLeft, false); \endverbatim */ class QWT_EXPORT QwtPlotScaleItem: public QwtPlotItem { public: explicit QwtPlotScaleItem( QwtScaleDraw::Alignment = QwtScaleDraw::BottomScale, const double pos = 0.0 ); virtual ~QwtPlotScaleItem(); virtual int rtti() const; void setScaleDiv( const QwtScaleDiv& ); const QwtScaleDiv& scaleDiv() const; void setScaleDivFromAxis( bool on ); bool isScaleDivFromAxis() const; void setPalette( const QPalette & ); QPalette palette() const; void setFont( const QFont& ); QFont font() const; void setScaleDraw( QwtScaleDraw * ); const QwtScaleDraw *scaleDraw() const; QwtScaleDraw *scaleDraw(); void setPosition( double pos ); double position() const; void setBorderDistance( int numPixels ); int borderDistance() const; void setAlignment( QwtScaleDraw::Alignment ); virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; virtual void updateScaleDiv( const QwtScaleDiv &, const QwtScaleDiv & ); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_spline.cpp000664 001750 001750 00000020412 12440612574 016476 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_spline.h" #include "qwt_math.h" class QwtSpline::PrivateData { public: PrivateData(): splineType( QwtSpline::Natural ) { } QwtSpline::SplineType splineType; // coefficient vectors QVector a; QVector b; QVector c; // control points QPolygonF points; }; static int lookup( double x, const QPolygonF &values ) { #if 0 //qLowerBound/qHigherBound ??? #endif int i1; const int size = values.size(); if ( x <= values[0].x() ) i1 = 0; else if ( x >= values[size - 2].x() ) i1 = size - 2; else { i1 = 0; int i2 = size - 2; int i3 = 0; while ( i2 - i1 > 1 ) { i3 = i1 + ( ( i2 - i1 ) >> 1 ); if ( values[i3].x() > x ) i2 = i3; else i1 = i3; } } return i1; } //! Constructor QwtSpline::QwtSpline() { d_data = new PrivateData; } /*! Copy constructor \param other Spline used for initialization */ QwtSpline::QwtSpline( const QwtSpline& other ) { d_data = new PrivateData( *other.d_data ); } /*! Assignment operator \param other Spline used for initialization \return *this */ QwtSpline &QwtSpline::operator=( const QwtSpline & other ) { *d_data = *other.d_data; return *this; } //! Destructor QwtSpline::~QwtSpline() { delete d_data; } /*! Select the algorithm used for calculating the spline \param splineType Spline type \sa splineType() */ void QwtSpline::setSplineType( SplineType splineType ) { d_data->splineType = splineType; } /*! \return the spline type \sa setSplineType() */ QwtSpline::SplineType QwtSpline::splineType() const { return d_data->splineType; } /*! \brief Calculate the spline coefficients Depending on the value of \a periodic, this function will determine the coefficients for a natural or a periodic spline and store them internally. \param points Points \return true if successful \warning The sequence of x (but not y) values has to be strictly monotone increasing, which means points[i].x() < points[i+1].x(). If this is not the case, the function will return false */ bool QwtSpline::setPoints( const QPolygonF& points ) { const int size = points.size(); if ( size <= 2 ) { reset(); return false; } d_data->points = points; d_data->a.resize( size - 1 ); d_data->b.resize( size - 1 ); d_data->c.resize( size - 1 ); bool ok; if ( d_data->splineType == Periodic ) ok = buildPeriodicSpline( points ); else ok = buildNaturalSpline( points ); if ( !ok ) reset(); return ok; } /*! \return Points, that have been by setPoints() */ QPolygonF QwtSpline::points() const { return d_data->points; } //! \return A coefficients const QVector &QwtSpline::coefficientsA() const { return d_data->a; } //! \return B coefficients const QVector &QwtSpline::coefficientsB() const { return d_data->b; } //! \return C coefficients const QVector &QwtSpline::coefficientsC() const { return d_data->c; } //! Free allocated memory and set size to 0 void QwtSpline::reset() { d_data->a.resize( 0 ); d_data->b.resize( 0 ); d_data->c.resize( 0 ); d_data->points.resize( 0 ); } //! True if valid bool QwtSpline::isValid() const { return d_data->a.size() > 0; } /*! Calculate the interpolated function value corresponding to a given argument x. \param x Coordinate \return Interpolated coordinate */ double QwtSpline::value( double x ) const { if ( d_data->a.size() == 0 ) return 0.0; const int i = lookup( x, d_data->points ); const double delta = x - d_data->points[i].x(); return( ( ( ( d_data->a[i] * delta ) + d_data->b[i] ) * delta + d_data->c[i] ) * delta + d_data->points[i].y() ); } /*! \brief Determines the coefficients for a natural spline \return true if successful */ bool QwtSpline::buildNaturalSpline( const QPolygonF &points ) { int i; const QPointF *p = points.data(); const int size = points.size(); double *a = d_data->a.data(); double *b = d_data->b.data(); double *c = d_data->c.data(); // set up tridiagonal equation system; use coefficient // vectors as temporary buffers QVector h( size - 1 ); for ( i = 0; i < size - 1; i++ ) { h[i] = p[i+1].x() - p[i].x(); if ( h[i] <= 0 ) return false; } QVector d( size - 1 ); double dy1 = ( p[1].y() - p[0].y() ) / h[0]; for ( i = 1; i < size - 1; i++ ) { b[i] = c[i] = h[i]; a[i] = 2.0 * ( h[i-1] + h[i] ); const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i]; d[i] = 6.0 * ( dy1 - dy2 ); dy1 = dy2; } // // solve it // // L-U Factorization for ( i = 1; i < size - 2; i++ ) { c[i] /= a[i]; a[i+1] -= b[i] * c[i]; } // forward elimination QVector s( size ); s[1] = d[1]; for ( i = 2; i < size - 1; i++ ) s[i] = d[i] - c[i-1] * s[i-1]; // backward elimination s[size - 2] = - s[size - 2] / a[size - 2]; for ( i = size - 3; i > 0; i-- ) s[i] = - ( s[i] + b[i] * s[i+1] ) / a[i]; s[size - 1] = s[0] = 0.0; // // Finally, determine the spline coefficients // for ( i = 0; i < size - 1; i++ ) { a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] ); b[i] = 0.5 * s[i]; c[i] = ( p[i+1].y() - p[i].y() ) / h[i] - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0; } return true; } /*! \brief Determines the coefficients for a periodic spline \return true if successful */ bool QwtSpline::buildPeriodicSpline( const QPolygonF &points ) { int i; const QPointF *p = points.data(); const int size = points.size(); double *a = d_data->a.data(); double *b = d_data->b.data(); double *c = d_data->c.data(); QVector d( size - 1 ); QVector h( size - 1 ); QVector s( size ); // // setup equation system; use coefficient // vectors as temporary buffers // for ( i = 0; i < size - 1; i++ ) { h[i] = p[i+1].x() - p[i].x(); if ( h[i] <= 0.0 ) return false; } const int imax = size - 2; double htmp = h[imax]; double dy1 = ( p[0].y() - p[imax].y() ) / htmp; for ( i = 0; i <= imax; i++ ) { b[i] = c[i] = h[i]; a[i] = 2.0 * ( htmp + h[i] ); const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i]; d[i] = 6.0 * ( dy1 - dy2 ); dy1 = dy2; htmp = h[i]; } // // solve it // // L-U Factorization a[0] = qSqrt( a[0] ); c[0] = h[imax] / a[0]; double sum = 0; for ( i = 0; i < imax - 1; i++ ) { b[i] /= a[i]; if ( i > 0 ) c[i] = - c[i-1] * b[i-1] / a[i]; a[i+1] = qSqrt( a[i+1] - qwtSqr( b[i] ) ); sum += qwtSqr( c[i] ); } b[imax-1] = ( b[imax-1] - c[imax-2] * b[imax-2] ) / a[imax-1]; a[imax] = qSqrt( a[imax] - qwtSqr( b[imax-1] ) - sum ); // forward elimination s[0] = d[0] / a[0]; sum = 0; for ( i = 1; i < imax; i++ ) { s[i] = ( d[i] - b[i-1] * s[i-1] ) / a[i]; sum += c[i-1] * s[i-1]; } s[imax] = ( d[imax] - b[imax-1] * s[imax-1] - sum ) / a[imax]; // backward elimination s[imax] = - s[imax] / a[imax]; s[imax-1] = -( s[imax-1] + b[imax-1] * s[imax] ) / a[imax-1]; for ( i = imax - 2; i >= 0; i-- ) s[i] = - ( s[i] + b[i] * s[i+1] + c[i] * s[imax] ) / a[i]; // // Finally, determine the spline coefficients // s[size-1] = s[0]; for ( i = 0; i < size - 1; i++ ) { a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] ); b[i] = 0.5 * s[i]; c[i] = ( p[i+1].y() - p[i].y() ) / h[i] - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0; } return true; } qsstv_8.2.12/qwt/qwt_plot_seriesitem.cpp000664 001750 001750 00000005024 12440612574 020415 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_seriesitem.h" class QwtPlotSeriesItem::PrivateData { public: PrivateData(): orientation( Qt::Vertical ) { } Qt::Orientation orientation; }; /*! Constructor \param title Title of the curve */ QwtPlotSeriesItem::QwtPlotSeriesItem( const QwtText &title ): QwtPlotItem( title ) { d_data = new PrivateData(); setItemInterest( QwtPlotItem::ScaleInterest, true ); } /*! Constructor \param title Title of the curve */ QwtPlotSeriesItem::QwtPlotSeriesItem( const QString &title ): QwtPlotItem( QwtText( title ) ) { d_data = new PrivateData(); } //! Destructor QwtPlotSeriesItem::~QwtPlotSeriesItem() { delete d_data; } /*! Set the orientation of the item. The orientation() might be used in specific way by a plot item. F.e. a QwtPlotCurve uses it to identify how to display the curve int QwtPlotCurve::Steps or QwtPlotCurve::Sticks style. \sa orientation() */ void QwtPlotSeriesItem::setOrientation( Qt::Orientation orientation ) { if ( d_data->orientation != orientation ) { d_data->orientation = orientation; legendChanged(); itemChanged(); } } /*! \return Orientation of the plot item \sa setOrientation() */ Qt::Orientation QwtPlotSeriesItem::orientation() const { return d_data->orientation; } /*! \brief Draw the complete series \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas */ void QwtPlotSeriesItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { drawSeries( painter, xMap, yMap, canvasRect, 0, -1 ); } QRectF QwtPlotSeriesItem::boundingRect() const { return dataRect(); } void QwtPlotSeriesItem::updateScaleDiv( const QwtScaleDiv &xScaleDiv, const QwtScaleDiv &yScaleDiv ) { const QRectF rect = QRectF( xScaleDiv.lowerBound(), yScaleDiv.lowerBound(), xScaleDiv.range(), yScaleDiv.range() ); setRectOfInterest( rect ); } void QwtPlotSeriesItem::dataChanged() { itemChanged(); } qsstv_8.2.12/qwt/qwt_plot_seriesitem.h000664 001750 001750 00000003704 12440612574 020065 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_SERIES_ITEM_H #define QWT_PLOT_SERIES_ITEM_H #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_scale_div.h" #include "qwt_series_data.h" #include "qwt_series_store.h" /*! \brief Base class for plot items representing a series of samples */ class QWT_EXPORT QwtPlotSeriesItem: public QwtPlotItem, public virtual QwtAbstractSeriesStore { public: explicit QwtPlotSeriesItem( const QString &title = QString::null ); explicit QwtPlotSeriesItem( const QwtText &title ); virtual ~QwtPlotSeriesItem(); void setOrientation( Qt::Orientation ); Qt::Orientation orientation() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF & ) const; /*! Draw a subset of the samples \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. */ virtual void drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const = 0; virtual QRectF boundingRect() const; virtual void updateScaleDiv( const QwtScaleDiv &, const QwtScaleDiv & ); protected: virtual void dataChanged(); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_symbol.cpp000664 001750 001750 00000120377 12440612574 016524 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt.h" #include "qwt_symbol.h" #include "qwt_painter.h" #include "qwt_graphic.h" #include #include #include #include #include #include namespace QwtTriangle { enum Type { Left, Right, Up, Down }; } static QwtGraphic qwtPathGraphic( const QPainterPath &path, const QPen &pen, const QBrush& brush ) { QwtGraphic graphic; graphic.setRenderHint( QwtGraphic::RenderPensUnscaled ); QPainter painter( &graphic ); painter.setPen( pen ); painter.setBrush( brush ); painter.drawPath( path ); painter.end(); return graphic; } static inline QRectF qwtScaledBoundingRect( const QwtGraphic &graphic, const QSizeF size ) { QSizeF scaledSize = size; if ( scaledSize.isEmpty() ) scaledSize = graphic.defaultSize(); const QSizeF sz = graphic.controlPointRect().size(); double sx = 1.0; if ( sz.width() > 0.0 ) sx = scaledSize.width() / sz.width(); double sy = 1.0; if ( sz.height() > 0.0 ) sy = scaledSize.height() / sz.height(); return graphic.scaledBoundingRect( sx, sy ); } static inline void qwtDrawPixmapSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { QSize size = symbol.size(); if ( size.isEmpty() ) size = symbol.pixmap().size(); const QTransform transform = painter->transform(); if ( transform.isScaling() ) { const QRect r( 0, 0, size.width(), size.height() ); size = transform.mapRect( r ).size(); } QPixmap pm = symbol.pixmap(); if ( pm.size() != size ) pm = pm.scaled( size ); QPointF pinPoint( 0.5 * size.width(), 0.5 * size.height() ); if ( symbol.isPinPointEnabled() ) pinPoint = symbol.pinPoint(); painter->resetTransform(); for ( int i = 0; i < numPoints; i++ ) { const QPointF pos = transform.map( points[i] ) - pinPoint; QwtPainter::drawPixmap( painter, QRect( pos.toPoint(), pm.size() ), pm ); } } static inline void qwtDrawGraphicSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtGraphic &graphic, const QwtSymbol &symbol ) { const QRectF pointRect = graphic.controlPointRect(); if ( pointRect.isEmpty() ) return; double sx = 1.0; double sy = 1.0; const QSize sz = symbol.size(); if ( sz.isValid() ) { sx = sz.width() / pointRect.width(); sy = sz.height() / pointRect.height(); } QPointF pinPoint = pointRect.center(); if ( symbol.isPinPointEnabled() ) pinPoint = symbol.pinPoint(); const QTransform transform = painter->transform(); for ( int i = 0; i < numPoints; i++ ) { QTransform tr = transform; tr.translate( points[i].x(), points[i].y() ); tr.scale( sx, sy ); tr.translate( -pinPoint.x(), -pinPoint.y() ); painter->setTransform( tr ); graphic.render( painter ); } painter->setTransform( transform ); } static inline void qwtDrawEllipseSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { painter->setBrush( symbol.brush() ); painter->setPen( symbol.pen() ); const QSize size = symbol.size(); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawEllipse( painter, r ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const double x = points[i].x(); const double y = points[i].y(); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawEllipse( painter, r ); } } } static inline void qwtDrawRectSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); painter->setRenderHint( QPainter::Antialiasing, false ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const QRect r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawRect( painter, r ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const double x = points[i].x(); const double y = points[i].y(); const QRectF r( x - sw2, y - sh2, sw, sh ); QwtPainter::drawRect( painter, r ); } } } static inline void qwtDrawDiamondSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); if ( QwtPainter::roundingAlignment( painter ) ) { for ( int i = 0; i < numPoints; i++ ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ); const int x1 = x - size.width() / 2; const int y1 = y - size.height() / 2; const int x2 = x1 + size.width(); const int y2 = y1 + size.height(); QPolygonF polygon; polygon += QPointF( x, y1 ); polygon += QPointF( x1, y ); polygon += QPointF( x, y2 ); polygon += QPointF( x2, y ); QwtPainter::drawPolygon( painter, polygon ); } } else { for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const double x1 = pos.x() - 0.5 * size.width(); const double y1 = pos.y() - 0.5 * size.height(); const double x2 = x1 + size.width(); const double y2 = y1 + size.height(); QPolygonF polygon; polygon += QPointF( pos.x(), y1 ); polygon += QPointF( x2, pos.y() ); polygon += QPointF( pos.x(), y2 ); polygon += QPointF( x1, pos.y() ); QwtPainter::drawPolygon( painter, polygon ); } } } static inline void qwtDrawTriangleSymbols( QPainter *painter, QwtTriangle::Type type, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); QPen pen = symbol.pen(); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const bool doAlign = QwtPainter::roundingAlignment( painter ); double sw2 = 0.5 * size.width(); double sh2 = 0.5 * size.height(); if ( doAlign ) { sw2 = qFloor( sw2 ); sh2 = qFloor( sh2 ); } QPolygonF triangle( 3 ); QPointF *trianglePoints = triangle.data(); for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; double x = pos.x(); double y = pos.y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } const double x1 = x - sw2; const double x2 = x1 + size.width(); const double y1 = y - sh2; const double y2 = y1 + size.height(); switch ( type ) { case QwtTriangle::Left: { trianglePoints[0].rx() = x2; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x1; trianglePoints[1].ry() = y; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Right: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x2; trianglePoints[1].ry() = y; trianglePoints[2].rx() = x1; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Up: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y2; trianglePoints[1].rx() = x; trianglePoints[1].ry() = y1; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y2; break; } case QwtTriangle::Down: { trianglePoints[0].rx() = x1; trianglePoints[0].ry() = y1; trianglePoints[1].rx() = x; trianglePoints[1].ry() = y2; trianglePoints[2].rx() = x2; trianglePoints[2].ry() = y1; break; } } QwtPainter::drawPolygon( painter, triangle ); } } static inline void qwtDrawLineSymbols( QPainter *painter, int orientations, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); int off = 0; QPen pen = symbol.pen(); if ( pen.width() > 1 ) { pen.setCapStyle( Qt::FlatCap ); off = 1; } painter->setPen( pen ); painter->setRenderHint( QPainter::Antialiasing, false ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = qFloor( size.width() ); const int sh = qFloor( size.height() ); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { if ( orientations & Qt::Horizontal ) { const int x = qRound( points[i].x() ) - sw2; const int y = qRound( points[i].y() ); QwtPainter::drawLine( painter, x, y, x + sw + off, y ); } if ( orientations & Qt::Vertical ) { const int x = qRound( points[i].x() ); const int y = qRound( points[i].y() ) - sh2; QwtPainter::drawLine( painter, x, y, x, y + sh + off ); } } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { if ( orientations & Qt::Horizontal ) { const double x = points[i].x() - sw2; const double y = points[i].y(); QwtPainter::drawLine( painter, x, y, x + sw, y ); } if ( orientations & Qt::Vertical ) { const double y = points[i].y() - sh2; const double x = points[i].x(); QwtPainter::drawLine( painter, x, y, x, y + sh ); } } } } static inline void qwtDrawXCrossSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); int off = 0; QPen pen = symbol.pen(); if ( pen.width() > 1 ) { pen.setCapStyle( Qt::FlatCap ); off = 1; } painter->setPen( pen ); if ( QwtPainter::roundingAlignment( painter ) ) { const int sw = size.width(); const int sh = size.height(); const int sw2 = size.width() / 2; const int sh2 = size.height() / 2; for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const int x = qRound( pos.x() ); const int y = qRound( pos.y() ); const int x1 = x - sw2; const int x2 = x1 + sw + off; const int y1 = y - sh2; const int y2 = y1 + sh + off; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); QwtPainter::drawLine( painter, x2, y1, x1, y2 ); } } else { const double sw = size.width(); const double sh = size.height(); const double sw2 = 0.5 * size.width(); const double sh2 = 0.5 * size.height(); for ( int i = 0; i < numPoints; i++ ) { const QPointF &pos = points[i]; const double x1 = pos.x() - sw2; const double x2 = x1 + sw; const double y1 = pos.y() - sh2; const double y2 = y1 + sh; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); QwtPainter::drawLine( painter, x1, y2, x2, y1 ); } } } static inline void qwtDrawStar1Symbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { const QSize size = symbol.size(); painter->setPen( symbol.pen() ); if ( QwtPainter::roundingAlignment( painter ) ) { QRect r( 0, 0, size.width(), size.height() ); for ( int i = 0; i < numPoints; i++ ) { r.moveCenter( points[i].toPoint() ); const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */ const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 ); QwtPainter::drawLine( painter, qRound( r.left() + d1 ), qRound( r.top() + d1 ), qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) ); QwtPainter::drawLine( painter, qRound( r.left() + d1 ), qRound( r.bottom() - d1 ), qRound( r .right() - d1), qRound( r.top() + d1 ) ); const QPoint c = r.center(); QwtPainter::drawLine( painter, c.x(), r.top(), c.x(), r.bottom() ); QwtPainter::drawLine( painter, r.left(), c.y(), r.right(), c.y() ); } } else { QRectF r( 0, 0, size.width(), size.height() ); for ( int i = 0; i < numPoints; i++ ) { r.moveCenter( points[i] ); const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */ const QPointF c = r.center(); const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 ); QwtPainter::drawLine( painter, r.left() + d1, r.top() + d1, r.right() - d1, r.bottom() - d1 ); QwtPainter::drawLine( painter, r.left() + d1, r.bottom() - d1, r.right() - d1, r.top() + d1 ); QwtPainter::drawLine( painter, c.x(), r.top(), c.x(), r.bottom() ); QwtPainter::drawLine( painter, r.left(), c.y(), r.right(), c.y() ); } } } static inline void qwtDrawStar2Symbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { QPen pen = symbol.pen(); if ( pen.width() > 1 ) pen.setCapStyle( Qt::FlatCap ); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const double cos30 = 0.866025; // cos(30°) const double dy = 0.25 * symbol.size().height(); const double dx = 0.5 * symbol.size().width() * cos30 / 3.0; QPolygonF star( 12 ); QPointF *starPoints = star.data(); const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < numPoints; i++ ) { double x = points[i].x(); double y = points[i].y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } double x1 = x - 3 * dx; double y1 = y - 2 * dy; if ( doAlign ) { x1 = qRound( x - 3 * dx ); y1 = qRound( y - 2 * dy ); } const double x2 = x1 + 1 * dx; const double x3 = x1 + 2 * dx; const double x4 = x1 + 3 * dx; const double x5 = x1 + 4 * dx; const double x6 = x1 + 5 * dx; const double x7 = x1 + 6 * dx; const double y2 = y1 + 1 * dy; const double y3 = y1 + 2 * dy; const double y4 = y1 + 3 * dy; const double y5 = y1 + 4 * dy; starPoints[0].rx() = x4; starPoints[0].ry() = y1; starPoints[1].rx() = x5; starPoints[1].ry() = y2; starPoints[2].rx() = x7; starPoints[2].ry() = y2; starPoints[3].rx() = x6; starPoints[3].ry() = y3; starPoints[4].rx() = x7; starPoints[4].ry() = y4; starPoints[5].rx() = x5; starPoints[5].ry() = y4; starPoints[6].rx() = x4; starPoints[6].ry() = y5; starPoints[7].rx() = x3; starPoints[7].ry() = y4; starPoints[8].rx() = x1; starPoints[8].ry() = y4; starPoints[9].rx() = x2; starPoints[9].ry() = y3; starPoints[10].rx() = x1; starPoints[10].ry() = y2; starPoints[11].rx() = x3; starPoints[11].ry() = y2; QwtPainter::drawPolygon( painter, star ); } } static inline void qwtDrawHexagonSymbols( QPainter *painter, const QPointF *points, int numPoints, const QwtSymbol &symbol ) { painter->setBrush( symbol.brush() ); painter->setPen( symbol.pen() ); const double cos30 = 0.866025; // cos(30°) const double dx = 0.5 * ( symbol.size().width() - cos30 ); const double dy = 0.25 * symbol.size().height(); QPolygonF hexaPolygon( 6 ); QPointF *hexaPoints = hexaPolygon.data(); const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < numPoints; i++ ) { double x = points[i].x(); double y = points[i].y(); if ( doAlign ) { x = qRound( x ); y = qRound( y ); } double x1 = x - dx; double y1 = y - 2 * dy; if ( doAlign ) { x1 = qCeil( x1 ); y1 = qCeil( y1 ); } const double x2 = x1 + 1 * dx; const double x3 = x1 + 2 * dx; const double y2 = y1 + 1 * dy; const double y3 = y1 + 3 * dy; const double y4 = y1 + 4 * dy; hexaPoints[0].rx() = x2; hexaPoints[0].ry() = y1; hexaPoints[1].rx() = x3; hexaPoints[1].ry() = y2; hexaPoints[2].rx() = x3; hexaPoints[2].ry() = y3; hexaPoints[3].rx() = x2; hexaPoints[3].ry() = y4; hexaPoints[4].rx() = x1; hexaPoints[4].ry() = y3; hexaPoints[5].rx() = x1; hexaPoints[5].ry() = y2; QwtPainter::drawPolygon( painter, hexaPolygon ); } } class QwtSymbol::PrivateData { public: PrivateData( QwtSymbol::Style st, const QBrush &br, const QPen &pn, const QSize &sz ): style( st ), size( sz ), brush( br ), pen( pn ), isPinPointEnabled( false ) { cache.policy = QwtSymbol::AutoCache; } ~PrivateData() { } Style style; QSize size; QBrush brush; QPen pen; bool isPinPointEnabled; QPointF pinPoint; struct Path { QPainterPath path; QwtGraphic graphic; } path; struct Pixmap { QPixmap pixmap; } pixmap; struct Graphic { QwtGraphic graphic; } graphic; struct PaintCache { QwtSymbol::CachePolicy policy; QPixmap pixmap; } cache; }; /*! Default Constructor \param style Symbol Style The symbol is constructed with gray interior, black outline with zero width, no size and style 'NoSymbol'. */ QwtSymbol::QwtSymbol( Style style ) { d_data = new PrivateData( style, QBrush( Qt::gray ), QPen( Qt::black, 0 ), QSize() ); } /*! \brief Constructor \param style Symbol Style \param brush brush to fill the interior \param pen outline pen \param size size \sa setStyle(), setBrush(), setPen(), setSize() */ QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush &brush, const QPen &pen, const QSize &size ) { d_data = new PrivateData( style, brush, pen, size ); } /*! \brief Constructor The symbol gets initialized by a painter path. The style is set to QwtSymbol::Path, the size is set to empty ( the path is displayed unscaled ). \param path painter path \param brush brush to fill the interior \param pen outline pen \sa setPath(), setBrush(), setPen(), setSize() */ QwtSymbol::QwtSymbol( const QPainterPath &path, const QBrush &brush, const QPen &pen ) { d_data = new PrivateData( QwtSymbol::Path, brush, pen, QSize() ); setPath( path ); } //! Destructor QwtSymbol::~QwtSymbol() { delete d_data; } /*! Change the cache policy The default policy is AutoCache \param policy Cache policy \sa CachePolicy, cachePolicy() */ void QwtSymbol::setCachePolicy( QwtSymbol::CachePolicy policy ) { if ( d_data->cache.policy != policy ) { d_data->cache.policy = policy; invalidateCache(); } } /*! \return Cache policy \sa CachePolicy, setCachePolicy() */ QwtSymbol::CachePolicy QwtSymbol::cachePolicy() const { return d_data->cache.policy; } /*! \brief Set a painter path as symbol The symbol is represented by a painter path, where the origin ( 0, 0 ) of the path coordinate system is mapped to the position of the symbol. When the symbol has valid size the painter path gets scaled to fit into the size. Otherwise the symbol size depends on the bounding rectangle of the path. The following code defines a symbol drawing an arrow: \verbatim #include QwtSymbol *symbol = new QwtSymbol(); QPen pen( Qt::black, 2 ); pen.setJoinStyle( Qt::MiterJoin ); symbol->setPen( pen ); symbol->setBrush( Qt::red ); QPainterPath path; path.moveTo( 0, 8 ); path.lineTo( 0, 5 ); path.lineTo( -3, 5 ); path.lineTo( 0, 0 ); path.lineTo( 3, 5 ); path.lineTo( 0, 5 ); QTransform transform; transform.rotate( -30.0 ); path = transform.map( path ); symbol->setPath( path ); symbol->setPinPoint( QPointF( 0.0, 0.0 ) ); setSize( 10, 14 ); \endverbatim \param path Painter path \note The style is implicitely set to QwtSymbol::Path. \sa path(), setSize() */ void QwtSymbol::setPath( const QPainterPath &path ) { d_data->style = QwtSymbol::Path; d_data->path.path = path; d_data->path.graphic.reset(); } /*! \return Painter path for displaying the symbol \sa setPath() */ const QPainterPath &QwtSymbol::path() const { return d_data->path.path; } /*! Set a pixmap as symbol \param pixmap Pixmap \sa pixmap(), setGraphic() \note the style() is set to QwtSymbol::Pixmap \note brush() and pen() have no effect */ void QwtSymbol::setPixmap( const QPixmap &pixmap ) { d_data->style = QwtSymbol::Pixmap; d_data->pixmap.pixmap = pixmap; } /*! \return Assigned pixmap \sa setPixmap() */ const QPixmap &QwtSymbol::pixmap() const { return d_data->pixmap.pixmap; } /*! Set a graphic as symbol \param graphic Graphic \sa graphic(), setPixmap() \note the style() is set to QwtSymbol::Graphic \note brush() and pen() have no effect */ void QwtSymbol::setGraphic( const QwtGraphic &graphic ) { d_data->style = QwtSymbol::Graphic; d_data->graphic.graphic = graphic; } /*! \return Assigned graphic \sa setGraphic() */ const QwtGraphic &QwtSymbol::graphic() const { return d_data->graphic.graphic; } /*! \brief Specify the symbol's size If the 'h' parameter is left out or less than 0, and the 'w' parameter is greater than or equal to 0, the symbol size will be set to (w,w). \param width Width \param height Height (defaults to -1) \sa size() */ void QwtSymbol::setSize( int width, int height ) { if ( ( width >= 0 ) && ( height < 0 ) ) height = width; setSize( QSize( width, height ) ); } /*! Set the symbol's size \param size Size \sa size() */ void QwtSymbol::setSize( const QSize &size ) { if ( size.isValid() && size != d_data->size ) { d_data->size = size; invalidateCache(); } } /*! \return Size \sa setSize() */ const QSize& QwtSymbol::size() const { return d_data->size; } /*! \brief Assign a brush The brush is used to draw the interior of the symbol. \param brush Brush \sa brush() */ void QwtSymbol::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; invalidateCache(); if ( d_data->style == QwtSymbol::Path ) d_data->path.graphic.reset(); } } /*! \return Brush \sa setBrush() */ const QBrush& QwtSymbol::brush() const { return d_data->brush; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtSymbol::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! Assign a pen The pen is used to draw the symbol's outline. \param pen Pen \sa pen(), setBrush() */ void QwtSymbol::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; invalidateCache(); if ( d_data->style == QwtSymbol::Path ) d_data->path.graphic.reset(); } } /*! \return Pen \sa setPen(), brush() */ const QPen& QwtSymbol::pen() const { return d_data->pen; } /*! \brief Set the color of the symbol Change the color of the brush for symbol types with a filled area. For all other symbol types the color will be assigned to the pen. \param color Color \sa setBrush(), setPen(), brush(), pen() */ void QwtSymbol::setColor( const QColor &color ) { switch ( d_data->style ) { case QwtSymbol::Ellipse: case QwtSymbol::Rect: case QwtSymbol::Diamond: case QwtSymbol::Triangle: case QwtSymbol::UTriangle: case QwtSymbol::DTriangle: case QwtSymbol::RTriangle: case QwtSymbol::LTriangle: case QwtSymbol::Star2: case QwtSymbol::Hexagon: { if ( d_data->brush.color() != color ) { d_data->brush.setColor( color ); invalidateCache(); } break; } case QwtSymbol::Cross: case QwtSymbol::XCross: case QwtSymbol::HLine: case QwtSymbol::VLine: case QwtSymbol::Star1: { if ( d_data->pen.color() != color ) { d_data->pen.setColor( color ); invalidateCache(); } break; } default: { if ( d_data->brush.color() != color || d_data->pen.color() != color ) { invalidateCache(); } d_data->brush.setColor( color ); d_data->pen.setColor( color ); } } } /*! \brief Set and enable a pin point The position of a complex symbol is not always aligned to its center ( f.e an arrow, where the peak points to a position ). The pin point defines the position inside of a Pixmap, Graphic, SvgDocument or PainterPath symbol where the represented point has to be aligned to. \param pos Position \param enable En/Disable the pin point alignment \sa pinPoint(), setPinPointEnabled() */ void QwtSymbol::setPinPoint( const QPointF &pos, bool enable ) { if ( d_data->pinPoint != pos ) { d_data->pinPoint = pos; if ( d_data->isPinPointEnabled ) { invalidateCache(); } } setPinPointEnabled( enable ); } /*! \return Pin point \sa setPinPoint(), setPinPointEnabled() */ QPointF QwtSymbol::pinPoint() const { return d_data->pinPoint; } /*! En/Disable the pin point alignment \param on Enabled, when on is true \sa setPinPoint(), isPinPointEnabled() */ void QwtSymbol::setPinPointEnabled( bool on ) { if ( d_data->isPinPointEnabled != on ) { d_data->isPinPointEnabled = on; invalidateCache(); } } /*! \return True, when the pin point translation is enabled \sa setPinPoint(), setPinPointEnabled() */ bool QwtSymbol::isPinPointEnabled() const { return d_data->isPinPointEnabled; } /*! Render an array of symbols Painting several symbols is more effective than drawing symbols one by one, as a couple of layout calculations and setting of pen/brush can be done once for the complete array. \param painter Painter \param points Array of points \param numPoints Number of points */ void QwtSymbol::drawSymbols( QPainter *painter, const QPointF *points, int numPoints ) const { if ( numPoints <= 0 ) return; bool useCache = false; // Don't use the pixmap, when the paint device // could generate scalable vectors if ( QwtPainter::roundingAlignment( painter ) && !painter->transform().isScaling() ) { if ( d_data->cache.policy == QwtSymbol::Cache ) { useCache = true; } else if ( d_data->cache.policy == QwtSymbol::AutoCache ) { if ( painter->paintEngine()->type() == QPaintEngine::Raster ) { useCache = true; } else { switch( d_data->style ) { case QwtSymbol::XCross: case QwtSymbol::HLine: case QwtSymbol::VLine: case QwtSymbol::Cross: break; case QwtSymbol::Pixmap: { if ( !d_data->size.isEmpty() && d_data->size != d_data->pixmap.pixmap.size() ) { useCache = true; } break; } default: useCache = true; } } } } if ( useCache ) { const QRect br = boundingRect(); const QRect rect( 0, 0, br.width(), br.height() ); if ( d_data->cache.pixmap.isNull() ) { d_data->cache.pixmap = QwtPainter::backingStore( NULL, br.size() ); d_data->cache.pixmap.fill( Qt::transparent ); QPainter p( &d_data->cache.pixmap ); p.setRenderHints( painter->renderHints() ); p.translate( -br.topLeft() ); const QPointF pos; renderSymbols( &p, &pos, 1 ); } const int dx = br.left(); const int dy = br.top(); for ( int i = 0; i < numPoints; i++ ) { const int left = qRound( points[i].x() ) + dx; const int top = qRound( points[i].y() ) + dy; painter->drawPixmap( left, top, d_data->cache.pixmap ); } } else { painter->save(); renderSymbols( painter, points, numPoints ); painter->restore(); } } /*! \brief Draw the symbol into a rectangle The symbol is painted centered and scaled into the target rectangle. It is always painted uncached and the pin point is ignored. This method is primarily intended for drawing a symbol to the legend. \param painter Painter \param rect Target rectangle for the symbol */ void QwtSymbol::drawSymbol( QPainter *painter, const QRectF &rect ) const { if ( d_data->style == QwtSymbol::NoSymbol ) return; if ( d_data->style == QwtSymbol::Graphic ) { d_data->graphic.graphic.render( painter, rect, Qt::KeepAspectRatio ); } else if ( d_data->style == QwtSymbol::Path ) { if ( d_data->path.graphic.isNull() ) { d_data->path.graphic = qwtPathGraphic( d_data->path.path, d_data->pen, d_data->brush ); } d_data->path.graphic.render( painter, rect, Qt::KeepAspectRatio ); return; } else if ( d_data->style == QwtSymbol::SvgDocument ) { } else { const QRect br = boundingRect(); // scale the symbol size to fit into rect. const double ratio = qMin( rect.width() / br.width(), rect.height() / br.height() ); painter->save(); painter->translate( rect.center() ); painter->scale( ratio, ratio ); const bool isPinPointEnabled = d_data->isPinPointEnabled; d_data->isPinPointEnabled = false; const QPointF pos; renderSymbols( painter, &pos, 1 ); d_data->isPinPointEnabled = isPinPointEnabled; painter->restore(); } } /*! Render the symbol to series of points \param painter Qt painter \param points Positions of the symbols \param numPoints Number of points */ void QwtSymbol::renderSymbols( QPainter *painter, const QPointF *points, int numPoints ) const { switch ( d_data->style ) { case QwtSymbol::Ellipse: { qwtDrawEllipseSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Rect: { qwtDrawRectSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Diamond: { qwtDrawDiamondSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Cross: { qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical, points, numPoints, *this ); break; } case QwtSymbol::XCross: { qwtDrawXCrossSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Triangle: case QwtSymbol::UTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Up, points, numPoints, *this ); break; } case QwtSymbol::DTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Down, points, numPoints, *this ); break; } case QwtSymbol::RTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Right, points, numPoints, *this ); break; } case QwtSymbol::LTriangle: { qwtDrawTriangleSymbols( painter, QwtTriangle::Left, points, numPoints, *this ); break; } case QwtSymbol::HLine: { qwtDrawLineSymbols( painter, Qt::Horizontal, points, numPoints, *this ); break; } case QwtSymbol::VLine: { qwtDrawLineSymbols( painter, Qt::Vertical, points, numPoints, *this ); break; } case QwtSymbol::Star1: { qwtDrawStar1Symbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Star2: { qwtDrawStar2Symbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Hexagon: { qwtDrawHexagonSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Path: { if ( d_data->path.graphic.isNull() ) { d_data->path.graphic = qwtPathGraphic( d_data->path.path, d_data->pen, d_data->brush ); } qwtDrawGraphicSymbols( painter, points, numPoints, d_data->path.graphic, *this ); break; } case QwtSymbol::Pixmap: { qwtDrawPixmapSymbols( painter, points, numPoints, *this ); break; } case QwtSymbol::Graphic: { qwtDrawGraphicSymbols( painter, points, numPoints, d_data->graphic.graphic, *this ); break; } case QwtSymbol::SvgDocument: { break; } default:; } } /*! Calculate the bounding rectangle for a symbol at position (0,0). \return Bounding rectangle */ QRect QwtSymbol::boundingRect() const { QRectF rect; switch ( d_data->style ) { case QwtSymbol::Ellipse: case QwtSymbol::Rect: case QwtSymbol::Hexagon: { qreal pw = 0.0; if ( d_data->pen.style() != Qt::NoPen ) pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) ); rect.setSize( d_data->size + QSizeF( pw, pw ) ); rect.moveCenter( QPointF( 0.0, 0.0 ) ); break; } case QwtSymbol::XCross: case QwtSymbol::Diamond: case QwtSymbol::Triangle: case QwtSymbol::UTriangle: case QwtSymbol::DTriangle: case QwtSymbol::RTriangle: case QwtSymbol::LTriangle: case QwtSymbol::Star1: case QwtSymbol::Star2: { qreal pw = 0.0; if ( d_data->pen.style() != Qt::NoPen ) pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) ); rect.setSize( d_data->size + QSizeF( 2 * pw, 2 * pw ) ); rect.moveCenter( QPointF( 0.0, 0.0 ) ); break; } case QwtSymbol::Path: { if ( d_data->path.graphic.isNull() ) { d_data->path.graphic = qwtPathGraphic( d_data->path.path, d_data->pen, d_data->brush ); } rect = qwtScaledBoundingRect( d_data->path.graphic, d_data->size ); break; } case QwtSymbol::Pixmap: { if ( d_data->size.isEmpty() ) rect.setSize( d_data->pixmap.pixmap.size() ); else rect.setSize( d_data->size ); rect.moveCenter( QPointF( 0.0, 0.0 ) ); // pinpoint ??? break; } case QwtSymbol::Graphic: { rect = qwtScaledBoundingRect( d_data->graphic.graphic, d_data->size ); break; } default: { rect.setSize( d_data->size ); rect.moveCenter( QPointF( 0.0, 0.0 ) ); } } if ( d_data->style == QwtSymbol::Graphic || d_data->style == QwtSymbol::SvgDocument || d_data->style == QwtSymbol::Path ) { QPointF pinPoint( 0.0, 0.0 ); if ( d_data->isPinPointEnabled ) pinPoint = rect.center() - d_data->pinPoint; rect.moveCenter( pinPoint ); } QRect r; r.setLeft( qFloor( rect.left() ) ); r.setTop( qFloor( rect.top() ) ); r.setRight( qCeil( rect.right() ) ); r.setBottom( qCeil( rect.bottom() ) ); if ( d_data->style != QwtSymbol::Pixmap ) r.adjust( -1, -1, 1, 1 ); // for antialiasing return r; } /*! Invalidate the cached symbol pixmap The symbol invalidates its cache, whenever an attribute is changed that has an effect ob how to display a symbol. In case of derived classes with individual styles ( >= QwtSymbol::UserStyle ) it might be necessary to call invalidateCache() for attributes that are relevant for this style. \sa CachePolicy, setCachePolicy(), drawSymbols() */ void QwtSymbol::invalidateCache() { if ( !d_data->cache.pixmap.isNull() ) d_data->cache.pixmap = QPixmap(); } /*! Specify the symbol style \param style Style \sa style() */ void QwtSymbol::setStyle( QwtSymbol::Style style ) { if ( d_data->style != style ) { d_data->style = style; invalidateCache(); } } /*! \return Current symbol style \sa setStyle() */ QwtSymbol::Style QwtSymbol::style() const { return d_data->style; } qsstv_8.2.12/qwt/qwt_plot_shapeitem.cpp000664 001750 001750 00000026066 12440612574 020234 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_shapeitem.h" #include "qwt_scale_map.h" #include "qwt_painter.h" #include "qwt_curve_fitter.h" #include "qwt_clipper.h" static QPainterPath qwtTransformPath( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QPainterPath &path, bool doAlign ) { QPainterPath shape; shape.setFillRule( path.fillRule() ); for ( int i = 0; i < path.elementCount(); i++ ) { const QPainterPath::Element &element = path.elementAt( i ); double x = xMap.transform( element.x ); double y = yMap.transform( element.y ); switch( element.type ) { case QPainterPath::MoveToElement: { if ( doAlign ) { x = qRound( x ); y = qRound( y ); } shape.moveTo( x, y ); break; } case QPainterPath::LineToElement: { if ( doAlign ) { x = qRound( x ); y = qRound( y ); } shape.lineTo( x, y ); break; } case QPainterPath::CurveToElement: { const QPainterPath::Element& element1 = path.elementAt( ++i ); const double x1 = xMap.transform( element1.x ); const double y1 = yMap.transform( element1.y ); const QPainterPath::Element& element2 = path.elementAt( ++i ); const double x2 = xMap.transform( element2.x ); const double y2 = yMap.transform( element2.y ); shape.cubicTo( x, y, x1, y1, x2, y2 ); break; } case QPainterPath::CurveToDataElement: { break; } } } return shape; } class QwtPlotShapeItem::PrivateData { public: PrivateData(): legendMode( QwtPlotShapeItem::LegendColor ), renderTolerance( 0.0 ) { } QwtPlotShapeItem::PaintAttributes paintAttributes; QwtPlotShapeItem::LegendMode legendMode; double renderTolerance; QRectF boundingRect; QPen pen; QBrush brush; QPainterPath shape; }; /*! \brief Constructor Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false \param title Title */ QwtPlotShapeItem::QwtPlotShapeItem( const QString& title ): QwtPlotItem( QwtText( title ) ) { init(); } /*! \brief Constructor Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false \param title Title */ QwtPlotShapeItem::QwtPlotShapeItem( const QwtText& title ): QwtPlotItem( title ) { init(); } //! Destructor QwtPlotShapeItem::~QwtPlotShapeItem() { delete d_data; } void QwtPlotShapeItem::init() { d_data = new PrivateData(); d_data->boundingRect = QwtPlotItem::boundingRect(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 8.0 ); } //! \return QwtPlotItem::Rtti_PlotShape int QwtPlotShapeItem::rtti() const { return QwtPlotItem::Rtti_PlotShape; } /*! Specify an attribute how to draw the shape \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotShapeItem::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \return True, when attribute is enabled \sa setPaintAttribute() */ bool QwtPlotShapeItem::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Set the mode how to represent the item on the legend \param mode Mode \sa legendMode() */ void QwtPlotShapeItem::setLegendMode( LegendMode mode ) { if ( mode != d_data->legendMode ) { d_data->legendMode = mode; legendChanged(); } } /*! \return Mode how to represent the item on the legend \sa legendMode() */ QwtPlotShapeItem::LegendMode QwtPlotShapeItem::legendMode() const { return d_data->legendMode; } //! Bounding rectangle of the shape QRectF QwtPlotShapeItem::boundingRect() const { return d_data->boundingRect; } /*! \brief Set a path built from a rectangle \param rect Rectangle \sa setShape(), setPolygon(), shape() */ void QwtPlotShapeItem::setRect( const QRectF &rect ) { QPainterPath path; path.addRect( rect ); setShape( path ); } /*! \brief Set a path built from a polygon \param polygon Polygon \sa setShape(), setRect(), shape() */ void QwtPlotShapeItem::setPolygon( const QPolygonF &polygon ) { QPainterPath shape; shape.addPolygon( polygon ); setShape( shape ); } /*! \brief Set the shape to be displayed \param shape Shape \sa setShape(), shape() */ void QwtPlotShapeItem::setShape( const QPainterPath &shape ) { if ( shape != d_data->shape ) { d_data->shape = shape; if ( shape.isEmpty() ) { d_data->boundingRect = QwtPlotItem::boundingRect(); } else { d_data->boundingRect = shape.boundingRect(); } itemChanged(); } } /*! \return Shape to be displayed \sa setShape() */ QPainterPath QwtPlotShapeItem::shape() const { return d_data->shape; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotShapeItem::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! \brief Assign a pen The pen is used to draw the outline of the shape \param pen Pen \sa pen(), brush() */ void QwtPlotShapeItem::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; itemChanged(); } } /*! \return Pen used to draw the outline of the shape \sa setPen(), brush() */ QPen QwtPlotShapeItem::pen() const { return d_data->pen; } /*! Assign a brush. The brush is used to fill the path \param brush Brush \sa brush(), pen() */ void QwtPlotShapeItem::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; itemChanged(); } } /*! \return Brush used to fill the shape \sa setBrush(), pen() */ QBrush QwtPlotShapeItem::brush() const { return d_data->brush; } /*! \brief Set the tolerance for the weeding optimization After translating the shape into target device coordinate ( usually widget geometries ) the painter path can be simplified by a point weeding algorithm ( Douglas-Peucker ). For shapes built from curves and ellipses weeding might have the opposite effect because they have to be expanded to polygons. \param tolerance Accepted error when reducing the number of points A value <= 0.0 disables weeding. \sa renderTolerance(), QwtWeedingCurveFitter */ void QwtPlotShapeItem::setRenderTolerance( double tolerance ) { tolerance = qMax( tolerance, 0.0 ); if ( tolerance != d_data->renderTolerance ) { d_data->renderTolerance = tolerance; itemChanged(); } } /*! \return Tolerance for the weeding optimization \sa setRenderTolerance() */ double QwtPlotShapeItem::renderTolerance() const { return d_data->renderTolerance; } /*! Draw the shape item \param painter Painter \param xMap X-Scale Map \param yMap Y-Scale Map \param canvasRect Contents rect of the plot canvas */ void QwtPlotShapeItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( d_data->shape.isEmpty() ) return; if ( d_data->pen.style() == Qt::NoPen && d_data->brush.style() == Qt::NoBrush ) { return; } const QRectF cRect = QwtScaleMap::invTransform( xMap, yMap, canvasRect.toRect() ); if ( d_data->boundingRect.intersects( cRect ) ) { const bool doAlign = QwtPainter::roundingAlignment( painter ); QPainterPath path = qwtTransformPath( xMap, yMap, d_data->shape, doAlign ); if ( testPaintAttribute( QwtPlotShapeItem::ClipPolygons ) ) { qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF()); QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw ); QPainterPath clippedPath; clippedPath.setFillRule( path.fillRule() ); const QList polygons = path.toSubpathPolygons(); for ( int i = 0; i < polygons.size(); i++ ) { const QPolygonF p = QwtClipper::clipPolygonF( clipRect, polygons[i], true ); clippedPath.addPolygon( p ); } path = clippedPath; } if ( d_data->renderTolerance > 0.0 ) { QwtWeedingCurveFitter fitter( d_data->renderTolerance ); QPainterPath fittedPath; fittedPath.setFillRule( path.fillRule() ); const QList polygons = path.toSubpathPolygons(); for ( int i = 0; i < polygons.size(); i++ ) fittedPath.addPolygon( fitter.fitCurve( polygons[ i ] ) ); path = fittedPath; } painter->setPen( d_data->pen ); painter->setBrush( d_data->brush ); painter->drawPath( path ); } } /*! \return A rectangle filled with the color of the brush ( or the pen ) \param index Index of the legend entry ( usually there is only one ) \param size Icon size \sa setLegendIconSize(), legendData() */ QwtGraphic QwtPlotShapeItem::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ); QwtGraphic icon; icon.setDefaultSize( size ); if ( size.isEmpty() ) return icon; if ( d_data->legendMode == QwtPlotShapeItem::LegendShape ) { const QRectF &br = d_data->boundingRect; QPainter painter( &icon ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); painter.translate( -br.topLeft() ); painter.setPen( d_data->pen ); painter.setBrush( d_data->brush ); painter.drawPath( d_data->shape ); } else { QColor iconColor; if ( d_data->brush.style() != Qt::NoBrush ) iconColor = d_data->brush.color(); else iconColor = d_data->pen.color(); icon = defaultIcon( iconColor, size ); } return icon; } qsstv_8.2.12/qwt/qwt_plot_shapeitem.h000664 001750 001750 00000006304 12440612574 017672 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_SHAPE_ITEM_H #define QWT_PLOT_SHAPE_ITEM_H #include "qwt_global.h" #include "qwt_plot_item.h" #include /*! \brief A plot item, which displays any graphical shape, that can be defined by a QPainterPath A QPainterPath is a shape composed from intersecting and uniting regions, rectangles, ellipses or irregular areas defined by lines, and curves. QwtPlotShapeItem displays a shape with a pen and brush. QwtPlotShapeItem offers a couple of optimizations like clipping or weeding. These algorithms need to convert the painter path into polygons that might be less performant for paths built from curves and ellipses. \sa QwtPlotZone */ class QWT_EXPORT QwtPlotShapeItem: public QwtPlotItem { public: /*! Attributes to modify the drawing algorithm. The default disables all attributes \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance But polygon clipping will convert the painter path into polygons what might introduce a negative impact on the performance of paths composed from curves or ellipses. */ ClipPolygons = 0x01, }; //! Paint attributes typedef QFlags PaintAttributes; //! Mode how to display the item on the legend enum LegendMode { //! Display a scaled down version of the shape LegendShape, //! Display a filled rectangle LegendColor }; explicit QwtPlotShapeItem( const QString &title = QString::null ); explicit QwtPlotShapeItem( const QwtText &title ); virtual ~QwtPlotShapeItem(); void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setLegendMode( LegendMode ); LegendMode legendMode() const; void setRect( const QRectF & ); void setPolygon( const QPolygonF & ); void setShape( const QPainterPath & ); QPainterPath shape() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); QPen pen() const; void setBrush( const QBrush & ); QBrush brush() const; void setRenderTolerance( double ); double renderTolerance() const; virtual QRectF boundingRect() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; virtual int rtti() const; private: void init(); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_system_clock.cpp000664 001750 001750 00000017607 12440612574 017717 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_system_clock.h" #if QT_VERSION >= 0x040800 #define USE_ELAPSED_TIMER 1 #endif #if USE_ELAPSED_TIMER #include class QwtSystemClock::PrivateData { public: QElapsedTimer timer; }; QwtSystemClock::QwtSystemClock() { d_data = new PrivateData(); } QwtSystemClock::~QwtSystemClock() { delete d_data; } bool QwtSystemClock::isNull() const { return d_data->timer.isValid(); } void QwtSystemClock::start() { d_data->timer.start(); } double QwtSystemClock::restart() { const qint64 nsecs = d_data->timer.restart(); return nsecs / 1e6; } double QwtSystemClock::elapsed() const { const qint64 nsecs = d_data->timer.nsecsElapsed(); return nsecs / 1e6; } #else // !USE_ELAPSED_TIMER #include #if !defined(Q_OS_WIN) #include #endif #if defined(Q_OS_MAC) #include #include #define QWT_HIGH_RESOLUTION_CLOCK #elif defined(_POSIX_TIMERS) #include #define QWT_HIGH_RESOLUTION_CLOCK #elif defined(Q_OS_WIN) #define QWT_HIGH_RESOLUTION_CLOCK #include #endif #if defined(QWT_HIGH_RESOLUTION_CLOCK) class QwtHighResolutionClock { public: QwtHighResolutionClock(); void start(); double restart(); double elapsed() const; bool isNull() const; static double precision(); private: #if defined(Q_OS_MAC) static double msecsTo( uint64_t, uint64_t ); uint64_t d_timeStamp; #elif defined(_POSIX_TIMERS) static double msecsTo( const struct timespec &, const struct timespec & ); static bool isMonotonic(); struct timespec d_timeStamp; clockid_t d_clockId; #elif defined(Q_OS_WIN) LARGE_INTEGER d_startTicks; LARGE_INTEGER d_ticksPerSecond; #endif }; #if defined(Q_OS_MAC) QwtHighResolutionClock::QwtHighResolutionClock(): d_timeStamp( 0 ) { } double QwtHighResolutionClock::precision() { return 1e-6; } void QwtHighResolutionClock::start() { d_timeStamp = mach_absolute_time(); } double QwtHighResolutionClock::restart() { const uint64_t timeStamp = mach_absolute_time(); const double elapsed = msecsTo( d_timeStamp, timeStamp ); d_timeStamp = timeStamp; return elapsed; } double QwtHighResolutionClock::elapsed() const { return msecsTo( d_timeStamp, mach_absolute_time() ); } bool QwtHighResolutionClock::isNull() const { return d_timeStamp == 0; } double QwtHighResolutionClock::msecsTo( uint64_t from, uint64_t to ) { const uint64_t difference = to - from; static double conversion = 0.0; if ( conversion == 0.0 ) { mach_timebase_info_data_t info; kern_return_t err = mach_timebase_info( &info ); // convert the timebase into ms if ( err == 0 ) conversion = 1e-6 * ( double ) info.numer / ( double ) info.denom; } return conversion * ( double ) difference; } #elif defined(_POSIX_TIMERS) QwtHighResolutionClock::QwtHighResolutionClock() { d_clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; d_timeStamp.tv_sec = d_timeStamp.tv_nsec = 0; } double QwtHighResolutionClock::precision() { struct timespec resolution; int clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; ::clock_getres( clockId, &resolution ); return resolution.tv_nsec / 1e3; } inline bool QwtHighResolutionClock::isNull() const { return d_timeStamp.tv_sec <= 0 && d_timeStamp.tv_nsec <= 0; } inline void QwtHighResolutionClock::start() { ::clock_gettime( d_clockId, &d_timeStamp ); } double QwtHighResolutionClock::restart() { struct timespec timeStamp; ::clock_gettime( d_clockId, &timeStamp ); const double elapsed = msecsTo( d_timeStamp, timeStamp ); d_timeStamp = timeStamp; return elapsed; } inline double QwtHighResolutionClock::elapsed() const { struct timespec timeStamp; ::clock_gettime( d_clockId, &timeStamp ); return msecsTo( d_timeStamp, timeStamp ); } inline double QwtHighResolutionClock::msecsTo( const struct timespec &t1, const struct timespec &t2 ) { return ( t2.tv_sec - t1.tv_sec ) * 1e3 + ( t2.tv_nsec - t1.tv_nsec ) * 1e-6; } bool QwtHighResolutionClock::isMonotonic() { // code copied from qcore_unix.cpp #if (_POSIX_MONOTONIC_CLOCK-0 > 0) return true; #else static int returnValue = 0; if ( returnValue == 0 ) { #if (_POSIX_MONOTONIC_CLOCK-0 < 0) || !defined(_SC_MONOTONIC_CLOCK) returnValue = -1; #elif (_POSIX_MONOTONIC_CLOCK == 0) // detect if the system support monotonic timers const long x = sysconf( _SC_MONOTONIC_CLOCK ); returnValue = ( x >= 200112L ) ? 1 : -1; #endif } return returnValue != -1; #endif } #elif defined(Q_OS_WIN) QwtHighResolutionClock::QwtHighResolutionClock() { d_startTicks.QuadPart = 0; QueryPerformanceFrequency( &d_ticksPerSecond ); } double QwtHighResolutionClock::precision() { LARGE_INTEGER ticks; if ( QueryPerformanceFrequency( &ticks ) && ticks.QuadPart > 0 ) return 1e3 / ticks.QuadPart; return 0.0; } inline bool QwtHighResolutionClock::isNull() const { return d_startTicks.QuadPart <= 0; } inline void QwtHighResolutionClock::start() { QueryPerformanceCounter( &d_startTicks ); } inline double QwtHighResolutionClock::restart() { LARGE_INTEGER ticks; QueryPerformanceCounter( &ticks ); const double dt = ticks.QuadPart - d_startTicks.QuadPart; d_startTicks = ticks; return dt / d_ticksPerSecond.QuadPart * 1e3; } inline double QwtHighResolutionClock::elapsed() const { LARGE_INTEGER ticks; QueryPerformanceCounter( &ticks ); const double dt = ticks.QuadPart - d_startTicks.QuadPart; return dt / d_ticksPerSecond.QuadPart * 1e3; } #endif #endif // QWT_HIGH_RESOLUTION_CLOCK class QwtSystemClock::PrivateData { public: #if defined(QWT_HIGH_RESOLUTION_CLOCK) QwtHighResolutionClock *clock; #endif QTime time; }; //! Constructs a null clock object. QwtSystemClock::QwtSystemClock() { d_data = new PrivateData; #if defined(QWT_HIGH_RESOLUTION_CLOCK) d_data->clock = NULL; if ( QwtHighResolutionClock::precision() > 0.0 ) d_data->clock = new QwtHighResolutionClock; #endif } //! Destructor QwtSystemClock::~QwtSystemClock() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) delete d_data->clock; #endif delete d_data; } /*! \return true if the clock has never been started. */ bool QwtSystemClock::isNull() const { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) return d_data->clock->isNull(); #endif return d_data->time.isNull(); } /*! Sets the start time to the current time. */ void QwtSystemClock::start() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) { d_data->clock->start(); return; } #endif d_data->time.start(); } /*! Set the start time to the current time \return Time, that is elapsed since the previous start time. */ double QwtSystemClock::restart() { #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) return d_data->clock->restart(); #endif return d_data->time.restart(); } /*! \return Number of milliseconds that have elapsed since the last time start() or restart() was called or 0.0 for null clocks. */ double QwtSystemClock::elapsed() const { double elapsed = 0.0; #if defined(QWT_HIGH_RESOLUTION_CLOCK) if ( d_data->clock ) { if ( !d_data->clock->isNull() ) elapsed = d_data->clock->elapsed(); return elapsed; } #endif if ( !d_data->time.isNull() ) elapsed = d_data->time.elapsed(); return elapsed; } #endif qsstv_8.2.12/qwt/qwt_plot_spectrocurve.cpp000664 001750 001750 00000017207 12440612574 020776 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_spectrocurve.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include "qwt_painter.h" #include class QwtPlotSpectroCurve::PrivateData { public: PrivateData(): colorRange( 0.0, 1000.0 ), penWidth(0.0), paintAttributes( QwtPlotSpectroCurve::ClipPoints ) { colorMap = new QwtLinearColorMap(); } ~PrivateData() { delete colorMap; } QwtColorMap *colorMap; QwtInterval colorRange; QVector colorTable; double penWidth; QwtPlotSpectroCurve::PaintAttributes paintAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotSpectroCurve::~QwtPlotSpectroCurve() { delete d_data; } /*! \brief Initialize data members */ void QwtPlotSpectroCurve::init() { setItemAttribute( QwtPlotItem::Legend ); setItemAttribute( QwtPlotItem::AutoScale ); d_data = new PrivateData; setData( new QwtPoint3DSeriesData() ); setZ( 20.0 ); } //! \return QwtPlotItem::Rtti_PlotSpectroCurve int QwtPlotSpectroCurve::rtti() const { return QwtPlotItem::Rtti_PlotSpectroCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off /sa PaintAttribute, testPaintAttribute() */ void QwtPlotSpectroCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \return True, when attribute is enabled \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotSpectroCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Initialize data with an array of samples. \param samples Vector of points */ void QwtPlotSpectroCurve::setSamples( const QVector &samples ) { setData( new QwtPoint3DSeriesData( samples ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotSpectroCurve::setSamples( QwtSeriesData *data ) { setData( data ); } /*! Change the color map Often it is useful to display the mapping between intensities and colors as an additional plot axis, showing a color bar. \param colorMap Color Map \sa colorMap(), setColorRange(), QwtColorMap::color(), QwtScaleWidget::setColorBarEnabled(), QwtScaleWidget::setColorMap() */ void QwtPlotSpectroCurve::setColorMap( QwtColorMap *colorMap ) { if ( colorMap != d_data->colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } legendChanged(); itemChanged(); } /*! \return Color Map used for mapping the intensity values to colors \sa setColorMap(), setColorRange(), QwtColorMap::color() */ const QwtColorMap *QwtPlotSpectroCurve::colorMap() const { return d_data->colorMap; } /*! Set the value interval, that corresponds to the color map \param interval interval.minValue() corresponds to 0.0, interval.maxValue() to 1.0 on the color map. \sa colorRange(), setColorMap(), QwtColorMap::color() */ void QwtPlotSpectroCurve::setColorRange( const QwtInterval &interval ) { if ( interval != d_data->colorRange ) { d_data->colorRange = interval; legendChanged(); itemChanged(); } } /*! \return Value interval, that corresponds to the color map \sa setColorRange(), setColorMap(), QwtColorMap::color() */ QwtInterval &QwtPlotSpectroCurve::colorRange() const { return d_data->colorRange; } /*! Assign a pen width \param penWidth New pen width \sa penWidth() */ void QwtPlotSpectroCurve::setPenWidth(double penWidth) { if ( penWidth < 0.0 ) penWidth = 0.0; if ( d_data->penWidth != penWidth ) { d_data->penWidth = penWidth; legendChanged(); itemChanged(); } } /*! \return Pen width used to draw a dot \sa setPenWidth() */ double QwtPlotSpectroCurve::penWidth() const { return d_data->penWidth; } /*! Draw a subset of the points \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawDots() */ void QwtPlotSpectroCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( !painter || dataSize() <= 0 ) return; if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; drawDots( painter, xMap, yMap, canvasRect, from, to ); } /*! Draw a subset of the points \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawSeries() */ void QwtPlotSpectroCurve::drawDots( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( !d_data->colorRange.isValid() ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); const QwtColorMap::Format format = d_data->colorMap->format(); if ( format == QwtColorMap::Indexed ) d_data->colorTable = d_data->colorMap->colorTable( d_data->colorRange ); const QwtSeriesData *series = data(); for ( int i = from; i <= to; i++ ) { const QwtPoint3D sample = series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( d_data->paintAttributes & QwtPlotSpectroCurve::ClipPoints ) { if ( !canvasRect.contains( xi, yi ) ) continue; } if ( format == QwtColorMap::RGB ) { const QRgb rgb = d_data->colorMap->rgb( d_data->colorRange, sample.z() ); painter->setPen( QPen( QColor( rgb ), d_data->penWidth ) ); } else { const unsigned char index = d_data->colorMap->colorIndex( d_data->colorRange, sample.z() ); painter->setPen( QPen( QColor( d_data->colorTable[index] ), d_data->penWidth ) ); } QwtPainter::drawPoint( painter, QPointF( xi, yi ) ); } d_data->colorTable.clear(); } qsstv_8.2.12/qwt/qwt_text_engine.cpp000664 001750 001750 00000021133 12440612574 017516 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_text_engine.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #include #include #include #include #include static QString taggedRichText( const QString &text, int flags ) { QString richText = text; // By default QSimpleRichText is Qt::AlignLeft if ( flags & Qt::AlignJustify ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } else if ( flags & Qt::AlignRight ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } else if ( flags & Qt::AlignHCenter ) { richText.prepend( QString::fromLatin1( "
" ) ); richText.append( QString::fromLatin1( "
" ) ); } return richText; } class QwtRichTextDocument: public QTextDocument { public: QwtRichTextDocument( const QString &text, int flags, const QFont &font ) { setUndoRedoEnabled( false ); setDefaultFont( font ); setHtml( text ); // make sure we have a document layout ( void )documentLayout(); QTextOption option = defaultTextOption(); if ( flags & Qt::TextWordWrap ) option.setWrapMode( QTextOption::WordWrap ); else option.setWrapMode( QTextOption::NoWrap ); option.setAlignment( static_cast( flags ) ); setDefaultTextOption( option ); QTextFrame *root = rootFrame(); QTextFrameFormat fm = root->frameFormat(); fm.setBorder( 0 ); fm.setMargin( 0 ); fm.setPadding( 0 ); fm.setBottomMargin( 0 ); fm.setLeftMargin( 0 ); root->setFrameFormat( fm ); adjustSize(); } }; class QwtPlainTextEngine::PrivateData { public: int effectiveAscent( const QFont &font ) const { const QString fontKey = font.key(); QMap::const_iterator it = d_ascentCache.find( fontKey ); if ( it == d_ascentCache.end() ) { int ascent = findAscent( font ); it = d_ascentCache.insert( fontKey, ascent ); } return ( *it ); } private: int findAscent( const QFont &font ) const { static const QString dummy( "E" ); static const QColor white( Qt::white ); const QFontMetrics fm( font ); QPixmap pm( fm.width( dummy ), fm.height() ); pm.fill( white ); QPainter p( &pm ); p.setFont( font ); p.drawText( 0, 0, pm.width(), pm.height(), 0, dummy ); p.end(); const QImage img = pm.toImage(); int row = 0; for ( row = 0; row < img.height(); row++ ) { const QRgb *line = reinterpret_cast( img.scanLine( row ) ); const int w = pm.width(); for ( int col = 0; col < w; col++ ) { if ( line[col] != white.rgb() ) return fm.ascent() - row + 1; } } return fm.ascent(); } mutable QMap d_ascentCache; }; //! Constructor QwtTextEngine::QwtTextEngine() { } //! Destructor QwtTextEngine::~QwtTextEngine() { } //! Constructor QwtPlainTextEngine::QwtPlainTextEngine() { d_data = new PrivateData; } //! Destructor QwtPlainTextEngine::~QwtPlainTextEngine() { delete d_data; } /*! Find the height for a given width \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \param width Width \return Calculated height */ double QwtPlainTextEngine::heightForWidth( const QFont& font, int flags, const QString& text, double width ) const { const QFontMetricsF fm( font ); const QRectF rect = fm.boundingRect( QRectF( 0, 0, width, QWIDGETSIZE_MAX ), flags, text ); return rect.height(); } /*! Returns the size, that is needed to render text \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \return Caluclated size */ QSizeF QwtPlainTextEngine::textSize( const QFont &font, int flags, const QString& text ) const { const QFontMetricsF fm( font ); const QRectF rect = fm.boundingRect( QRectF( 0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ), flags, text ); return rect.size(); } /*! Return margins around the texts \param font Font of the text \param left Return 0 \param right Return 0 \param top Return value for the top margin \param bottom Return value for the bottom margin */ void QwtPlainTextEngine::textMargins( const QFont &font, const QString &, double &left, double &right, double &top, double &bottom ) const { left = right = top = 0; const QFontMetricsF fm( font ); top = fm.ascent() - d_data->effectiveAscent( font ); bottom = fm.descent(); } /*! \brief Draw the text in a clipping rectangle A wrapper for QPainter::drawText. \param painter Painter \param rect Clipping rectangle \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered */ void QwtPlainTextEngine::draw( QPainter *painter, const QRectF &rect, int flags, const QString& text ) const { QwtPainter::drawText( painter, rect, flags, text ); } /*! Test if a string can be rendered by this text engine. \return Always true. All texts can be rendered by QwtPlainTextEngine */ bool QwtPlainTextEngine::mightRender( const QString & ) const { return true; } #ifndef QT_NO_RICHTEXT //! Constructor QwtRichTextEngine::QwtRichTextEngine() { } /*! Find the height for a given width \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText() \param text Text to be rendered \param width Width \return Calculated height */ double QwtRichTextEngine::heightForWidth( const QFont& font, int flags, const QString& text, double width ) const { QwtRichTextDocument doc( text, flags, font ); doc.setPageSize( QSizeF( width, QWIDGETSIZE_MAX ) ); return doc.documentLayout()->documentSize().height(); } /*! Returns the size, that is needed to render text \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText() \param text Text to be rendered \return Caluclated size */ QSizeF QwtRichTextEngine::textSize( const QFont &font, int flags, const QString& text ) const { QwtRichTextDocument doc( text, flags, font ); QTextOption option = doc.defaultTextOption(); if ( option.wrapMode() != QTextOption::NoWrap ) { option.setWrapMode( QTextOption::NoWrap ); doc.setDefaultTextOption( option ); doc.adjustSize(); } return doc.size(); } /*! Draw the text in a clipping rectangle \param painter Painter \param rect Clipping rectangle \param flags Bitwise OR of the flags like in for QPainter::drawText() \param text Text to be rendered */ void QwtRichTextEngine::draw( QPainter *painter, const QRectF &rect, int flags, const QString& text ) const { QwtRichTextDocument doc( text, flags, painter->font() ); QwtPainter::drawSimpleRichText( painter, rect, flags, doc ); } /*! Wrap text into
tags according flags \param text Text \param flags Bitwise OR of the flags like in for QPainter::drawText() \return Tagged text */ QString QwtRichTextEngine::taggedText( const QString &text, int flags ) const { return taggedRichText( text, flags ); } /*! Test if a string can be rendered by this text engine \param text Text to be tested \return Qt::mightBeRichText(text); */ bool QwtRichTextEngine::mightRender( const QString &text ) const { return Qt::mightBeRichText( text ); } /*! Return margins around the texts \param left Return 0 \param right Return 0 \param top Return 0 \param bottom Return 0 */ void QwtRichTextEngine::textMargins( const QFont &, const QString &, double &left, double &right, double &top, double &bottom ) const { left = right = top = bottom = 0; } #endif // !QT_NO_RICHTEXT qsstv_8.2.12/qwt/qwt_plot_spectrocurve.h000664 001750 001750 00000004141 12440612574 020434 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_CURVE_3D_H #define QWT_PLOT_CURVE_3D_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" class QwtSymbol; class QwtColorMap; /*! \brief Curve that displays 3D points as dots, where the z coordinate is mapped to a color. */ class QWT_EXPORT QwtPlotSpectroCurve: public QwtPlotSeriesItem, QwtSeriesStore { public: //! Paint attributes enum PaintAttribute { //! Clip points outside the canvas rectangle ClipPoints = 1 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotSpectroCurve( const QString &title = QString::null ); explicit QwtPlotSpectroCurve( const QwtText &title ); virtual ~QwtPlotSpectroCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setSamples( const QVector & ); void setSamples( QwtSeriesData * ); void setColorMap( QwtColorMap * ); const QwtColorMap *colorMap() const; void setColorRange( const QwtInterval & ); QwtInterval & colorRange() const; virtual void drawSeries( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; void setPenWidth(double width); double penWidth() const; protected: virtual void drawDots( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; private: void init(); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotSpectroCurve::PaintAttributes ) #endif qsstv_8.2.12/qwt/qwt_text.h000664 001750 001750 00000014026 12440612574 015641 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_TEXT_H #define QWT_TEXT_H #include "qwt_global.h" #include #include #include #include class QColor; class QPen; class QBrush; class QRectF; class QPainter; class QwtTextEngine; /*! \brief A class representing a text A QwtText is a text including a set of attributes how to render it. - Format\n A text might include control sequences (f.e tags) describing how to render it. Each format (f.e MathML, TeX, Qt Rich Text) has its own set of control sequences, that can be handles by a special QwtTextEngine for this format. - Background\n A text might have a background, defined by a QPen and QBrush to improve its visibility. The corners of the background might be rounded. - Font\n A text might have an individual font. - Color\n A text might have an individual color. - Render Flags\n Flags from Qt::AlignmentFlag and Qt::TextFlag used like in QPainter::drawText(). \sa QwtTextEngine, QwtTextLabel */ class QWT_EXPORT QwtText { public: /*! \brief Text format The text format defines the QwtTextEngine, that is used to render the text. \sa QwtTextEngine, setTextEngine() */ enum TextFormat { /*! The text format is determined using QwtTextEngine::mightRender() for all available text engines in increasing order > PlainText. If none of the text engines can render the text is rendered like QwtText::PlainText. */ AutoText = 0, //! Draw the text as it is, using a QwtPlainTextEngine. PlainText, //! Use the Scribe framework (Qt Rich Text) to render the text. RichText, /*! Use a MathML (http://en.wikipedia.org/wiki/MathML) render engine to display the text. The Qwt MathML extension offers such an engine based on the MathML renderer of the Qt solutions package. To enable MathML support the following code needs to be added to the application: \verbatim QwtText::setTextEngine(QwtText::MathMLText, new QwtMathMLTextEngine()); \endverbatim */ MathMLText, /*! Use a TeX (http://en.wikipedia.org/wiki/TeX) render engine to display the text ( not implemented yet ). */ TeXText, /*! The number of text formats can be extended using setTextEngine. Formats >= QwtText::OtherFormat are not used by Qwt. */ OtherFormat = 100 }; /*! \brief Paint Attributes Font and color and background are optional attributes of a QwtText. The paint attributes hold the information, if they are set. */ enum PaintAttribute { //! The text has an individual font. PaintUsingTextFont = 0x01, //! The text has an individual color. PaintUsingTextColor = 0x02, //! The text has an individual background. PaintBackground = 0x04 }; //! Paint attributes typedef QFlags PaintAttributes; /*! \brief Layout Attributes The layout attributes affects some aspects of the layout of the text. */ enum LayoutAttribute { /*! Layout the text without its margins. This mode is useful if a text needs to be aligned accurately, like the tick labels of a scale. If QwtTextEngine::textMargins is not implemented for the format of the text, MinimumLayout has no effect. */ MinimumLayout = 0x01 }; //! Layout attributes typedef QFlags LayoutAttributes; QwtText( const QString & = QString::null, TextFormat textFormat = AutoText ); QwtText( const QwtText & ); ~QwtText(); QwtText &operator=( const QwtText & ); bool operator==( const QwtText & ) const; bool operator!=( const QwtText & ) const; void setText( const QString &, QwtText::TextFormat textFormat = AutoText ); QString text() const; bool isNull() const; bool isEmpty() const; void setFont( const QFont & ); QFont font() const; QFont usedFont( const QFont & ) const; void setRenderFlags( int flags ); int renderFlags() const; void setColor( const QColor & ); QColor color() const; QColor usedColor( const QColor & ) const; void setBorderRadius( double ); double borderRadius() const; void setBorderPen( const QPen & ); QPen borderPen() const; void setBackgroundBrush( const QBrush & ); QBrush backgroundBrush() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setLayoutAttribute( LayoutAttribute, bool on = true ); bool testLayoutAttribute( LayoutAttribute ) const; double heightForWidth( double width, const QFont & = QFont() ) const; QSizeF textSize( const QFont & = QFont() ) const; void draw( QPainter *painter, const QRectF &rect ) const; static const QwtTextEngine *textEngine( const QString &text, QwtText::TextFormat = AutoText ); static const QwtTextEngine *textEngine( QwtText::TextFormat ); static void setTextEngine( QwtText::TextFormat, QwtTextEngine * ); private: class PrivateData; PrivateData *d_data; class LayoutCache; LayoutCache *d_layoutCache; }; //! \return text().isNull() inline bool QwtText::isNull() const { return text().isNull(); } //! \return text().isEmpty() inline bool QwtText::isEmpty() const { return text().isEmpty(); } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtText::PaintAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtText::LayoutAttributes ) Q_DECLARE_METATYPE( QwtText ) #endif qsstv_8.2.12/qwt/qwt_plot_spectrogram.cpp000664 001750 001750 00000041275 12440612574 020602 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_spectrogram.h" #include "qwt_painter.h" #include "qwt_interval.h" #include "qwt_scale_map.h" #include "qwt_color_map.h" #include #include #include #include #include #if QT_VERSION >= 0x040400 #include #include #include #endif class QwtPlotSpectrogram::PrivateData { public: PrivateData(): data( NULL ) { colorMap = new QwtLinearColorMap(); displayMode = ImageMode; conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel; #if 0 conrecFlags |= QwtRasterData::IgnoreOutOfRange; #endif } ~PrivateData() { delete data; delete colorMap; } QwtRasterData *data; QwtColorMap *colorMap; DisplayModes displayMode; QList contourLevels; QPen defaultContourPen; QwtRasterData::ConrecFlags conrecFlags; }; /*! Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false The z value is initialized by 8.0. \param title Title \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ() */ QwtPlotSpectrogram::QwtPlotSpectrogram( const QString &title ): QwtPlotRasterItem( title ) { d_data = new PrivateData(); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 8.0 ); } //! Destructor QwtPlotSpectrogram::~QwtPlotSpectrogram() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotSpectrogram int QwtPlotSpectrogram::rtti() const { return QwtPlotItem::Rtti_PlotSpectrogram; } /*! The display mode controls how the raster data will be represented. \param mode Display mode \param on On/Off The default setting enables ImageMode. \sa DisplayMode, displayMode() */ void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on ) { if ( on != bool( mode & d_data->displayMode ) ) { if ( on ) d_data->displayMode |= mode; else d_data->displayMode &= ~mode; } legendChanged(); itemChanged(); } /*! The display mode controls how the raster data will be represented. \param mode Display mode \return true if mode is enabled */ bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const { return ( d_data->displayMode & mode ); } /*! Change the color map Often it is useful to display the mapping between intensities and colors as an additional plot axis, showing a color bar. \param colorMap Color Map \sa colorMap(), QwtScaleWidget::setColorBarEnabled(), QwtScaleWidget::setColorMap() */ void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap ) { if ( d_data->colorMap != colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } invalidateCache(); legendChanged(); itemChanged(); } /*! \return Color Map used for mapping the intensity values to colors \sa setColorMap() */ const QwtColorMap *QwtPlotSpectrogram::colorMap() const { return d_data->colorMap; } /*! Build and assign the default pen for the contour lines In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotSpectrogram::setDefaultContourPen( const QColor &color, qreal width, Qt::PenStyle style ) { setDefaultContourPen( QPen( color, width, style ) ); } /*! \brief Set the default pen for the contour lines If the spectrogram has a valid default contour pen a contour line is painted using the default contour pen. Otherwise (pen.style() == Qt::NoPen) the pen is calculated for each contour level using contourPen(). \sa defaultContourPen(), contourPen() */ void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen ) { if ( pen != d_data->defaultContourPen ) { d_data->defaultContourPen = pen; legendChanged(); itemChanged(); } } /*! \return Default contour pen \sa setDefaultContourPen() */ QPen QwtPlotSpectrogram::defaultContourPen() const { return d_data->defaultContourPen; } /*! \brief Calculate the pen for a contour line The color of the pen is the color for level calculated by the color map \param level Contour level \return Pen for the contour line \note contourPen is only used if defaultContourPen().style() == Qt::NoPen \sa setDefaultContourPen(), setColorMap(), setContourLevels() */ QPen QwtPlotSpectrogram::contourPen( double level ) const { if ( d_data->data == NULL || d_data->colorMap == NULL ) return QPen(); const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis); const QColor c( d_data->colorMap->rgb( intensityRange, level ) ); return QPen( c ); } /*! Modify an attribute of the CONREC algorithm, used to calculate the contour lines. \param flag CONREC flag \param on On/Off \sa testConrecFlag(), renderContourLines(), QwtRasterData::contourLines() */ void QwtPlotSpectrogram::setConrecFlag( QwtRasterData::ConrecFlag flag, bool on ) { if ( bool( d_data->conrecFlags & flag ) == on ) return; if ( on ) d_data->conrecFlags |= flag; else d_data->conrecFlags &= ~flag; itemChanged(); } /*! Test an attribute of the CONREC algorithm, used to calculate the contour lines. \param flag CONREC flag \return true, is enabled The default setting enables QwtRasterData::IgnoreAllVerticesOnLevel \sa setConrecClag(), renderContourLines(), QwtRasterData::contourLines() */ bool QwtPlotSpectrogram::testConrecFlag( QwtRasterData::ConrecFlag flag ) const { return d_data->conrecFlags & flag; } /*! Set the levels of the contour lines \param levels Values of the contour levels \sa contourLevels(), renderContourLines(), QwtRasterData::contourLines() \note contourLevels returns the same levels but sorted. */ void QwtPlotSpectrogram::setContourLevels( const QList &levels ) { d_data->contourLevels = levels; qSort( d_data->contourLevels ); legendChanged(); itemChanged(); } /*! \return Levels of the contour lines. The levels are sorted in increasing order. \sa contourLevels(), renderContourLines(), QwtRasterData::contourLines() */ QList QwtPlotSpectrogram::contourLevels() const { return d_data->contourLevels; } /*! Set the data to be displayed \param data Spectrogram Data \sa data() */ void QwtPlotSpectrogram::setData( QwtRasterData *data ) { if ( data != d_data->data ) { delete d_data->data; d_data->data = data; invalidateCache(); itemChanged(); } } /*! \return Spectrogram data \sa setData() */ const QwtRasterData *QwtPlotSpectrogram::data() const { return d_data->data; } /*! \return Spectrogram data \sa setData() */ QwtRasterData *QwtPlotSpectrogram::data() { return d_data->data; } /*! \return Bounding interval for an axis The default implementation returns the interval of the associated raster data object. \param axis X, Y, or Z axis \sa QwtRasterData::interval() */ QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const { if ( d_data->data == NULL ) return QwtInterval(); return d_data->data->interval( axis ); } /*! \brief Pixel hint The geometry of a pixel is used to calculated the resolution and alignment of the rendered image. The default implementation returns data()->pixelHint( rect ); \param area In most implementations the resolution of the data doesn't depend on the requested area. \return Bounding rectangle of a pixel \sa QwtPlotRasterItem::pixelHint(), QwtRasterData::pixelHint(), render(), renderImage() */ QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const { if ( d_data->data == NULL ) return QRectF(); return d_data->data->pixelHint( area ); } /*! \brief Render an image from data and color map. For each pixel of area the value is mapped into a color. \param xMap X-Scale Map \param yMap Y-Scale Map \param area Requested area for the image in scale coordinates \param imageSize Size of the requested image \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending on the color map. \sa QwtRasterData::value(), QwtColorMap::rgb(), QwtColorMap::colorIndex() */ QImage QwtPlotSpectrogram::renderImage( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize ) const { if ( imageSize.isEmpty() || d_data->data == NULL || d_data->colorMap == NULL ) { return QImage(); } const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis ); if ( !intensityRange.isValid() ) return QImage(); QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB ) ? QImage::Format_ARGB32 : QImage::Format_Indexed8; QImage image( imageSize, format ); if ( d_data->colorMap->format() == QwtColorMap::Indexed ) image.setColorTable( d_data->colorMap->colorTable( intensityRange ) ); d_data->data->initRaster( area, image.size() ); #if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE) uint numThreads = renderThreadCount(); if ( numThreads <= 0 ) numThreads = QThread::idealThreadCount(); if ( numThreads <= 0 ) numThreads = 1; const int numRows = imageSize.height() / numThreads; QList< QFuture > futures; for ( uint i = 0; i < numThreads; i++ ) { QRect tile( 0, i * numRows, image.width(), numRows ); if ( i == numThreads - 1 ) { tile.setHeight( image.height() - i * numRows ); renderTile( xMap, yMap, tile, &image ); } else { futures += QtConcurrent::run( this, &QwtPlotSpectrogram::renderTile, xMap, yMap, tile, &image ); } } for ( int i = 0; i < futures.size(); i++ ) futures[i].waitForFinished(); #else // QT_VERSION < 0x040400 const QRect tile( 0, 0, image.width(), image.height() ); renderTile( xMap, yMap, tile, &image ); #endif d_data->data->discardRaster(); return image; } /*! \brief Render a tile of an image. Rendering in tiles can be used to composite an image in parallel threads. \param xMap X-Scale Map \param yMap Y-Scale Map \param tile Geometry of the tile in image coordinates \param image Image to be rendered */ void QwtPlotSpectrogram::renderTile( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &tile, QImage *image ) const { const QwtInterval range = d_data->data->interval( Qt::ZAxis ); if ( !range.isValid() ) return; if ( d_data->colorMap->format() == QwtColorMap::RGB ) { for ( int y = tile.top(); y <= tile.bottom(); y++ ) { const double ty = yMap.invTransform( y ); QRgb *line = reinterpret_cast( image->scanLine( y ) ); line += tile.left(); for ( int x = tile.left(); x <= tile.right(); x++ ) { const double tx = xMap.invTransform( x ); *line++ = d_data->colorMap->rgb( range, d_data->data->value( tx, ty ) ); } } } else if ( d_data->colorMap->format() == QwtColorMap::Indexed ) { for ( int y = tile.top(); y <= tile.bottom(); y++ ) { const double ty = yMap.invTransform( y ); unsigned char *line = image->scanLine( y ); line += tile.left(); for ( int x = tile.left(); x <= tile.right(); x++ ) { const double tx = xMap.invTransform( x ); *line++ = d_data->colorMap->colorIndex( range, d_data->data->value( tx, ty ) ); } } } } /*! \brief Return the raster to be used by the CONREC contour algorithm. A larger size will improve the precision of the CONREC algorithm, but will slow down the time that is needed to calculate the lines. The default implementation returns rect.size() / 2 bounded to the resolution depending on pixelSize(). \param area Rectangle, where to calculate the contour lines \param rect Rectangle in pixel coordinates, where to paint the contour lines \return Raster to be used by the CONREC contour algorithm. \note The size will be bounded to rect.size(). \sa drawContourLines(), QwtRasterData::contourLines() */ QSize QwtPlotSpectrogram::contourRasterSize( const QRectF &area, const QRect &rect ) const { QSize raster = rect.size() / 2; const QRectF pixelRect = pixelHint( area ); if ( !pixelRect.isEmpty() ) { const QSize res( qCeil( rect.width() / pixelRect.width() ), qCeil( rect.height() / pixelRect.height() ) ); raster = raster.boundedTo( res ); } return raster; } /*! Calculate contour lines \param rect Rectangle, where to calculate the contour lines \param raster Raster, used by the CONREC algorithm \return Calculated contour lines \sa contourLevels(), setConrecFlag(), QwtRasterData::contourLines() */ QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines( const QRectF &rect, const QSize &raster ) const { if ( d_data->data == NULL ) return QwtRasterData::ContourLines(); return d_data->data->contourLines( rect, raster, d_data->contourLevels, d_data->conrecFlags ); } /*! Paint the contour lines \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param contourLines Contour lines \sa renderContourLines(), defaultContourPen(), contourPen() */ void QwtPlotSpectrogram::drawContourLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines &contourLines ) const { if ( d_data->data == NULL ) return; const int numLevels = d_data->contourLevels.size(); for ( int l = 0; l < numLevels; l++ ) { const double level = d_data->contourLevels[l]; QPen pen = defaultContourPen(); if ( pen.style() == Qt::NoPen ) pen = contourPen( level ); if ( pen.style() == Qt::NoPen ) continue; painter->setPen( pen ); const QPolygonF &lines = contourLines[level]; for ( int i = 0; i < lines.size(); i += 2 ) { const QPointF p1( xMap.transform( lines[i].x() ), yMap.transform( lines[i].y() ) ); const QPointF p2( xMap.transform( lines[i+1].x() ), yMap.transform( lines[i+1].y() ) ); QwtPainter::drawLine( painter, p1, p2 ); } } } /*! \brief Draw the spectrogram \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas in painter coordinates \sa setDisplayMode(), renderImage(), QwtPlotRasterItem::draw(), drawContourLines() */ void QwtPlotSpectrogram::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( d_data->displayMode & ImageMode ) QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect ); if ( d_data->displayMode & ContourMode ) { // Add some pixels at the borders const int margin = 2; QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin, canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin ); QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect ); const QRectF br = boundingRect(); if ( br.isValid() ) { area &= br; if ( area.isEmpty() ) return; rasterRect = QwtScaleMap::transform( xMap, yMap, area ); } QSize raster = contourRasterSize( area, rasterRect.toRect() ); raster = raster.boundedTo( rasterRect.toRect().size() ); if ( raster.isValid() ) { const QwtRasterData::ContourLines lines = renderContourLines( area, raster ); drawContourLines( painter, xMap, yMap, lines ); } } } qsstv_8.2.12/qwt/qwt_text_engine.h000664 001750 001750 00000011367 12440612574 017173 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_TEXT_ENGINE_H #define QWT_TEXT_ENGINE_H 1 #include "qwt_global.h" #include class QFont; class QRectF; class QString; class QPainter; /*! \brief Abstract base class for rendering text strings A text engine is responsible for rendering texts for a specific text format. They are used by QwtText to render a text. QwtPlainTextEngine and QwtRichTextEngine are part of the Qwt library. The implementation of QwtMathMLTextEngine uses code from the Qt solution package. Because of license implications it is built into a separate library. \sa QwtText::setTextEngine() */ class QWT_EXPORT QwtTextEngine { public: virtual ~QwtTextEngine(); /*! Find the height for a given width \param font Font of the text \param flags Bitwise OR of the flags used like in QPainter::drawText \param text Text to be rendered \param width Width \return Calculated height */ virtual double heightForWidth( const QFont &font, int flags, const QString &text, double width ) const = 0; /*! Returns the size, that is needed to render text \param font Font of the text \param flags Bitwise OR of the flags like in for QPainter::drawText \param text Text to be rendered \return Calculated size */ virtual QSizeF textSize( const QFont &font, int flags, const QString &text ) const = 0; /*! Test if a string can be rendered by this text engine \param text Text to be tested \return true, if it can be rendered */ virtual bool mightRender( const QString &text ) const = 0; /*! Return margins around the texts The textSize might include margins around the text, like QFontMetrics::descent(). In situations where texts need to be aligned in detail, knowing these margins might improve the layout calculations. \param font Font of the text \param text Text to be rendered \param left Return value for the left margin \param right Return value for the right margin \param top Return value for the top margin \param bottom Return value for the bottom margin */ virtual void textMargins( const QFont &font, const QString &text, double &left, double &right, double &top, double &bottom ) const = 0; /*! Draw the text in a clipping rectangle \param painter Painter \param rect Clipping rectangle \param flags Bitwise OR of the flags like in for QPainter::drawText() \param text Text to be rendered */ virtual void draw( QPainter *painter, const QRectF &rect, int flags, const QString &text ) const = 0; protected: QwtTextEngine(); }; /*! \brief A text engine for plain texts QwtPlainTextEngine renders texts using the basic Qt classes QPainter and QFontMetrics. */ class QWT_EXPORT QwtPlainTextEngine: public QwtTextEngine { public: QwtPlainTextEngine(); virtual ~QwtPlainTextEngine(); virtual double heightForWidth( const QFont &font, int flags, const QString &text, double width ) const; virtual QSizeF textSize( const QFont &font, int flags, const QString &text ) const; virtual void draw( QPainter *painter, const QRectF &rect, int flags, const QString &text ) const; virtual bool mightRender( const QString & ) const; virtual void textMargins( const QFont &, const QString &, double &left, double &right, double &top, double &bottom ) const; private: class PrivateData; PrivateData *d_data; }; #ifndef QT_NO_RICHTEXT /*! \brief A text engine for Qt rich texts QwtRichTextEngine renders Qt rich texts using the classes of the Scribe framework of Qt. */ class QWT_EXPORT QwtRichTextEngine: public QwtTextEngine { public: QwtRichTextEngine(); virtual double heightForWidth( const QFont &font, int flags, const QString &text, double width ) const; virtual QSizeF textSize( const QFont &font, int flags, const QString &text ) const; virtual void draw( QPainter *painter, const QRectF &rect, int flags, const QString &text ) const; virtual bool mightRender( const QString & ) const; virtual void textMargins( const QFont &, const QString &, double &left, double &right, double &top, double &bottom ) const; private: QString taggedText( const QString &, int flags ) const; }; #endif // !QT_NO_RICHTEXT #endif qsstv_8.2.12/qwt/qwt_plot_spectrogram.h000664 001750 001750 00000007023 12440612574 020240 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_SPECTROGRAM_H #define QWT_PLOT_SPECTROGRAM_H #include "qwt_global.h" #include "qwt_raster_data.h" #include "qwt_plot_rasteritem.h" #include class QwtColorMap; /*! \brief A plot item, which displays a spectrogram A spectrogram displays 3-dimensional data, where the 3rd dimension ( the intensity ) is displayed using colors. The colors are calculated from the values using a color map. On multi-core systems the performance of the image composition can often be improved by dividing the area into tiles - each of them rendered in a different thread ( see QwtPlotItem::setRenderThreadCount() ). In ContourMode contour lines are painted for the contour levels. \image html spectrogram3.png \sa QwtRasterData, QwtColorMap, QwtPlotItem::setRenderThreadCount() */ class QWT_EXPORT QwtPlotSpectrogram: public QwtPlotRasterItem { public: /*! The display mode controls how the raster data will be represented. \sa setDisplayMode(), testDisplayMode() */ enum DisplayMode { //! The values are mapped to colors using a color map. ImageMode = 0x01, //! The data is displayed using contour lines ContourMode = 0x02 }; //! Display modes typedef QFlags DisplayModes; explicit QwtPlotSpectrogram( const QString &title = QString::null ); virtual ~QwtPlotSpectrogram(); void setDisplayMode( DisplayMode, bool on = true ); bool testDisplayMode( DisplayMode ) const; void setData( QwtRasterData *data ); const QwtRasterData *data() const; QwtRasterData *data(); void setColorMap( QwtColorMap * ); const QwtColorMap *colorMap() const; virtual QwtInterval interval(Qt::Axis) const; virtual QRectF pixelHint( const QRectF & ) const; void setDefaultContourPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setDefaultContourPen( const QPen & ); QPen defaultContourPen() const; virtual QPen contourPen( double level ) const; void setConrecFlag( QwtRasterData::ConrecFlag, bool on ); bool testConrecFlag( QwtRasterData::ConrecFlag ) const; void setContourLevels( const QList & ); QList contourLevels() const; virtual int rtti() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; protected: virtual QImage renderImage( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize ) const; virtual QSize contourRasterSize( const QRectF &, const QRect & ) const; virtual QwtRasterData::ContourLines renderContourLines( const QRectF &rect, const QSize &raster ) const; virtual void drawContourLines( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines& lines ) const; void renderTile( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &imageRect, QImage *image ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotSpectrogram::DisplayModes ) #endif qsstv_8.2.12/qwt/qwt_plot_svgitem.h000664 001750 001750 00000003020 12440612574 017361 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_SVGITEM_H #define QWT_PLOT_SVGITEM_H #include "qwt_global.h" #include "qwt_plot_item.h" #include class QSvgRenderer; class QByteArray; /*! \brief A plot item, which displays data in Scalable Vector Graphics (SVG) format. SVG images are often used to display maps */ class QWT_EXPORT QwtPlotSvgItem: public QwtPlotItem { public: explicit QwtPlotSvgItem( const QString& title = QString::null ); explicit QwtPlotSvgItem( const QwtText& title ); virtual ~QwtPlotSvgItem(); bool loadFile( const QRectF&, const QString &fileName ); bool loadData( const QRectF&, const QByteArray & ); virtual QRectF boundingRect() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; virtual int rtti() const; protected: const QSvgRenderer &renderer() const; QSvgRenderer &renderer(); void render( QPainter *painter, const QRectF &viewBox, const QRectF &rect ) const; QRectF viewBox( const QRectF &area ) const; private: void init(); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_text_label.cpp000664 001750 001750 00000015343 12440612574 017336 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_text_label.h" #include "qwt_text.h" #include "qwt_painter.h" #include #include #include class QwtTextLabel::PrivateData { public: PrivateData(): indent( 4 ), margin( 0 ) { } int indent; int margin; QwtText text; }; /*! Constructs an empty label. \param parent Parent widget */ QwtTextLabel::QwtTextLabel( QWidget *parent ): QFrame( parent ) { init(); } /*! Constructs a label that displays the text, text \param parent Parent widget \param text Text */ QwtTextLabel::QwtTextLabel( const QwtText &text, QWidget *parent ): QFrame( parent ) { init(); d_data->text = text; } //! Destructor QwtTextLabel::~QwtTextLabel() { delete d_data; } void QwtTextLabel::init() { d_data = new PrivateData(); setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); } /*! Interface for the designer plugin - does the same as setText() \sa plainText() */ void QwtTextLabel::setPlainText( const QString &text ) { setText( QwtText( text ) ); } /*! Interface for the designer plugin \return Text as plain text \sa setPlainText(), text() */ QString QwtTextLabel::plainText() const { return d_data->text.text(); } /*! Change the label's text, keeping all other QwtText attributes \param text New text \param textFormat Format of text \sa QwtText */ void QwtTextLabel::setText( const QString &text, QwtText::TextFormat textFormat ) { d_data->text.setText( text, textFormat ); update(); updateGeometry(); } /*! Change the label's text \param text New text */ void QwtTextLabel::setText( const QwtText &text ) { d_data->text = text; update(); updateGeometry(); } //! Return the text const QwtText &QwtTextLabel::text() const { return d_data->text; } //! Clear the text and all QwtText attributes void QwtTextLabel::clear() { d_data->text = QwtText(); update(); updateGeometry(); } //! Return label's text indent in pixels int QwtTextLabel::indent() const { return d_data->indent; } /*! Set label's text indent in pixels \param indent Indentation in pixels */ void QwtTextLabel::setIndent( int indent ) { if ( indent < 0 ) indent = 0; d_data->indent = indent; update(); updateGeometry(); } //! Return label's text indent in pixels int QwtTextLabel::margin() const { return d_data->margin; } /*! Set label's margin in pixels \param margin Margin in pixels */ void QwtTextLabel::setMargin( int margin ) { d_data->margin = margin; update(); updateGeometry(); } //! Return label's margin in pixels QSize QwtTextLabel::sizeHint() const { return minimumSizeHint(); } //! Return a minimum size hint QSize QwtTextLabel::minimumSizeHint() const { QSizeF sz = d_data->text.textSize( font() ); int mw = 2 * ( frameWidth() + d_data->margin ); int mh = mw; int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); if ( indent > 0 ) { const int align = d_data->text.renderFlags(); if ( align & Qt::AlignLeft || align & Qt::AlignRight ) mw += d_data->indent; else if ( align & Qt::AlignTop || align & Qt::AlignBottom ) mh += d_data->indent; } sz += QSizeF( mw, mh ); return QSize( qCeil( sz.width() ), qCeil( sz.height() ) ); } /*! \param width Width \return Preferred height for this widget, given the width. */ int QwtTextLabel::heightForWidth( int width ) const { const int renderFlags = d_data->text.renderFlags(); int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); width -= 2 * frameWidth(); if ( renderFlags & Qt::AlignLeft || renderFlags & Qt::AlignRight ) width -= indent; int height = qCeil( d_data->text.heightForWidth( width, font() ) ); if ( ( renderFlags & Qt::AlignTop ) || ( renderFlags & Qt::AlignBottom ) ) height += indent; height += 2 * frameWidth(); return height; } /*! Qt paint event \param event Paint event */ void QwtTextLabel::paintEvent( QPaintEvent *event ) { QPainter painter( this ); if ( !contentsRect().contains( event->rect() ) ) { painter.save(); painter.setClipRegion( event->region() & frameRect() ); drawFrame( &painter ); painter.restore(); } painter.setClipRegion( event->region() & contentsRect() ); drawContents( &painter ); } //! Redraw the text and focus indicator void QwtTextLabel::drawContents( QPainter *painter ) { const QRect r = textRect(); if ( r.isEmpty() ) return; painter->setFont( font() ); painter->setPen( palette().color( QPalette::Active, QPalette::Text ) ); drawText( painter, QRectF( r ) ); if ( hasFocus() ) { const int m = 2; QRect focusRect = contentsRect().adjusted( m, m, -m + 1, -m + 1); QwtPainter::drawFocusRect( painter, this, focusRect ); } } //! Redraw the text void QwtTextLabel::drawText( QPainter *painter, const QRectF &textRect ) { d_data->text.draw( painter, textRect ); } /*! Calculate geometry for the text in widget coordinates \return Geometry for the text */ QRect QwtTextLabel::textRect() const { QRect r = contentsRect(); if ( !r.isEmpty() && d_data->margin > 0 ) { r.setRect( r.x() + d_data->margin, r.y() + d_data->margin, r.width() - 2 * d_data->margin, r.height() - 2 * d_data->margin ); } if ( !r.isEmpty() ) { int indent = d_data->indent; if ( indent <= 0 ) indent = defaultIndent(); if ( indent > 0 ) { const int renderFlags = d_data->text.renderFlags(); if ( renderFlags & Qt::AlignLeft ) r.setX( r.x() + indent ); else if ( renderFlags & Qt::AlignRight ) r.setWidth( r.width() - indent ); else if ( renderFlags & Qt::AlignTop ) r.setY( r.y() + indent ); else if ( renderFlags & Qt::AlignBottom ) r.setHeight( r.height() - indent ); } } return r; } int QwtTextLabel::defaultIndent() const { if ( frameWidth() <= 0 ) return 0; QFont fnt; if ( d_data->text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) fnt = d_data->text.font(); else fnt = font(); return QFontMetrics( fnt ).width( 'x' ) / 2; } qsstv_8.2.12/qwt/qwt_plot_textlabel.cpp000664 001750 001750 00000012722 12440612574 020233 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_textlabel.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include #include #include static QRect qwtItemRect( int renderFlags, const QRectF &rect, const QSizeF &itemSize ) { int x; if ( renderFlags & Qt::AlignLeft ) { x = rect.left(); } else if ( renderFlags & Qt::AlignRight ) { x = rect.right() - itemSize.width(); } else { x = rect.center().x() - 0.5 * itemSize.width(); } int y; if ( renderFlags & Qt::AlignTop ) { y = rect.top(); } else if ( renderFlags & Qt::AlignBottom ) { y = rect.bottom() - itemSize.height(); } else { y = rect.center().y() - 0.5 * itemSize.height(); } return QRect( x, y, itemSize.width(), itemSize.height() ); } class QwtPlotTextLabel::PrivateData { public: PrivateData(): margin( 5 ) { } QwtText text; int margin; QPixmap pixmap; }; /*! \brief Constructor Initializes an text label with an empty text Sets the following item attributes: - QwtPlotItem::AutoScale: true - QwtPlotItem::Legend: false The z value is initialized by 150 \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ() */ QwtPlotTextLabel::QwtPlotTextLabel(): QwtPlotItem( QwtText( "Label" ) ) { d_data = new PrivateData; setItemAttribute( QwtPlotItem::AutoScale, false ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 150 ); } //! Destructor QwtPlotTextLabel::~QwtPlotTextLabel() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotTextLabel int QwtPlotTextLabel::rtti() const { return QwtPlotItem::Rtti_PlotTextLabel; } /*! Set the text The label will be aligned to the plot canvas according to the alignment flags of text. \param text Text to be displayed \sa text(), QwtText::renderFlags() */ void QwtPlotTextLabel::setText( const QwtText &text ) { if ( d_data->text != text ) { d_data->text = text; invalidateCache(); itemChanged(); } } /*! \return Text to be displayed \sa setText() */ QwtText QwtPlotTextLabel::text() const { return d_data->text; } /*! Set the margin The margin is the distance between the contentsRect() of the plot canvas and the rectangle where the label can be displayed. \param margin Margin \sa margin(), textRect() */ void QwtPlotTextLabel::setMargin( int margin ) { margin = qMax( margin, 0 ); if ( d_data->margin != margin ) { d_data->margin = margin; itemChanged(); } } /*! \return Margin added to the contentsMargins() of the canvas \sa setMargin() */ int QwtPlotTextLabel::margin() const { return d_data->margin; } /*! Draw the text label \param painter Painter \param xMap x Scale Map \param yMap y Scale Map \param canvasRect Contents rectangle of the canvas in painter coordinates \sa textRect() */ void QwtPlotTextLabel::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { Q_UNUSED( xMap ); Q_UNUSED( yMap ); const int m = d_data->margin; const QRectF rect = textRect( canvasRect.adjusted( m, m, -m, -m ), d_data->text.textSize( painter->font() ) ); const bool doAlign = QwtPainter::roundingAlignment( painter ); if ( doAlign ) { // when the paint device is aligning it is not one // where scalability matters ( PDF, SVG ). // As rendering a text label is an expensive operation // we use a cache. int pw = 0; if ( d_data->text.borderPen().style() != Qt::NoPen ) pw = qMax( d_data->text.borderPen().width(), 1 ); QRect pixmapRect; pixmapRect.setLeft( qFloor( rect.left() ) - pw ); pixmapRect.setTop( qFloor( rect.top() ) - pw ); pixmapRect.setRight( qCeil( rect.right() ) + pw ); pixmapRect.setBottom( qCeil( rect.bottom() ) + pw ); if ( d_data->pixmap.isNull() || ( pixmapRect.size() != d_data->pixmap.size() ) ) { d_data->pixmap = QPixmap( pixmapRect.size() ); d_data->pixmap.fill( Qt::transparent ); const QRect r( pw, pw, pixmapRect.width() - 2 * pw, pixmapRect.height() - 2 * pw ); QPainter pmPainter( &d_data->pixmap ); d_data->text.draw( &pmPainter, r ); } painter->drawPixmap( pixmapRect, d_data->pixmap ); } else { d_data->text.draw( painter, rect ); } } /*! \brief Align the text label \param rect Canvas rectangle with margins subtracted \param textSize Size required to draw the text \return A rectangle aligned according the the alignment flags of the text. \sa setMargin(), QwtText::renderFlags(), QwtText::textSize() */ QRectF QwtPlotTextLabel::textRect( const QRectF &rect, const QSizeF &textSize ) const { return qwtItemRect( d_data->text.renderFlags(), rect, textSize ); } //! Invalidate all internal cache void QwtPlotTextLabel::invalidateCache() { d_data->pixmap = QPixmap(); } qsstv_8.2.12/qwt/qwt_plot_textlabel.h000664 001750 001750 00000003435 12440612574 017701 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_TEXT_LABEL_H #define QWT_PLOT_TEXT_LABEL_H 1 #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_text.h" /*! \brief A plot item, which displays a text label QwtPlotTextLabel displays a text label aligned to the plot canvas. In opposite to QwtPlotMarker the position of the label is unrelated to plot coordinates. As drawing a text is an expensive operation the label is cached in a pixmap to speed up replots. \par Example The following code shows how to add a title. \verbatim QwtText title( "Plot Title" ); title.setRenderFlags( Qt::AlignHCenter | Qt::AlignTop ); QFont font; font.setBold( true ); title.setFont( font ); QwtPlotTextLabel *titleItem = new QwtPlotTextLabel(); titleItem->setText( title ); titleItem->attach( this ); \endverbatim \sa QwtPlotMarker */ class QWT_EXPORT QwtPlotTextLabel: public QwtPlotItem { public: QwtPlotTextLabel(); virtual ~QwtPlotTextLabel(); virtual int rtti() const; void setText( const QwtText & ); QwtText text() const; void setMargin( int margin ); int margin() const; virtual QRectF textRect( const QRectF &, const QSizeF & ) const; protected: virtual void draw( QPainter *, const QwtScaleMap &, const QwtScaleMap &, const QRectF &) const; void invalidateCache(); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_text_label.h000664 001750 001750 00000003466 12440612574 017006 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_TEXT_LABEL_H #define QWT_TEXT_LABEL_H #include "qwt_global.h" #include "qwt_text.h" #include class QString; class QPaintEvent; class QPainter; /*! \brief A Widget which displays a QwtText */ class QWT_EXPORT QwtTextLabel : public QFrame { Q_OBJECT Q_PROPERTY( int indent READ indent WRITE setIndent ) Q_PROPERTY( int margin READ margin WRITE setMargin ) Q_PROPERTY( QString plainText READ plainText WRITE setPlainText ) public: explicit QwtTextLabel( QWidget *parent = NULL ); explicit QwtTextLabel( const QwtText &, QWidget *parent = NULL ); virtual ~QwtTextLabel(); void setPlainText( const QString & ); QString plainText() const; public Q_SLOTS: void setText( const QString &, QwtText::TextFormat textFormat = QwtText::AutoText ); virtual void setText( const QwtText & ); void clear(); public: const QwtText &text() const; int indent() const; void setIndent( int ); int margin() const; void setMargin( int ); virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual int heightForWidth( int ) const; QRect textRect() const; virtual void drawText( QPainter *, const QRectF & ); protected: virtual void paintEvent( QPaintEvent *e ); virtual void drawContents( QPainter * ); private: void init(); int defaultIndent() const; class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_tradingcurve.cpp000664 001750 001750 00000043617 12440612574 020753 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_tradingcurve.h" #include "qwt_scale_map.h" #include "qwt_clipper.h" #include "qwt_painter.h" #include static inline bool qwtIsSampleInside( const QwtOHLCSample &sample, double tMin, double tMax, double vMin, double vMax ) { const double t = sample.time; const QwtInterval interval = sample.boundingInterval(); const bool isOffScreen = ( t < tMin ) || ( t > tMax ) || ( interval.maxValue() < vMin ) || ( interval.minValue() > vMax ); return !isOffScreen; } class QwtPlotTradingCurve::PrivateData { public: PrivateData(): symbolStyle( QwtPlotTradingCurve::CandleStick ), symbolExtent( 0.6 ), minSymbolWidth( 2.0 ), maxSymbolWidth( -1.0 ), paintAttributes( QwtPlotTradingCurve::ClipSymbols ) { symbolBrush[0] = QBrush( Qt::white ); symbolBrush[1] = QBrush( Qt::black ); } QwtPlotTradingCurve::SymbolStyle symbolStyle; double symbolExtent; double minSymbolWidth; double maxSymbolWidth; QPen symbolPen; QBrush symbolBrush[2]; // Increasing/Decreasing QwtPlotTradingCurve::PaintAttributes paintAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotTradingCurve::QwtPlotTradingCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotTradingCurve::QwtPlotTradingCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotTradingCurve::~QwtPlotTradingCurve() { delete d_data; } //! Initialize internal members void QwtPlotTradingCurve::init() { setItemAttribute( QwtPlotItem::Legend, true ); setItemAttribute( QwtPlotItem::AutoScale, true ); d_data = new PrivateData; setData( new QwtTradingChartData() ); setZ( 19.0 ); } //! \return QwtPlotItem::Rtti_PlotTradingCurve int QwtPlotTradingCurve::rtti() const { return QwtPlotTradingCurve::Rtti_PlotTradingCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotTradingCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \return True, when attribute is enabled \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotTradingCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Initialize data with an array of samples. \param samples Vector of samples \sa QwtPlotSeriesItem::setData() */ void QwtPlotTradingCurve::setSamples( const QVector &samples ) { setData( new QwtTradingChartData( samples ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotTradingCurve::setSamples( QwtSeriesData *data ) { setData( data ); } /*! Set the symbol style \param style Symbol style \sa symbolStyle(), setSymbolExtent(), setSymbolPen(), setSymbolBrush() */ void QwtPlotTradingCurve::setSymbolStyle( SymbolStyle style ) { if ( style != d_data->symbolStyle ) { d_data->symbolStyle = style; legendChanged(); itemChanged(); } } /*! \return Symbol style \sa setSymbolStyle(), symbolExtent(), symbolPen(), symbolBrush() */ QwtPlotTradingCurve::SymbolStyle QwtPlotTradingCurve::symbolStyle() const { return d_data->symbolStyle; } /*! Build and assign the symbol pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotTradingCurve::setSymbolPen( const QColor &color, qreal width, Qt::PenStyle style ) { setSymbolPen( QPen( color, width, style ) ); } /*! \brief Set the symbol pen The symbol pen is used for rendering the lines of the bar or candlestick symbols \sa symbolPen(), setSymbolBrush() */ void QwtPlotTradingCurve::setSymbolPen( const QPen &pen ) { if ( pen != d_data->symbolPen ) { d_data->symbolPen = pen; legendChanged(); itemChanged(); } } /*! \return Symbol pen \sa setSymbolPen(), symbolBrush() */ QPen QwtPlotTradingCurve::symbolPen() const { return d_data->symbolPen; } /*! Set the symbol brush \param direction Direction type \param brush Brush used to fill the body of all candlestick symbols with the direction \sa symbolBrush(), setSymbolPen() */ void QwtPlotTradingCurve::setSymbolBrush( Direction direction, const QBrush &brush ) { if ( direction < 0 || direction >= 2 ) return; if ( brush != d_data->symbolBrush[ direction ] ) { d_data->symbolBrush[ direction ] = brush; legendChanged(); itemChanged(); } } /*! \param direction \return Brush used to fill the body of all candlestick symbols with the direction \sa setSymbolPen(), symbolBrush() */ QBrush QwtPlotTradingCurve::symbolBrush( Direction direction ) const { if ( direction < 0 || direction >= 2 ) return QBrush(); return d_data->symbolBrush[ direction ]; } /*! \brief Set the extent of the symbol The width of the symbol is given in scale coordinates. When painting a symbol the width is scaled into paint device coordinates by scaledSymbolWidth(). The scaled width is bounded by minSymbolWidth(), maxSymbolWidth() \param extent Symbol width in scale coordinates \sa symbolExtent(), scaledSymbolWidth(), setMinSymbolWidth(), setMaxSymbolWidth() */ void QwtPlotTradingCurve::setSymbolExtent( double extent ) { extent = qMax( 0.0, extent ); if ( extent != d_data->symbolExtent ) { d_data->symbolExtent = extent; legendChanged(); itemChanged(); } } /*! \return Extent of a symbol in scale coordinates \sa setSymbolExtent(), scaledSymbolWidth(), minSymbolWidth(), maxSymbolWidth() */ double QwtPlotTradingCurve::symbolExtent() const { return d_data->symbolExtent; } /*! Set a minimum for the symbol width \param width Width in paint device coordinates \sa minSymbolWidth(), setMaxSymbolWidth(), setSymbolExtent() */ void QwtPlotTradingCurve::setMinSymbolWidth( double width ) { width = qMax( width, 0.0 ); if ( width != d_data->minSymbolWidth ) { d_data->minSymbolWidth = width; legendChanged(); itemChanged(); } } /*! \return Minmum for the symbol width \sa setMinSymbolWidth(), maxSymbolWidth(), symbolExtent() */ double QwtPlotTradingCurve::minSymbolWidth() const { return d_data->minSymbolWidth; } /*! Set a maximum for the symbol width A value <= 0.0 means an unlimited width \param width Width in paint device coordinates \sa maxSymbolWidth(), setMinSymbolWidth(), setSymbolExtent() */ void QwtPlotTradingCurve::setMaxSymbolWidth( double width ) { if ( width != d_data->maxSymbolWidth ) { d_data->maxSymbolWidth = width; legendChanged(); itemChanged(); } } /*! \return Maximum for the symbol width \sa setMaxSymbolWidth(), minSymbolWidth(), symbolExtent() */ double QwtPlotTradingCurve::maxSymbolWidth() const { return d_data->maxSymbolWidth; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotTradingCurve::boundingRect() const { QRectF rect = QwtPlotSeriesItem::boundingRect(); if ( rect.isValid() && orientation() == Qt::Vertical ) rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() ); return rect; } /*! Draw an interval of the curve \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. \sa drawSymbols() */ void QwtPlotTradingCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; painter->save(); if ( d_data->symbolStyle != QwtPlotTradingCurve::NoSymbol ) drawSymbols( painter, xMap, yMap, canvasRect, from, to ); painter->restore(); } /*! Draw symbols \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted \sa drawSeries() */ void QwtPlotTradingCurve::drawSymbols( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect ); const QwtScaleMap *timeMap, *valueMap; double tMin, tMax, vMin, vMax; const Qt::Orientation orient = orientation(); if ( orient == Qt::Vertical ) { timeMap = &xMap; valueMap = &yMap; tMin = tr.left(); tMax = tr.right(); vMin = tr.top(); vMax = tr.bottom(); } else { timeMap = &yMap; valueMap = &xMap; vMin = tr.left(); vMax = tr.right(); tMin = tr.top(); tMax = tr.bottom(); } const bool inverted = timeMap->isInverting(); const bool doClip = d_data->paintAttributes & ClipSymbols; const bool doAlign = QwtPainter::roundingAlignment( painter ); double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect ); if ( doAlign ) symbolWidth = qFloor( 0.5 * symbolWidth ) * 2.0; QPen pen = d_data->symbolPen; pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); for ( int i = from; i <= to; i++ ) { const QwtOHLCSample s = sample( i ); if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) ) { QwtOHLCSample translatedSample; translatedSample.time = timeMap->transform( s.time ); translatedSample.open = valueMap->transform( s.open ); translatedSample.high = valueMap->transform( s.high ); translatedSample.low = valueMap->transform( s.low ); translatedSample.close = valueMap->transform( s.close ); const int brushIndex = ( s.open < s.close ) ? QwtPlotTradingCurve::Increasing : QwtPlotTradingCurve::Decreasing; if ( doAlign ) { translatedSample.time = qRound( translatedSample.time ); translatedSample.open = qRound( translatedSample.open ); translatedSample.high = qRound( translatedSample.high ); translatedSample.low = qRound( translatedSample.low ); translatedSample.close = qRound( translatedSample.close ); } switch( d_data->symbolStyle ) { case Bar: { drawBar( painter, translatedSample, orient, inverted, symbolWidth ); break; } case CandleStick: { painter->setBrush( d_data->symbolBrush[ brushIndex ] ); drawCandleStick( painter, translatedSample, orient, symbolWidth ); break; } default: { if ( d_data->symbolStyle >= UserSymbol ) { painter->setBrush( d_data->symbolBrush[ brushIndex ] ); drawUserSymbol( painter, d_data->symbolStyle, translatedSample, orient, inverted, symbolWidth ); } } } } } } /*! \brief Draw a symbol for a symbol style >= UserSymbol The implementation does nothing and is intended to be overloaded \param painter Qt painter, initialized with pen/brush \param symbolStyle Symbol style \param sample Samples already translated into paint device coordinates \param orientation Vertical or horizontal \param inverted True, when the opposite scale ( Qt::Vertical: x, Qt::Horizontal: y ) is increasing in the opposite direction as QPainter coordinates. \param symbolWidth Width of the symbol in paint device coordinates */ void QwtPlotTradingCurve::drawUserSymbol( QPainter *painter, SymbolStyle symbolStyle, const QwtOHLCSample &sample, Qt::Orientation orientation, bool inverted, double symbolWidth ) const { Q_UNUSED( painter ) Q_UNUSED( symbolStyle ) Q_UNUSED( orientation ) Q_UNUSED( inverted ) Q_UNUSED( symbolWidth ) Q_UNUSED( sample ) } /*! \brief Draw a bar \param painter Qt painter, initialized with pen/brush \param sample Sample, already translated into paint device coordinates \param orientation Vertical or horizontal \param inverted When inverted is false the open tick is painted to the left/top, otherwise it is painted right/bottom. The close tick is painted in the opposite direction of the open tick. painted in the opposite d opposite direction. \param width Width or height of the candle, depending on the orientation \sa Bar */ void QwtPlotTradingCurve::drawBar( QPainter *painter, const QwtOHLCSample &sample, Qt::Orientation orientation, bool inverted, double width ) const { double w2 = 0.5 * width; if ( inverted ) w2 *= -1; if ( orientation == Qt::Vertical ) { QwtPainter::drawLine( painter, sample.time, sample.low, sample.time, sample.high ); QwtPainter::drawLine( painter, sample.time - w2, sample.open, sample.time, sample.open ); QwtPainter::drawLine( painter, sample.time + w2, sample.close, sample.time, sample.close ); } else { QwtPainter::drawLine( painter, sample.low, sample.time, sample.high, sample.time ); QwtPainter::drawLine( painter, sample.open, sample.time - w2, sample.open, sample.time ); QwtPainter::drawLine( painter, sample.close, sample.time + w2, sample.close, sample.time ); } } /*! \brief Draw a candle stick \param painter Qt painter, initialized with pen/brush \param sample Samples already translated into paint device coordinates \param orientation Vertical or horizontal \param width Width or height of the candle, depending on the orientation \sa CandleStick */ void QwtPlotTradingCurve::drawCandleStick( QPainter *painter, const QwtOHLCSample &sample, Qt::Orientation orientation, double width ) const { const double t = sample.time; const double v1 = qMin( sample.low, sample.high ); const double v2 = qMin( sample.open, sample.close ); const double v3 = qMax( sample.low, sample.high ); const double v4 = qMax( sample.open, sample.close ); if ( orientation == Qt::Vertical ) { QwtPainter::drawLine( painter, t, v1, t, v2 ); QwtPainter::drawLine( painter, t, v3, t, v4 ); QRectF rect( t - 0.5 * width, sample.open, width, sample.close - sample.open ); QwtPainter::drawRect( painter, rect ); } else { QwtPainter::drawLine( painter, v1, t, v2, t ); QwtPainter::drawLine( painter, v3, t, v4, t ); const QRectF rect( sample.open, t - 0.5 * width, sample.close - sample.open, width ); QwtPainter::drawRect( painter, rect ); } } /*! \return A rectangle filled with the color of the symbol pen \param index Index of the legend entry ( usually there is only one ) \param size Icon size \sa setLegendIconSize(), legendData() */ QwtGraphic QwtPlotTradingCurve::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ); return defaultIcon( d_data->symbolPen.color(), size ); } /*! Calculate the symbol width in paint coordinates The width is calculated by scaling the symbol extent into paint device coordinates bounded by the minimum/maximum symbol width. \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \return Symbol width in paint coordinates \sa symbolExtent(), minSymbolWidth(), maxSymbolWidth() */ double QwtPlotTradingCurve::scaledSymbolWidth( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { Q_UNUSED( canvasRect ); if ( d_data->maxSymbolWidth > 0.0 && d_data->minSymbolWidth >= d_data->maxSymbolWidth ) { return d_data->minSymbolWidth; } const QwtScaleMap *map = ( orientation() == Qt::Vertical ) ? &xMap : &yMap; const double pos = map->transform( map->s1() + d_data->symbolExtent ); double width = qAbs( pos - map->p1() ); width = qMax( width, d_data->minSymbolWidth ); if ( d_data->maxSymbolWidth > 0.0 ) width = qMin( width, d_data->maxSymbolWidth ); return width; } qsstv_8.2.12/qwt/qwt_thermo.cpp000664 001750 001750 00000055034 12440612574 016512 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_thermo.h" #include "qwt_scale_engine.h" #include "qwt_scale_draw.h" #include "qwt_scale_map.h" #include "qwt_color_map.h" #include #include #include #include #include #include static inline void qwtDrawLine( QPainter *painter, int pos, const QColor &color, const QRect &pipeRect, const QRect &liquidRect, Qt::Orientation orientation ) { painter->setPen( color ); if ( orientation == Qt::Horizontal ) { if ( pos >= liquidRect.left() && pos < liquidRect.right() ) painter->drawLine( pos, pipeRect.top(), pos, pipeRect.bottom() ); } else { if ( pos >= liquidRect.top() && pos < liquidRect.bottom() ) painter->drawLine( pipeRect.left(), pos, pipeRect.right(), pos ); } } QVector qwtTickList( const QwtScaleDiv &scaleDiv ) { QVector values; double lowerLimit = scaleDiv.interval().minValue(); double upperLimit = scaleDiv.interval().maxValue(); if ( upperLimit < lowerLimit ) qSwap( lowerLimit, upperLimit ); values += lowerLimit; for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList ticks = scaleDiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( v > lowerLimit && v < upperLimit ) values += v; } } values += upperLimit; return values; } class QwtThermo::PrivateData { public: PrivateData(): orientation( Qt::Vertical ), scalePosition( QwtThermo::TrailingScale ), spacing( 3 ), borderWidth( 2 ), pipeWidth( 10 ), alarmLevel( 0.0 ), alarmEnabled( false ), autoFillPipe( true ), originMode( QwtThermo::OriginMinimum ), origin( 0.0 ), colorMap( NULL ), value( 0.0 ) { rangeFlags = QwtInterval::IncludeBorders; } ~PrivateData() { delete colorMap; } Qt::Orientation orientation; QwtThermo::ScalePosition scalePosition; int spacing; int borderWidth; int pipeWidth; QwtInterval::BorderFlags rangeFlags; double alarmLevel; bool alarmEnabled; bool autoFillPipe; QwtThermo::OriginMode originMode; double origin; QwtColorMap *colorMap; double value; }; /*! Constructor \param parent Parent widget */ QwtThermo::QwtThermo( QWidget *parent ): QwtAbstractScale( parent ) { d_data = new PrivateData; QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->orientation == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); layoutThermo( true ); } //! Destructor QwtThermo::~QwtThermo() { delete d_data; } /*! \brief Exclude/Include min/max values According to the flags minValue() and maxValue() are included/excluded from the pipe. In case of an excluded value the corresponding tick is painted 1 pixel off of the pipeRect(). F.e. when a minimum of 0.0 has to be displayed as an empty pipe the minValue() needs to be excluded. \param flags Range flags \sa rangeFlags() */ void QwtThermo::setRangeFlags( QwtInterval::BorderFlags flags ) { if ( d_data->rangeFlags != flags ) { d_data->rangeFlags = flags; update(); } } /*! \return Range flags \sa setRangeFlags() */ QwtInterval::BorderFlags QwtThermo::rangeFlags() const { return d_data->rangeFlags; } /*! Set the current value. \param value New Value \sa value() */ void QwtThermo::setValue( double value ) { if ( d_data->value != value ) { d_data->value = value; update(); } } //! Return the value. double QwtThermo::value() const { return d_data->value; } /*! \brief Set a scale draw For changing the labels of the scales, it is necessary to derive from QwtScaleDraw and overload QwtScaleDraw::label(). \param scaleDraw ScaleDraw object, that has to be created with new and will be deleted in ~QwtThermo() or the next call of setScaleDraw(). */ void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw ) { setAbstractScaleDraw( scaleDraw ); } /*! \return the scale draw of the thermo \sa setScaleDraw() */ const QwtScaleDraw *QwtThermo::scaleDraw() const { return static_cast( abstractScaleDraw() ); } /*! \return the scale draw of the thermo \sa setScaleDraw() */ QwtScaleDraw *QwtThermo::scaleDraw() { return static_cast( abstractScaleDraw() ); } /*! Paint event handler \param event Paint event */ void QwtThermo::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); const QRect tRect = pipeRect(); if ( !tRect.contains( event->rect() ) ) { if ( d_data->scalePosition != QwtThermo::NoScale ) scaleDraw()->draw( &painter, palette() ); } const int bw = d_data->borderWidth; const QBrush brush = palette().brush( QPalette::Base ); qDrawShadePanel( &painter, tRect.adjusted( -bw, -bw, bw, bw ), palette(), true, bw, d_data->autoFillPipe ? &brush : NULL ); drawLiquid( &painter, tRect ); } /*! Resize event handler \param event Resize event */ void QwtThermo::resizeEvent( QResizeEvent *event ) { Q_UNUSED( event ); layoutThermo( false ); } /*! Qt change event handler \param event Event */ void QwtThermo::changeEvent( QEvent *event ) { switch( event->type() ) { case QEvent::StyleChange: case QEvent::FontChange: { layoutThermo( true ); break; } default: break; } } /*! Recalculate the QwtThermo geometry and layout based on pipeRect() and the fonts. \param update_geometry notify the layout system and call update to redraw the scale */ void QwtThermo::layoutThermo( bool update_geometry ) { const QRect tRect = pipeRect(); const int bw = d_data->borderWidth + d_data->spacing; const bool inverted = ( upperBound() < lowerBound() ); int from, to; if ( d_data->orientation == Qt::Horizontal ) { from = tRect.left(); to = tRect.right(); if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum ) { if ( inverted ) to++; else from--; } if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum ) { if ( inverted ) from--; else to++; } if ( d_data->scalePosition == QwtThermo::TrailingScale ) { scaleDraw()->setAlignment( QwtScaleDraw::TopScale ); scaleDraw()->move( from, tRect.top() - bw ); } else { scaleDraw()->setAlignment( QwtScaleDraw::BottomScale ); scaleDraw()->move( from, tRect.bottom() + bw ); } scaleDraw()->setLength( to - from ); } else // Qt::Vertical { from = tRect.top(); to = tRect.bottom(); if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum ) { if ( inverted ) from--; else to++; } if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum ) { if ( inverted ) to++; else from--; } if ( d_data->scalePosition == QwtThermo::LeadingScale ) { scaleDraw()->setAlignment( QwtScaleDraw::RightScale ); scaleDraw()->move( tRect.right() + bw, from ); } else { scaleDraw()->setAlignment( QwtScaleDraw::LeftScale ); scaleDraw()->move( tRect.left() - bw, from ); } scaleDraw()->setLength( to - from ); } if ( update_geometry ) { updateGeometry(); update(); } } /*! \return Bounding rectangle of the pipe ( without borders ) in widget coordinates */ QRect QwtThermo::pipeRect() const { int mbd = 0; if ( d_data->scalePosition != QwtThermo::NoScale ) { int d1, d2; scaleDraw()->getBorderDistHint( font(), d1, d2 ); mbd = qMax( d1, d2 ); } const int bw = d_data->borderWidth; const int scaleOff = bw + mbd; const QRect cr = contentsRect(); QRect pipeRect = cr; if ( d_data->orientation == Qt::Horizontal ) { pipeRect.adjust( scaleOff, 0, -scaleOff, 0 ); if ( d_data->scalePosition == QwtThermo::TrailingScale ) pipeRect.setTop( cr.top() + cr.height() - bw - d_data->pipeWidth ); else pipeRect.setTop( bw ); pipeRect.setHeight( d_data->pipeWidth ); } else // Qt::Vertical { pipeRect.adjust( 0, scaleOff, 0, -scaleOff ); if ( d_data->scalePosition == QwtThermo::LeadingScale ) pipeRect.setLeft( bw ); else pipeRect.setLeft( cr.left() + cr.width() - bw - d_data->pipeWidth ); pipeRect.setWidth( d_data->pipeWidth ); } return pipeRect; } /*! \brief Set the orientation. \param orientation Allowed values are Qt::Horizontal and Qt::Vertical. \sa orientation(), scalePosition() */ void QwtThermo::setOrientation( Qt::Orientation orientation ) { if ( orientation == d_data->orientation ) return; d_data->orientation = orientation; if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy sp = sizePolicy(); sp.transpose(); setSizePolicy( sp ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } layoutThermo( true ); } /*! \return Orientation \sa setOrientation() */ Qt::Orientation QwtThermo::orientation() const { return d_data->orientation; } /*! \brief Change how the origin is determined. \sa originMode(), serOrigin(), origin() */ void QwtThermo::setOriginMode( OriginMode m ) { if ( m == d_data->originMode ) return; d_data->originMode = m; update(); } /*! \return Mode, how the origin is determined. \sa setOriginMode(), serOrigin(), origin() */ QwtThermo::OriginMode QwtThermo::originMode() const { return d_data->originMode; } /*! \brief Specifies the custom origin. If originMode is set to OriginCustom this property controls where the liquid starts. \param origin New origin level \sa setOriginMode(), originMode(), origin() */ void QwtThermo::setOrigin( double origin ) { if ( origin == d_data->origin ) return; d_data->origin = origin; update(); } /*! \return Origin of the thermo, when OriginCustom is enabled \sa setOrigin(), setOriginMode(), originMode() */ double QwtThermo::origin() const { return d_data->origin; } /*! \brief Change the position of the scale \param scalePosition Position of the scale. \sa ScalePosition, scalePosition() */ void QwtThermo::setScalePosition( ScalePosition scalePosition ) { if ( d_data->scalePosition == scalePosition ) return; d_data->scalePosition = scalePosition; if ( testAttribute( Qt::WA_WState_Polished ) ) layoutThermo( true ); } /*! \return Scale position. \sa setScalePosition() */ QwtThermo::ScalePosition QwtThermo::scalePosition() const { return d_data->scalePosition; } //! Notify a scale change. void QwtThermo::scaleChange() { layoutThermo( true ); } /*! Redraw the liquid in thermometer pipe. \param painter Painter \param pipeRect Bounding rectangle of the pipe without borders */ void QwtThermo::drawLiquid( QPainter *painter, const QRect &pipeRect ) const { painter->save(); painter->setClipRect( pipeRect, Qt::IntersectClip ); painter->setPen( Qt::NoPen ); const QwtScaleMap scaleMap = scaleDraw()->scaleMap(); QRect liquidRect = fillRect( pipeRect ); if ( d_data->colorMap != NULL ) { const QwtInterval interval = scaleDiv().interval().normalized(); // Because the positions of the ticks are rounded // we calculate the colors for the rounded tick values QVector values = qwtTickList( scaleDraw()->scaleDiv() ); if ( scaleMap.isInverting() ) qSort( values.begin(), values.end(), qGreater() ); else qSort( values.begin(), values.end(), qLess() ); int from; if ( !values.isEmpty() ) { from = qRound( scaleMap.transform( values[0] ) ); qwtDrawLine( painter, from, d_data->colorMap->color( interval, values[0] ), pipeRect, liquidRect, d_data->orientation ); } for ( int i = 1; i < values.size(); i++ ) { const int to = qRound( scaleMap.transform( values[i] ) ); for ( int pos = from + 1; pos < to; pos++ ) { const double v = scaleMap.invTransform( pos ); qwtDrawLine( painter, pos, d_data->colorMap->color( interval, v ), pipeRect, liquidRect, d_data->orientation ); } qwtDrawLine( painter, to, d_data->colorMap->color( interval, values[i] ), pipeRect, liquidRect, d_data->orientation ); from = to; } } else { if ( !liquidRect.isEmpty() && d_data->alarmEnabled ) { const QRect r = alarmRect( liquidRect ); if ( !r.isEmpty() ) { painter->fillRect( r, palette().brush( QPalette::Highlight ) ); liquidRect = QRegion( liquidRect ).subtracted( r ).boundingRect(); } } painter->fillRect( liquidRect, palette().brush( QPalette::ButtonText ) ); } painter->restore(); } /*! \brief Change the spacing between pipe and scale A spacing of 0 means, that the backbone of the scale is below the pipe. The default setting is 3 pixels. \param spacing Number of pixels \sa spacing(); */ void QwtThermo::setSpacing( int spacing ) { if ( spacing <= 0 ) spacing = 0; if ( spacing != d_data->spacing ) { d_data->spacing = spacing; layoutThermo( true ); } } /*! \return Number of pixels between pipe and scale \sa setSpacing() */ int QwtThermo::spacing() const { return d_data->spacing; } /*! Set the border width of the pipe. \param width Border width \sa borderWidth() */ void QwtThermo::setBorderWidth( int width ) { if ( width <= 0 ) width = 0; if ( width != d_data->borderWidth ) { d_data->borderWidth = width; layoutThermo( true ); } } /*! \return Border width of the thermometer pipe. \sa setBorderWidth() */ int QwtThermo::borderWidth() const { return d_data->borderWidth; } /*! \brief Assign a color map for the fill color \param colorMap Color map \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setColorMap( QwtColorMap *colorMap ) { if ( colorMap != d_data->colorMap ) { delete d_data->colorMap; d_data->colorMap = colorMap; } } /*! \return Color map for the fill color \warning The alarm threshold has no effect, when a color map has been assigned */ QwtColorMap *QwtThermo::colorMap() { return d_data->colorMap; } /*! \return Color map for the fill color \warning The alarm threshold has no effect, when a color map has been assigned */ const QwtColorMap *QwtThermo::colorMap() const { return d_data->colorMap; } /*! \brief Change the brush of the liquid. Changes the QPalette::ButtonText brush of the palette. \param brush New brush. \sa fillBrush(), QWidget::setPalette() */ void QwtThermo::setFillBrush( const QBrush& brush ) { QPalette pal = palette(); pal.setBrush( QPalette::ButtonText, brush ); setPalette( pal ); } /*! \return Liquid ( QPalette::ButtonText ) brush. \sa setFillBrush(), QWidget::palette() */ QBrush QwtThermo::fillBrush() const { return palette().brush( QPalette::ButtonText ); } /*! \brief Specify the liquid brush above the alarm threshold Changes the QPalette::Highlight brush of the palette. \param brush New brush. \sa alarmBrush(), QWidget::setPalette() \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmBrush( const QBrush& brush ) { QPalette pal = palette(); pal.setBrush( QPalette::Highlight, brush ); setPalette( pal ); } /*! \return Liquid brush ( QPalette::Highlight ) above the alarm threshold. \sa setAlarmBrush(), QWidget::palette() \warning The alarm threshold has no effect, when a color map has been assigned */ QBrush QwtThermo::alarmBrush() const { return palette().brush( QPalette::Highlight ); } /*! Specify the alarm threshold. \param level Alarm threshold \sa alarmLevel() \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmLevel( double level ) { d_data->alarmLevel = level; d_data->alarmEnabled = 1; update(); } /*! \return Alarm threshold. \sa setAlarmLevel() \warning The alarm threshold has no effect, when a color map has been assigned */ double QwtThermo::alarmLevel() const { return d_data->alarmLevel; } /*! Change the width of the pipe. \param width Width of the pipe \sa pipeWidth() */ void QwtThermo::setPipeWidth( int width ) { if ( width > 0 ) { d_data->pipeWidth = width; layoutThermo( true ); } } /*! \return Width of the pipe. \sa setPipeWidth() */ int QwtThermo::pipeWidth() const { return d_data->pipeWidth; } /*! \brief Enable or disable the alarm threshold \param on true (disabled) or false (enabled) \warning The alarm threshold has no effect, when a color map has been assigned */ void QwtThermo::setAlarmEnabled( bool on ) { d_data->alarmEnabled = on; update(); } /*! \return True, when the alarm threshold is enabled. \warning The alarm threshold has no effect, when a color map has been assigned */ bool QwtThermo::alarmEnabled() const { return d_data->alarmEnabled; } /*! \return the minimum size hint \sa minimumSizeHint() */ QSize QwtThermo::sizeHint() const { return minimumSizeHint(); } /*! \return Minimum size hint \warning The return value depends on the font and the scale. \sa sizeHint() */ QSize QwtThermo::minimumSizeHint() const { int w = 0, h = 0; if ( d_data->scalePosition != NoScale ) { const int sdExtent = qCeil( scaleDraw()->extent( font() ) ); const int sdLength = scaleDraw()->minLength( font() ); w = sdLength; h = d_data->pipeWidth + sdExtent + d_data->spacing; } else // no scale { w = 200; h = d_data->pipeWidth; } if ( d_data->orientation == Qt::Vertical ) qSwap( w, h ); w += 2 * d_data->borderWidth; h += 2 * d_data->borderWidth; // finally add the margins int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); w += left + right; h += top + bottom; return QSize( w, h ); } /*! \brief Calculate the filled rectangle of the pipe \param pipeRect Rectangle of the pipe \return Rectangle to be filled ( fill and alarm brush ) \sa pipeRect(), alarmRect() */ QRect QwtThermo::fillRect( const QRect &pipeRect ) const { double origin; if ( d_data->originMode == OriginMinimum ) { origin = qMin( lowerBound(), upperBound() ); } else if ( d_data->originMode == OriginMaximum ) { origin = qMax( lowerBound(), upperBound() ); } else // OriginCustom { origin = d_data->origin; } const QwtScaleMap scaleMap = scaleDraw()->scaleMap(); int from = qRound( scaleMap.transform( d_data->value ) ); int to = qRound( scaleMap.transform( origin ) ); if ( to < from ) qSwap( from, to ); QRect fillRect = pipeRect; if ( d_data->orientation == Qt::Horizontal ) { fillRect.setLeft( from ); fillRect.setRight( to ); } else // Qt::Vertical { fillRect.setTop( from ); fillRect.setBottom( to ); } return fillRect.normalized(); } /*! \brief Calculate the alarm rectangle of the pipe \param fillRect Filled rectangle in the pipe \return Rectangle to be filled with the alarm brush \sa pipeRect(), fillRect(), alarmLevel(), alarmBrush() */ QRect QwtThermo::alarmRect( const QRect &fillRect ) const { QRect alarmRect( 0, 0, -1, -1); // something invalid if ( !d_data->alarmEnabled ) return alarmRect; const bool inverted = ( upperBound() < lowerBound() ); bool increasing; if ( d_data->originMode == OriginCustom ) { increasing = d_data->value > d_data->origin; } else { increasing = d_data->originMode == OriginMinimum; } const QwtScaleMap map = scaleDraw()->scaleMap(); const int alarmPos = qRound( map.transform( d_data->alarmLevel ) ); const int valuePos = qRound( map.transform( d_data->value ) ); if ( d_data->orientation == Qt::Horizontal ) { int v1, v2; if ( inverted ) { v1 = fillRect.left(); v2 = alarmPos - 1; v2 = qMin( v2, increasing ? fillRect.right() : valuePos ); } else { v1 = alarmPos + 1; v1 = qMax( v1, increasing ? fillRect.left() : valuePos ); v2 = fillRect.right(); } alarmRect.setRect( v1, fillRect.top(), v2 - v1 + 1, fillRect.height() ); } else { int v1, v2; if ( inverted ) { v1 = alarmPos + 1; v1 = qMax( v1, increasing ? fillRect.top() : valuePos ); v2 = fillRect.bottom(); } else { v1 = fillRect.top(); v2 = alarmPos - 1; v2 = qMin( v2, increasing ? fillRect.bottom() : valuePos ); } alarmRect.setRect( fillRect.left(), v1, fillRect.width(), v2 - v1 + 1 ); } return alarmRect; } qsstv_8.2.12/qwt/qwt_plot_tradingcurve.h000664 001750 001750 00000012150 12440612574 020404 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_TRADING_CURVE_H #define QWT_PLOT_TRADING_CURVE_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" /*! \brief QwtPlotTradingCurve illustrates movements in the price of a financial instrument over time. QwtPlotTradingCurve supports candlestick or bar ( OHLC ) charts that are used in the domain of technical analysis. While the length ( height or width depending on orientation() ) of each symbol depends on the corresponding OHLC sample the size of the other dimension can be controlled using: - setSymbolExtent() - setSymbolMinWidth() - setSymbolMaxWidth() The extent is a size in scale coordinates, so that the symbol width is increasing when the plot is zoomed in. Minimum/Maximum width is in widget coordinates independent from the zoom level. When setting the minimum and maximum to the same value, the width of the symbol is fixed. */ class QWT_EXPORT QwtPlotTradingCurve: public QwtPlotSeriesItem, QwtSeriesStore { public: /*! \brief Symbol styles. The default setting is QwtPlotSeriesItem::CandleStick. \sa setSymbolStyle(), symbolStyle() */ enum SymbolStyle { //! Nothing is displayed NoSymbol = -1, /*! A line on the chart shows the price range (the highest and lowest prices) over one unit of time, e.g. one day or one hour. Tick marks project from each side of the line indicating the opening and closing price. */ Bar, /*! The range between opening/closing price are displayed as a filled box. The fill brush depends on the direction of the price movement. The box is connected to the highest/lowest values by lines. */ CandleStick, /*! SymbolTypes >= UserSymbol are displayed by drawUserSymbol(), that needs to be overloaded and implemented in derived curve classes. \sa drawUserSymbol() */ UserSymbol = 100 }; /*! \brief Direction of a price movement */ enum Direction { //! The closing price is higher than the opening price Increasing, //! The closing price is lower than the opening price Decreasing }; /*! Attributes to modify the drawing algorithm. \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { //! Check if a symbol is on the plot canvas before painting it. ClipSymbols = 0x01 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotTradingCurve( const QString &title = QString::null ); explicit QwtPlotTradingCurve( const QwtText &title ); virtual ~QwtPlotTradingCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setSamples( const QVector & ); void setSamples( QwtSeriesData * ); void setSymbolStyle( SymbolStyle style ); SymbolStyle symbolStyle() const; void setSymbolPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setSymbolPen( const QPen & ); QPen symbolPen() const; void setSymbolBrush( Direction, const QBrush & ); QBrush symbolBrush( Direction ) const; void setSymbolExtent( double width ); double symbolExtent() const; void setMinSymbolWidth( double ); double minSymbolWidth() const; void setMaxSymbolWidth( double ); double maxSymbolWidth() const; virtual void drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: void init(); virtual void drawSymbols( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawUserSymbol( QPainter *, SymbolStyle, const QwtOHLCSample &, Qt::Orientation, bool inverted, double width ) const; void drawBar( QPainter *painter, const QwtOHLCSample &, Qt::Orientation, bool inverted, double width ) const; void drawCandleStick( QPainter *, const QwtOHLCSample &, Qt::Orientation, double width ) const; virtual double scaledSymbolWidth( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotTradingCurve::PaintAttributes ) #endif qsstv_8.2.12/qwt/qwt_plot_xml.cpp000664 001750 001750 00000002143 12440612574 017043 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" /*! This method is intended for manipulating the plot widget from a specific editor in the Qwt designer plugin. \warning The plot editor has never been implemented. */ void QwtPlot::applyProperties( const QString & /* xmlDocument */ ) { #if 0 // Temporary dummy code, for designer tests setTitle( xmlDocument ); replot(); #endif } /*! This method is intended for manipulating the plot widget from a specific editor in the Qwt designer plugin. \return QString::null \warning The plot editor has never been implemented. */ QString QwtPlot::grabProperties() const { #if 0 // Temporary dummy code, for designer tests return title().text(); #else return QString::null; #endif } qsstv_8.2.12/qwt/qwt_plot_zoneitem.cpp000664 001750 001750 00000016056 12440612574 020105 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_zoneitem.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include class QwtPlotZoneItem::PrivateData { public: PrivateData(): orientation( Qt::Vertical ), pen( Qt::NoPen ) { QColor c( Qt::darkGray ); c.setAlpha( 100 ); brush = QBrush( c ); } Qt::Orientation orientation; QPen pen; QBrush brush; QwtInterval interval; }; /*! \brief Constructor Initializes the zone with no pen and a semi transparent gray brush Sets the following item attributes: - QwtPlotItem::AutoScale: false - QwtPlotItem::Legend: false The z value is initialized by 5 \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ() */ QwtPlotZoneItem::QwtPlotZoneItem(): QwtPlotItem( QwtText( "Zone" ) ) { d_data = new PrivateData; setItemAttribute( QwtPlotItem::AutoScale, false ); setItemAttribute( QwtPlotItem::Legend, false ); setZ( 5 ); } //! Destructor QwtPlotZoneItem::~QwtPlotZoneItem() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotZone int QwtPlotZoneItem::rtti() const { return QwtPlotItem::Rtti_PlotZone; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotZoneItem::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! \brief Assign a pen The pen is used to draw the border lines of the zone \param pen Pen \sa pen(), setBrush() */ void QwtPlotZoneItem::setPen( const QPen &pen ) { if ( d_data->pen != pen ) { d_data->pen = pen; itemChanged(); } } /*! \return Pen used to draw the border lines \sa setPen(), brush() */ const QPen &QwtPlotZoneItem::pen() const { return d_data->pen; } /*! \brief Assign a brush The brush is used to fill the zone \param brush Brush \sa pen(), setBrush() */ void QwtPlotZoneItem::setBrush( const QBrush &brush ) { if ( d_data->brush != brush ) { d_data->brush = brush; itemChanged(); } } /*! \return Brush used to fill the zone \sa setPen(), brush() */ const QBrush &QwtPlotZoneItem::brush() const { return d_data->brush; } /*! \brief Set the orientation of the zone A horizontal zone highlights an interval of the y axis, a vertical zone of the x axis. It is unbounded in the opposite direction. \sa orientation(), QwtPlotItem::setAxes() */ void QwtPlotZoneItem::setOrientation( Qt::Orientation orientation ) { if ( d_data->orientation != orientation ) { d_data->orientation = orientation; itemChanged(); } } /*! \return Orientation of the zone \sa setOrientation() */ Qt::Orientation QwtPlotZoneItem::orientation() { return d_data->orientation; } /*! Set the interval of the zone For a horizontal zone the interval is related to the y axis, for a vertical zone it is related to the x axis. \param min Minimum of the interval \param max Maximum of the interval \sa interval(), setOrientation() */ void QwtPlotZoneItem::setInterval( double min, double max ) { setInterval( QwtInterval( min, max ) ); } /*! Set the interval of the zone For a horizontal zone the interval is related to the y axis, for a vertical zone it is related to the x axis. \param interval Zone interval \sa interval(), setOrientation() */ void QwtPlotZoneItem::setInterval( const QwtInterval &interval ) { if ( d_data->interval != interval ) { d_data->interval = interval; itemChanged(); } } /*! \return Zone interval \sa setInterval(), orientation() */ QwtInterval QwtPlotZoneItem::interval() const { return d_data->interval; } /*! Draw the zone \param painter Painter \param xMap x Scale Map \param yMap y Scale Map \param canvasRect Contents rectangle of the canvas in painter coordinates */ void QwtPlotZoneItem::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { if ( !d_data->interval.isValid() ) return; QPen pen = d_data->pen; pen.setCapStyle( Qt::FlatCap ); const bool doAlign = QwtPainter::roundingAlignment( painter ); if ( d_data->orientation == Qt::Horizontal ) { double y1 = yMap.transform( d_data->interval.minValue() ); double y2 = yMap.transform( d_data->interval.maxValue() ); if ( doAlign ) { y1 = qRound( y1 ); y2 = qRound( y2 ); } QRectF r( canvasRect.left(), y1, canvasRect.width(), y2 - y1 ); r = r.normalized(); if ( ( d_data->brush.style() != Qt::NoBrush ) && ( y1 != y2 ) ) { QwtPainter::fillRect( painter, r, d_data->brush ); } if ( d_data->pen.style() != Qt::NoPen ) { painter->setPen( d_data->pen ); QwtPainter::drawLine( painter, r.left(), r.top(), r.right(), r.top() ); QwtPainter::drawLine( painter, r.left(), r.bottom(), r.right(), r.bottom() ); } } else { double x1 = xMap.transform( d_data->interval.minValue() ); double x2 = xMap.transform( d_data->interval.maxValue() ); if ( doAlign ) { x1 = qRound( x1 ); x2 = qRound( x2 ); } QRectF r( x1, canvasRect.top(), x2 - x1, canvasRect.height() ); r = r.normalized(); if ( ( d_data->brush.style() != Qt::NoBrush ) && ( x1 != x2 ) ) { QwtPainter::fillRect( painter, r, d_data->brush ); } if ( d_data->pen.style() != Qt::NoPen ) { painter->setPen( d_data->pen ); QwtPainter::drawLine( painter, r.left(), r.top(), r.left(), r.bottom() ); QwtPainter::drawLine( painter, r.right(), r.top(), r.right(), r.bottom() ); } } } /*! The bounding rectangle is build from the interval in one direction and something invalid for the opposite direction. \return An invalid rectangle with valid boundaries in one direction */ QRectF QwtPlotZoneItem::boundingRect() const { QRectF br = QwtPlotItem::boundingRect(); const QwtInterval &intv = d_data->interval; if ( intv.isValid() ) { if ( d_data->orientation == Qt::Horizontal ) { br.setTop( intv.minValue() ); br.setBottom( intv.maxValue() ); } else { br.setLeft( intv.minValue() ); br.setRight( intv.maxValue() ); } } return br; } qsstv_8.2.12/qwt/qwt_plot_zoneitem.h000664 001750 001750 00000003337 12440612574 017550 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ZONE_ITEM_H #define QWT_PLOT_ZONE_ITEM_H #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_interval.h" class QPen; class QBrush; /*! \brief A plot item, which displays a zone A horizontal zone highlights an interval of the y axis - a vertical zone an interval of the x axis - and is unbounded in the opposite direction. It is filled with a brush and its border lines are optionally displayed with a pen. \note For displaying an area that is bounded for x and y coordinates use QwtPlotShapeItem */ class QWT_EXPORT QwtPlotZoneItem: public QwtPlotItem { public: explicit QwtPlotZoneItem(); virtual ~QwtPlotZoneItem(); virtual int rtti() const; void setOrientation( Qt::Orientation ); Qt::Orientation orientation(); void setInterval( double min, double max ); void setInterval( const QwtInterval & ); QwtInterval interval() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; virtual void draw( QPainter *, const QwtScaleMap &, const QwtScaleMap &, const QRectF &) const; virtual QRectF boundingRect() const; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_zoomer.cpp000664 001750 001750 00000035461 12440612574 017567 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_zoomer.h" #include "qwt_plot.h" #include "qwt_scale_div.h" #include "qwt_picker_machine.h" #include class QwtPlotZoomer::PrivateData { public: uint zoomRectIndex; QStack zoomStack; int maxStackDepth; }; /*! \brief Create a zoomer for a plot canvas. The zoomer is set to those x- and y-axis of the parent plot of the canvas that are enabled. If both or no x-axis are enabled, the picker is set to QwtPlot::xBottom. If both or no y-axis are enabled, it is set to QwtPlot::yLeft. The zoomer is initialized with a QwtPickerDragRectMachine, the tracker mode is set to QwtPicker::ActiveOnly and the rubber band is set to QwtPicker::RectRubberBand \param canvas Plot canvas to observe, also the parent object \param doReplot Call QwtPlot::replot() for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase() */ QwtPlotZoomer::QwtPlotZoomer( QWidget *canvas, bool doReplot ): QwtPlotPicker( canvas ) { if ( canvas ) init( doReplot ); } /*! \brief Create a zoomer for a plot canvas. The zoomer is initialized with a QwtPickerDragRectMachine, the tracker mode is set to QwtPicker::ActiveOnly and the rubber band is set to QwtPicker;;RectRubberBand \param xAxis X axis of the zoomer \param yAxis Y axis of the zoomer \param canvas Plot canvas to observe, also the parent object \param doReplot Call QwtPlot::replot() for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase() */ QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis, QWidget *canvas, bool doReplot ): QwtPlotPicker( xAxis, yAxis, canvas ) { if ( canvas ) init( doReplot ); } //! Init the zoomer, used by the constructors void QwtPlotZoomer::init( bool doReplot ) { d_data = new PrivateData; d_data->maxStackDepth = -1; setTrackerMode( ActiveOnly ); setRubberBand( RectRubberBand ); setStateMachine( new QwtPickerDragRectMachine() ); if ( doReplot && plot() ) plot()->replot(); setZoomBase( scaleRect() ); } QwtPlotZoomer::~QwtPlotZoomer() { delete d_data; } /*! \brief Limit the number of recursive zoom operations to depth. A value of -1 set the depth to unlimited, 0 disables zooming. If the current zoom rectangle is below depth, the plot is unzoomed. \param depth Maximum for the stack depth \sa maxStackDepth() \note depth doesn't include the zoom base, so zoomStack().count() might be maxStackDepth() + 1. */ void QwtPlotZoomer::setMaxStackDepth( int depth ) { d_data->maxStackDepth = depth; if ( depth >= 0 ) { // unzoom if the current depth is below d_data->maxStackDepth const int zoomOut = int( d_data->zoomStack.count() ) - 1 - depth; // -1 for the zoom base if ( zoomOut > 0 ) { zoom( -zoomOut ); for ( int i = int( d_data->zoomStack.count() ) - 1; i > int( d_data->zoomRectIndex ); i-- ) { ( void )d_data->zoomStack.pop(); // remove trailing rects } } } } /*! \return Maximal depth of the zoom stack. \sa setMaxStackDepth() */ int QwtPlotZoomer::maxStackDepth() const { return d_data->maxStackDepth; } /*! \return The zoom stack. zoomStack()[0] is the zoom base, zoomStack()[1] the first zoomed rectangle. \sa setZoomStack(), zoomRectIndex() */ const QStack &QwtPlotZoomer::zoomStack() const { return d_data->zoomStack; } /*! \return Initial rectangle of the zoomer \sa setZoomBase(), zoomRect() */ QRectF QwtPlotZoomer::zoomBase() const { return d_data->zoomStack[0]; } /*! Reinitialized the zoom stack with scaleRect() as base. \param doReplot Call QwtPlot::replot() for the attached plot before initializing the zoomer with its scales. This might be necessary, when the plot is in a state with pending scale changes. \sa zoomBase(), scaleRect() QwtPlot::autoReplot(), QwtPlot::replot(). */ void QwtPlotZoomer::setZoomBase( bool doReplot ) { QwtPlot *plt = plot(); if ( plt == NULL ) return; if ( doReplot ) plt->replot(); d_data->zoomStack.clear(); d_data->zoomStack.push( scaleRect() ); d_data->zoomRectIndex = 0; rescale(); } /*! \brief Set the initial size of the zoomer. base is united with the current scaleRect() and the zoom stack is reinitialized with it as zoom base. plot is zoomed to scaleRect(). \param base Zoom base \sa zoomBase(), scaleRect() */ void QwtPlotZoomer::setZoomBase( const QRectF &base ) { const QwtPlot *plt = plot(); if ( !plt ) return; const QRectF sRect = scaleRect(); const QRectF bRect = base | sRect; d_data->zoomStack.clear(); d_data->zoomStack.push( bRect ); d_data->zoomRectIndex = 0; if ( base != sRect ) { d_data->zoomStack.push( sRect ); d_data->zoomRectIndex++; } rescale(); } /*! \return Rectangle at the current position on the zoom stack. \sa zoomRectIndex(), scaleRect(). */ QRectF QwtPlotZoomer::zoomRect() const { return d_data->zoomStack[d_data->zoomRectIndex]; } /*! \return Index of current position of zoom stack. */ uint QwtPlotZoomer::zoomRectIndex() const { return d_data->zoomRectIndex; } /*! \brief Zoom in Clears all rectangles above the current position of the zoom stack and pushes the normalized rectangle on it. \note If the maximal stack depth is reached, zoom is ignored. \note The zoomed signal is emitted. */ void QwtPlotZoomer::zoom( const QRectF &rect ) { if ( d_data->maxStackDepth >= 0 && int( d_data->zoomRectIndex ) >= d_data->maxStackDepth ) { return; } const QRectF zoomRect = rect.normalized(); if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] ) { for ( uint i = int( d_data->zoomStack.count() ) - 1; i > d_data->zoomRectIndex; i-- ) { ( void )d_data->zoomStack.pop(); } d_data->zoomStack.push( zoomRect ); d_data->zoomRectIndex++; rescale(); Q_EMIT zoomed( zoomRect ); } } /*! \brief Zoom in or out Activate a rectangle on the zoom stack with an offset relative to the current position. Negative values of offset will zoom out, positive zoom in. A value of 0 zooms out to the zoom base. \param offset Offset relative to the current position of the zoom stack. \note The zoomed signal is emitted. \sa zoomRectIndex() */ void QwtPlotZoomer::zoom( int offset ) { if ( offset == 0 ) d_data->zoomRectIndex = 0; else { int newIndex = d_data->zoomRectIndex + offset; newIndex = qMax( 0, newIndex ); newIndex = qMin( int( d_data->zoomStack.count() ) - 1, newIndex ); d_data->zoomRectIndex = uint( newIndex ); } rescale(); Q_EMIT zoomed( zoomRect() ); } /*! \brief Assign a zoom stack In combination with other types of navigation it might be useful to modify to manipulate the complete zoom stack. \param zoomStack New zoom stack \param zoomRectIndex Index of the current position of zoom stack. In case of -1 the current position is at the top of the stack. \note The zoomed signal might be emitted. \sa zoomStack(), zoomRectIndex() */ void QwtPlotZoomer::setZoomStack( const QStack &zoomStack, int zoomRectIndex ) { if ( zoomStack.isEmpty() ) return; if ( d_data->maxStackDepth >= 0 && int( zoomStack.count() ) > d_data->maxStackDepth ) { return; } if ( zoomRectIndex < 0 || zoomRectIndex > int( zoomStack.count() ) ) zoomRectIndex = zoomStack.count() - 1; const bool doRescale = zoomStack[zoomRectIndex] != zoomRect(); d_data->zoomStack = zoomStack; d_data->zoomRectIndex = uint( zoomRectIndex ); if ( doRescale ) { rescale(); Q_EMIT zoomed( zoomRect() ); } } /*! Adjust the observed plot to zoomRect() \note Initiates QwtPlot::replot() */ void QwtPlotZoomer::rescale() { QwtPlot *plt = plot(); if ( !plt ) return; const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex]; if ( rect != scaleRect() ) { const bool doReplot = plt->autoReplot(); plt->setAutoReplot( false ); double x1 = rect.left(); double x2 = rect.right(); if ( !plt->axisScaleDiv( xAxis() ).isIncreasing() ) qSwap( x1, x2 ); plt->setAxisScale( xAxis(), x1, x2 ); double y1 = rect.top(); double y2 = rect.bottom(); if ( !plt->axisScaleDiv( yAxis() ).isIncreasing() ) qSwap( y1, y2 ); plt->setAxisScale( yAxis(), y1, y2 ); plt->setAutoReplot( doReplot ); plt->replot(); } } /*! Reinitialize the axes, and set the zoom base to their scales. \param xAxis X axis \param yAxis Y axis */ void QwtPlotZoomer::setAxis( int xAxis, int yAxis ) { if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() ) { QwtPlotPicker::setAxis( xAxis, yAxis ); setZoomBase( scaleRect() ); } } /*! Qt::MidButton zooms out one position on the zoom stack, Qt::RightButton to the zoom base. Changes the current position on the stack, but doesn't pop any rectangle. \note The mouse events can be changed, using QwtEventPattern::setMousePattern: 2, 1 */ void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me ) { if ( mouseMatch( MouseSelect2, me ) ) zoom( 0 ); else if ( mouseMatch( MouseSelect3, me ) ) zoom( -1 ); else if ( mouseMatch( MouseSelect6, me ) ) zoom( +1 ); else QwtPlotPicker::widgetMouseReleaseEvent( me ); } /*! Qt::Key_Plus zooms in, Qt::Key_Minus zooms out one position on the zoom stack, Qt::Key_Escape zooms out to the zoom base. Changes the current position on the stack, but doesn't pop any rectangle. \note The keys codes can be changed, using QwtEventPattern::setKeyPattern: 3, 4, 5 */ void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke ) { if ( !isActive() ) { if ( keyMatch( KeyUndo, ke ) ) zoom( -1 ); else if ( keyMatch( KeyRedo, ke ) ) zoom( +1 ); else if ( keyMatch( KeyHome, ke ) ) zoom( 0 ); } QwtPlotPicker::widgetKeyPressEvent( ke ); } /*! Move the current zoom rectangle. \param dx X offset \param dy Y offset \note The changed rectangle is limited by the zoom base */ void QwtPlotZoomer::moveBy( double dx, double dy ) { const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex]; moveTo( QPointF( rect.left() + dx, rect.top() + dy ) ); } /*! Move the the current zoom rectangle. \param pos New position \sa QRectF::moveTo() \note The changed rectangle is limited by the zoom base */ void QwtPlotZoomer::moveTo( const QPointF &pos ) { double x = pos.x(); double y = pos.y(); if ( x < zoomBase().left() ) x = zoomBase().left(); if ( x > zoomBase().right() - zoomRect().width() ) x = zoomBase().right() - zoomRect().width(); if ( y < zoomBase().top() ) y = zoomBase().top(); if ( y > zoomBase().bottom() - zoomRect().height() ) y = zoomBase().bottom() - zoomRect().height(); if ( x != zoomRect().left() || y != zoomRect().top() ) { d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y ); rescale(); } } /*! \brief Check and correct a selected rectangle Reject rectangles with a height or width < 2, otherwise expand the selected rectangle to a minimum size of 11x11 and accept it. \return true If the rectangle is accepted, or has been changed to an accepted one. */ bool QwtPlotZoomer::accept( QPolygon &pa ) const { if ( pa.count() < 2 ) return false; QRect rect = QRect( pa[0], pa[int( pa.count() ) - 1] ); rect = rect.normalized(); const int minSize = 2; if ( rect.width() < minSize && rect.height() < minSize ) return false; const int minZoomSize = 11; const QPoint center = rect.center(); rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) ); rect.moveCenter( center ); pa.resize( 2 ); pa[0] = rect.topLeft(); pa[1] = rect.bottomRight(); return true; } /*! \brief Limit zooming by a minimum rectangle \return zoomBase().width() / 10e4, zoomBase().height() / 10e4 */ QSizeF QwtPlotZoomer::minZoomSize() const { return QSizeF( d_data->zoomStack[0].width() / 10e4, d_data->zoomStack[0].height() / 10e4 ); } /*! Rejects selections, when the stack depth is too deep, or the zoomed rectangle is minZoomSize(). \sa minZoomSize(), maxStackDepth() */ void QwtPlotZoomer::begin() { if ( d_data->maxStackDepth >= 0 ) { if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) ) return; } const QSizeF minSize = minZoomSize(); if ( minSize.isValid() ) { const QSizeF sz = d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999; if ( minSize.width() >= sz.width() && minSize.height() >= sz.height() ) { return; } } QwtPlotPicker::begin(); } /*! Expand the selected rectangle to minZoomSize() and zoom in if accepted. \param ok If true, complete the selection and emit selected signals otherwise discard the selection. \sa accept(), minZoomSize() \return True if the selection has been accepted, false otherwise */ bool QwtPlotZoomer::end( bool ok ) { ok = QwtPlotPicker::end( ok ); if ( !ok ) return false; QwtPlot *plot = QwtPlotZoomer::plot(); if ( !plot ) return false; const QPolygon &pa = selection(); if ( pa.count() < 2 ) return false; QRect rect = QRect( pa[0], pa[int( pa.count() - 1 )] ); rect = rect.normalized(); QRectF zoomRect = invTransform( rect ).normalized(); const QSizeF minSize = minZoomSize(); if ( minSize.isValid() ) { const QPointF center = zoomRect.center(); zoomRect.setSize( zoomRect.size().expandedTo( minZoomSize() ) ); zoomRect.moveCenter( center ); } zoom( zoomRect ); return true; } qsstv_8.2.12/qwt/qwt_plot_zoomer.h000664 001750 001750 00000010306 12440612574 017223 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ZOOMER_H #define QWT_PLOT_ZOOMER_H #include "qwt_global.h" #include "qwt_plot_picker.h" #include /*! \brief QwtPlotZoomer provides stacked zooming for a plot widget QwtPlotZoomer selects rectangles from user inputs ( mouse or keyboard ) translates them into plot coordinates and adjusts the axes to them. The selection is supported by a rubber band and optionally by displaying the coordinates of the current mouse position. Zooming can be repeated as often as possible, limited only by maxStackDepth() or minZoomSize(). Each rectangle is pushed on a stack. The default setting how to select rectangles is a QwtPickerDragRectMachine with the following bindings: - QwtEventPattern::MouseSelect1\n The first point of the zoom rectangle is selected by a mouse press, the second point from the position, where the mouse is released. - QwtEventPattern::KeySelect1\n The first key press selects the first, the second key press selects the second point. - QwtEventPattern::KeyAbort\n Discard the selection in the state, where the first point is selected. To traverse the zoom stack the following bindings are used: - QwtEventPattern::MouseSelect3, QwtEventPattern::KeyUndo\n Zoom out one position on the zoom stack - QwtEventPattern::MouseSelect6, QwtEventPattern::KeyRedo\n Zoom in one position on the zoom stack - QwtEventPattern::MouseSelect2, QwtEventPattern::KeyHome\n Zoom to the zoom base The setKeyPattern() and setMousePattern() functions can be used to configure the zoomer actions. The following example shows, how to configure the 'I' and 'O' keys for zooming in and out one position on the zoom stack. The "Home" key is used to "unzoom" the plot. \code zoomer = new QwtPlotZoomer( plot ); zoomer->setKeyPattern( QwtEventPattern::KeyRedo, Qt::Key_I, Qt::ShiftModifier ); zoomer->setKeyPattern( QwtEventPattern::KeyUndo, Qt::Key_O, Qt::ShiftModifier ); zoomer->setKeyPattern( QwtEventPattern::KeyHome, Qt::Key_Home ); \endcode QwtPlotZoomer is tailored for plots with one x and y axis, but it is allowed to attach a second QwtPlotZoomer ( without rubber band and tracker ) for the other axes. \note The realtime example includes an derived zoomer class that adds scrollbars to the plot canvas. \sa QwtPlotPanner, QwtPlotMagnifier */ class QWT_EXPORT QwtPlotZoomer: public QwtPlotPicker { Q_OBJECT public: explicit QwtPlotZoomer( QWidget *, bool doReplot = true ); explicit QwtPlotZoomer( int xAxis, int yAxis, QWidget *, bool doReplot = true ); virtual ~QwtPlotZoomer(); virtual void setZoomBase( bool doReplot = true ); virtual void setZoomBase( const QRectF & ); QRectF zoomBase() const; QRectF zoomRect() const; virtual void setAxis( int xAxis, int yAxis ); void setMaxStackDepth( int ); int maxStackDepth() const; const QStack &zoomStack() const; void setZoomStack( const QStack &, int zoomRectIndex = -1 ); uint zoomRectIndex() const; public Q_SLOTS: void moveBy( double x, double y ); virtual void moveTo( const QPointF & ); virtual void zoom( const QRectF & ); virtual void zoom( int up ); Q_SIGNALS: /*! A signal emitting the zoomRect(), when the plot has been zoomed in or out. \param rect Current zoom rectangle. */ void zoomed( const QRectF &rect ); protected: virtual void rescale(); virtual QSizeF minZoomSize() const; virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void begin(); virtual bool end( bool ok = true ); virtual bool accept( QPolygon & ) const; private: void init( bool doReplot ); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_point_3d.cpp000664 001750 001750 00000001206 12440612574 016723 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_3d.h" #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtPoint3D &point ) { debug.nospace() << "QwtPoint3D(" << point.x() << "," << point.y() << "," << point.z() << ")"; return debug.space(); } #endif qsstv_8.2.12/qwt/qwt_point_3d.h000664 001750 001750 00000007571 12440612574 016403 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ /*! \file */ #ifndef QWT_POINT_3D_H #define QWT_POINT_3D_H 1 #include "qwt_global.h" #include #ifndef QT_NO_DEBUG_STREAM #include #endif /*! \brief QwtPoint3D class defines a 3D point in double coordinates */ class QWT_EXPORT QwtPoint3D { public: QwtPoint3D(); QwtPoint3D( double x, double y, double z ); QwtPoint3D( const QwtPoint3D & ); QwtPoint3D( const QPointF & ); bool isNull() const; double x() const; double y() const; double z() const; double &rx(); double &ry(); double &rz(); void setX( double x ); void setY( double y ); void setZ( double y ); QPointF toPoint() const; bool operator==( const QwtPoint3D & ) const; bool operator!=( const QwtPoint3D & ) const; private: double d_x; double d_y; double d_z; }; Q_DECLARE_TYPEINFO(QwtPoint3D, Q_MOVABLE_TYPE); #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtPoint3D & ); #endif /*! Constructs a null point. \sa isNull() */ inline QwtPoint3D::QwtPoint3D(): d_x( 0.0 ), d_y( 0.0 ), d_z( 0.0 ) { } //! Constructs a point with coordinates specified by x, y and z. inline QwtPoint3D::QwtPoint3D( double x, double y, double z = 0.0 ): d_x( x ), d_y( y ), d_z( z ) { } /*! Copy constructor. Constructs a point using the values of the point specified. */ inline QwtPoint3D::QwtPoint3D( const QwtPoint3D &other ): d_x( other.d_x ), d_y( other.d_y ), d_z( other.d_z ) { } /*! Constructs a point with x and y coordinates from a 2D point, and a z coordinate of 0. */ inline QwtPoint3D::QwtPoint3D( const QPointF &other ): d_x( other.x() ), d_y( other.y() ), d_z( 0.0 ) { } /*! \return True if the point is null; otherwise returns false. A point is considered to be null if x, y and z-coordinates are equal to zero. */ inline bool QwtPoint3D::isNull() const { return d_x == 0.0 && d_y == 0.0 && d_z == 0.0; } //! \return The x-coordinate of the point. inline double QwtPoint3D::x() const { return d_x; } //! \return The y-coordinate of the point. inline double QwtPoint3D::y() const { return d_y; } //! \return The z-coordinate of the point. inline double QwtPoint3D::z() const { return d_z; } //! \return A reference to the x-coordinate of the point. inline double &QwtPoint3D::rx() { return d_x; } //! \return A reference to the y-coordinate of the point. inline double &QwtPoint3D::ry() { return d_y; } //! \return A reference to the z-coordinate of the point. inline double &QwtPoint3D::rz() { return d_z; } //! Sets the x-coordinate of the point to the value specified by x. inline void QwtPoint3D::setX( double x ) { d_x = x; } //! Sets the y-coordinate of the point to the value specified by y. inline void QwtPoint3D::setY( double y ) { d_y = y; } //! Sets the z-coordinate of the point to the value specified by z. inline void QwtPoint3D::setZ( double z ) { d_z = z; } /*! \return 2D point, where the z coordinate is dropped. */ inline QPointF QwtPoint3D::toPoint() const { return QPointF( d_x, d_y ); } //! \return True, if this point and other are equal; otherwise returns false. inline bool QwtPoint3D::operator==( const QwtPoint3D &other ) const { return ( d_x == other.d_x ) && ( d_y == other.d_y ) && ( d_z == other.d_z ); } //! \return True if this rect and other are different; otherwise returns false. inline bool QwtPoint3D::operator!=( const QwtPoint3D &other ) const { return !operator==( other ); } #endif qsstv_8.2.12/qwt/qwt_point_data.cpp000664 001750 001750 00000015247 12440612574 017340 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_data.h" #include "qwt_math.h" #include /*! Constructor \param x Array of x values \param y Array of y values \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples() */ QwtPointArrayData::QwtPointArrayData( const QVector &x, const QVector &y ): d_x( x ), d_y( y ) { } /*! Constructor \param x Array of x values \param y Array of y values \param size Size of the x and y arrays \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples() */ QwtPointArrayData::QwtPointArrayData( const double *x, const double *y, size_t size ) { d_x.resize( size ); ::memcpy( d_x.data(), x, size * sizeof( double ) ); d_y.resize( size ); ::memcpy( d_y.data(), y, size * sizeof( double ) ); } /*! \brief Calculate the bounding rectangle The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtPointArrayData::boundingRect() const { if ( d_boundingRect.width() < 0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } //! \return Size of the data set size_t QwtPointArrayData::size() const { return qMin( d_x.size(), d_y.size() ); } /*! Return the sample at position i \param index Index \return Sample at position i */ QPointF QwtPointArrayData::sample( size_t index ) const { return QPointF( d_x[int( index )], d_y[int( index )] ); } //! \return Array of the x-values const QVector &QwtPointArrayData::xData() const { return d_x; } //! \return Array of the y-values const QVector &QwtPointArrayData::yData() const { return d_y; } /*! Constructor \param x Array of x values \param y Array of y values \param size Size of the x and y arrays \warning The programmer must assure that the memory blocks referenced by the pointers remain valid during the lifetime of the QwtPlotCPointer object. \sa QwtPlotCurve::setData(), QwtPlotCurve::setRawSamples() */ QwtCPointerData::QwtCPointerData( const double *x, const double *y, size_t size ): d_x( x ), d_y( y ), d_size( size ) { } /*! \brief Calculate the bounding rectangle The bounding rectangle is calculated once by iterating over all points and is stored for all following requests. \return Bounding rectangle */ QRectF QwtCPointerData::boundingRect() const { if ( d_boundingRect.width() < 0 ) d_boundingRect = qwtBoundingRect( *this ); return d_boundingRect; } //! \return Size of the data set size_t QwtCPointerData::size() const { return d_size; } /*! Return the sample at position i \param index Index \return Sample at position i */ QPointF QwtCPointerData::sample( size_t index ) const { return QPointF( d_x[int( index )], d_y[int( index )] ); } //! \return Array of the x-values const double *QwtCPointerData::xData() const { return d_x; } //! \return Array of the y-values const double *QwtCPointerData::yData() const { return d_y; } /*! Constructor \param size Number of points \param interval Bounding interval for the points \sa setInterval(), setSize() */ QwtSyntheticPointData::QwtSyntheticPointData( size_t size, const QwtInterval &interval ): d_size( size ), d_interval( interval ) { } /*! Change the number of points \param size Number of points \sa size(), setInterval() */ void QwtSyntheticPointData::setSize( size_t size ) { d_size = size; } /*! \return Number of points \sa setSize(), interval() */ size_t QwtSyntheticPointData::size() const { return d_size; } /*! Set the bounding interval \param interval Interval \sa interval(), setSize() */ void QwtSyntheticPointData::setInterval( const QwtInterval &interval ) { d_interval = interval.normalized(); } /*! \return Bounding interval \sa setInterval(), size() */ QwtInterval QwtSyntheticPointData::interval() const { return d_interval; } /*! Set a the "rectangle of interest" QwtPlotSeriesItem defines the current area of the plot canvas as "rect of interest" ( QwtPlotSeriesItem::updateScaleDiv() ). If interval().isValid() == false the x values are calculated in the interval rect.left() -> rect.right(). \sa rectOfInterest() */ void QwtSyntheticPointData::setRectOfInterest( const QRectF &rect ) { d_rectOfInterest = rect; d_intervalOfInterest = QwtInterval( rect.left(), rect.right() ).normalized(); } /*! \return "rectangle of interest" \sa setRectOfInterest() */ QRectF QwtSyntheticPointData::rectOfInterest() const { return d_rectOfInterest; } /*! \brief Calculate the bounding rectangle This implementation iterates over all points, what could often be implemented much faster using the characteristics of the series. When there are many points it is recommended to overload and reimplement this method using the characteristics of the series ( if possible ). \return Bounding rectangle */ QRectF QwtSyntheticPointData::boundingRect() const { if ( d_size == 0 || !( d_interval.isValid() || d_intervalOfInterest.isValid() ) ) { return QRectF( 1.0, 1.0, -2.0, -2.0 ); // something invalid } return qwtBoundingRect( *this ); } /*! Calculate the point from an index \param index Index \return QPointF(x(index), y(x(index))); \warning For invalid indices ( index < 0 || index >= size() ) (0, 0) is returned. */ QPointF QwtSyntheticPointData::sample( size_t index ) const { if ( index >= d_size ) return QPointF( 0, 0 ); const double xValue = x( index ); const double yValue = y( xValue ); return QPointF( xValue, yValue ); } /*! Calculate a x-value from an index x values are calculated by dividing an interval into equidistant steps. If !interval().isValid() the interval is calculated from the "rectangle of interest". \param index Index of the requested point \return Calculated x coordinate \sa interval(), rectOfInterest(), y() */ double QwtSyntheticPointData::x( uint index ) const { const QwtInterval &interval = d_interval.isValid() ? d_interval : d_intervalOfInterest; if ( !interval.isValid() || d_size == 0 || index >= d_size ) return 0.0; const double dx = interval.width() / d_size; return interval.minValue() + index * dx; } qsstv_8.2.12/qwt/qwt_point_data.h000664 001750 001750 00000006770 12440612574 017006 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_POINT_DATA_H #define QWT_POINT_DATA_H 1 #include "qwt_global.h" #include "qwt_series_data.h" /*! \brief Interface for iterating over two QVector objects. */ class QWT_EXPORT QwtPointArrayData: public QwtSeriesData { public: QwtPointArrayData( const QVector &x, const QVector &y ); QwtPointArrayData( const double *x, const double *y, size_t size ); virtual QRectF boundingRect() const; virtual size_t size() const; virtual QPointF sample( size_t i ) const; const QVector &xData() const; const QVector &yData() const; private: QVector d_x; QVector d_y; }; /*! \brief Data class containing two pointers to memory blocks of doubles. */ class QWT_EXPORT QwtCPointerData: public QwtSeriesData { public: QwtCPointerData( const double *x, const double *y, size_t size ); virtual QRectF boundingRect() const; virtual size_t size() const; virtual QPointF sample( size_t i ) const; const double *xData() const; const double *yData() const; private: const double *d_x; const double *d_y; size_t d_size; }; /*! \brief Synthetic point data QwtSyntheticPointData provides a fixed number of points for an interval. The points are calculated in equidistant steps in x-direction. If the interval is invalid, the points are calculated for the "rectangle of interest", what normally is the displayed area on the plot canvas. In this mode you get different levels of detail, when zooming in/out. \par Example The following example shows how to implement a sinus curve. \code #include #include #include #include #include class SinusData: public QwtSyntheticPointData { public: SinusData(): QwtSyntheticPointData( 100 ) { } virtual double y( double x ) const { return qSin( x ); } }; int main(int argc, char **argv) { QApplication a( argc, argv ); QwtPlot plot; plot.setAxisScale( QwtPlot::xBottom, 0.0, 10.0 ); plot.setAxisScale( QwtPlot::yLeft, -1.0, 1.0 ); QwtPlotCurve *curve = new QwtPlotCurve( "y = sin(x)" ); curve->setData( new SinusData() ); curve->attach( &plot ); plot.show(); return a.exec(); } \endcode */ class QWT_EXPORT QwtSyntheticPointData: public QwtSeriesData { public: QwtSyntheticPointData( size_t size, const QwtInterval & = QwtInterval() ); void setSize( size_t size ); virtual size_t size() const; void setInterval( const QwtInterval& ); QwtInterval interval() const; virtual QRectF boundingRect() const; virtual QPointF sample( size_t i ) const; /*! Calculate a y value for a x value \param x x value \return Corresponding y value */ virtual double y( double x ) const = 0; virtual double x( uint index ) const; virtual void setRectOfInterest( const QRectF & ); QRectF rectOfInterest() const; private: size_t d_size; QwtInterval d_interval; QRectF d_rectOfInterest; QwtInterval d_intervalOfInterest; }; #endif qsstv_8.2.12/qwt/qwt_point_mapper.cpp000664 001750 001750 00000045424 12440612574 017713 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_mapper.h" #include "qwt_scale_map.h" #include "qwt_pixel_matrix.h" #include #include #include #include #if QT_VERSION >= 0x040400 #include #include #include #if !defined(QT_NO_QFUTURE) #define QWT_USE_THREADS 0 #endif #endif static QRectF qwtInvalidRect( 0.0, 0.0, -1.0, -1.0 ); // Helper class to work around the 5 parameters // limitation of QtConcurrent::run() class QwtDotsCommand { public: const QwtSeriesData *series; int from; int to; QRgb rgb; }; static void qwtRenderDots( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtDotsCommand command, const QPoint &pos, QImage *image ) { const QRgb rgb = command.rgb; QRgb *bits = reinterpret_cast( image->bits() ); const int w = image->width(); const int h = image->height(); const int x0 = pos.x(); const int y0 = pos.y(); for ( int i = command.from; i <= command.to; i++ ) { const QPointF sample = command.series->sample( i ); const int x = static_cast( xMap.transform( sample.x() ) + 0.5 ) - x0; const int y = static_cast( yMap.transform( sample.y() ) + 0.5 ) - y0; if ( x >= 0 && x < w && y >= 0 && y < h ) bits[ y * w + x ] = rgb; } } static inline int qwtRoundValue( double value ) { #if 1 return qRound( value ); #else // A little bit faster, but differs from qRound() // for negative values. Should be no problem as we are // rounding widgets coordinates, where negative values // are clipped off anyway ( at least when there is no // painter transformation ) return static_cast( value + 0.5 ); #endif } // some functors, so that the compile can inline struct QwtRoundI { inline int operator()( double value ) { return qwtRoundValue( value ); } }; struct QwtRoundF { inline double operator()( double value ) { return static_cast( qwtRoundValue( value ) ); } }; struct QwtNoRoundF { inline double operator()( double value ) { return value; } }; // mapping points without any filtering - beside checking // the bounding rectangle template static inline Polygon qwtToPoints( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, Round round ) { Polygon polyline( to - from + 1 ); Point *points = polyline.data(); int numPoints = 0; if ( boundingRect.isValid() ) { // iterating over all values // filtering out all points outside of // the bounding rectangle for ( int i = from; i <= to; i++ ) { const QPointF sample = series->sample( i ); const double x = xMap.transform( sample.x() ); const double y = yMap.transform( sample.y() ); if ( boundingRect.contains( x, y ) ) { points[ numPoints ].rx() = round( x ); points[ numPoints ].ry() = round( y ); numPoints++; } } polyline.resize( numPoints ); } else { // simply iterating over all values // without any filtering for ( int i = from; i <= to; i++ ) { const QPointF sample = series->sample( i ); const double x = xMap.transform( sample.x() ); const double y = yMap.transform( sample.y() ); points[ numPoints ].rx() = round( x ); points[ numPoints ].ry() = round( y ); numPoints++; } } return polyline; } static inline QPolygon qwtToPointsI( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) { return qwtToPoints( boundingRect, xMap, yMap, series, from, to, QwtRoundI() ); } template static inline QPolygonF qwtToPointsF( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, Round round ) { return qwtToPoints( boundingRect, xMap, yMap, series, from, to, round ); } // Mapping points with filtering out consecutive // points mapped to the same position template static inline Polygon qwtToPolylineFiltered( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, Round round ) { // in curves with many points consecutive points // are often mapped to the same position. As this might // result in empty lines ( or symbols hidden by others ) // we try to filter them out Polygon polyline( to - from + 1 ); Point *points = polyline.data(); const QPointF sample0 = series->sample( from ); points[0].rx() = round( xMap.transform( sample0.x() ) ); points[0].ry() = round( yMap.transform( sample0.y() ) ); int pos = 0; for ( int i = from + 1; i <= to; i++ ) { const QPointF sample = series->sample( i ); const Point p( round( xMap.transform( sample.x() ) ), round( yMap.transform( sample.y() ) ) ); if ( points[pos] != p ) points[++pos] = p; } polyline.resize( pos + 1 ); return polyline; } static inline QPolygon qwtToPolylineFilteredI( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) { return qwtToPolylineFiltered( xMap, yMap, series, from, to, QwtRoundI() ); } template static inline QPolygonF qwtToPolylineFilteredF( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, Round round ) { return qwtToPolylineFiltered( xMap, yMap, series, from, to, round ); } template static inline Polygon qwtToPointsFiltered( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) { // F.e. in scatter plots ( no connecting lines ) we // can sort out all duplicates ( not only consecutive points ) Polygon polygon( to - from + 1 ); Point *points = polygon.data(); QwtPixelMatrix pixelMatrix( boundingRect.toAlignedRect() ); int numPoints = 0; for ( int i = from; i <= to; i++ ) { const QPointF sample = series->sample( i ); const int x = qwtRoundValue( xMap.transform( sample.x() ) ); const int y = qwtRoundValue( yMap.transform( sample.y() ) ); if ( pixelMatrix.testAndSetPixel( x, y, true ) == false ) { points[ numPoints ].rx() = x; points[ numPoints ].ry() = y; numPoints++; } } polygon.resize( numPoints ); return polygon; } static inline QPolygon qwtToPointsFilteredI( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) { return qwtToPointsFiltered( boundingRect, xMap, yMap, series, from, to ); } static inline QPolygonF qwtToPointsFilteredF( const QRectF &boundingRect, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) { return qwtToPointsFiltered( boundingRect, xMap, yMap, series, from, to ); } class QwtPointMapper::PrivateData { public: PrivateData(): boundingRect( qwtInvalidRect ) { } QRectF boundingRect; QwtPointMapper::TransformationFlags flags; }; //! Constructor QwtPointMapper::QwtPointMapper() { d_data = new PrivateData(); } //! Destructor QwtPointMapper::~QwtPointMapper() { delete d_data; } /*! Set the flags affecting the transformation process \param flags Flags \sa flags(), setFlag() */ void QwtPointMapper::setFlags( TransformationFlags flags ) { d_data->flags = flags; } /*! \return Flags affecting the transformation process \sa setFlags(), setFlag() */ QwtPointMapper::TransformationFlags QwtPointMapper::flags() const { return d_data->flags; } /*! Modify a flag affecting the transformation process \param flag Flag type \param on Value \sa flag(), setFlags() */ void QwtPointMapper::setFlag( TransformationFlag flag, bool on ) { if ( on ) d_data->flags |= flag; else d_data->flags &= ~flag; } /*! \return True, when the flag is set \param flag Flag type \sa setFlag(), setFlags() */ bool QwtPointMapper::testFlag( TransformationFlag flag ) const { return d_data->flags & flag; } /*! Set a bounding rectangle for the point mapping algorithm A valid bounding rectangle can be used for optimizations \param rect Bounding rectangle \sa boundingRect() */ void QwtPointMapper::setBoundingRect( const QRectF &rect ) { d_data->boundingRect = rect; } /*! \return Bounding rectangle \sa setBoundingRect() */ QRectF QwtPointMapper::boundingRect() const { return d_data->boundingRect; } /*! \brief Translate a series of points into a QPolygonF When the WeedOutPoints flag is enabled consecutive points, that are mapped to the same position will be one point. When RoundPoints is set all points are rounded to integers but returned as PolygonF - what only makes sense when the further processing of the values need a QPolygonF. \param xMap x map \param yMap y map \param series Series of points to be mapped \param from Index of the first point to be painted \param to Index of the last point to be painted \return Translated polygon */ QPolygonF QwtPointMapper::toPolygonF( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const { QPolygonF polyline; if ( d_data->flags & WeedOutPoints ) { if ( d_data->flags & RoundPoints ) { polyline = qwtToPolylineFilteredF( xMap, yMap, series, from, to, QwtRoundF() ); } else { polyline = qwtToPolylineFilteredF( xMap, yMap, series, from, to, QwtNoRoundF() ); } } else { if ( d_data->flags & RoundPoints ) { polyline = qwtToPointsF( qwtInvalidRect, xMap, yMap, series, from, to, QwtRoundF() ); } else { polyline = qwtToPointsF( qwtInvalidRect, xMap, yMap, series, from, to, QwtNoRoundF() ); } } return polyline; } /*! \brief Translate a series of points into a QPolygon When the WeedOutPoints flag is enabled consecutive points, that are mapped to the same position will be one point. \param xMap x map \param yMap y map \param series Series of points to be mapped \param from Index of the first point to be painted \param to Index of the last point to be painted \return Translated polygon */ QPolygon QwtPointMapper::toPolygon( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const { QPolygon polyline; if ( d_data->flags & WeedOutPoints ) { polyline = qwtToPolylineFilteredI( xMap, yMap, series, from, to ); } else { polyline = qwtToPointsI( qwtInvalidRect, xMap, yMap, series, from, to ); } return polyline; } /*! \brief Translate a series into a QPolygonF - WeedOutPoints & RoundPoints & boundingRect().isValid() All points that are mapped to the same position will be one point. Points outside of the bounding rectangle are ignored. - WeedOutPoints & RoundPoints & !boundingRect().isValid() All consecutive points that are mapped to the same position will one point - WeedOutPoints & !RoundPoints All consecutive points that are mapped to the same position will one point - !WeedOutPoints & boundingRect().isValid() Points outside of the bounding rectangle are ignored. When RoundPoints is set all points are rounded to integers but returned as PolygonF - what only makes sense when the further processing of the values need a QPolygonF. \param xMap x map \param yMap y map \param series Series of points to be mapped \param from Index of the first point to be painted \param to Index of the last point to be painted \return Translated polygon */ QPolygonF QwtPointMapper::toPointsF( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const { QPolygonF points; if ( d_data->flags & WeedOutPoints ) { if ( d_data->flags & RoundPoints ) { if ( d_data->boundingRect.isValid() ) { points = qwtToPointsFilteredF( d_data->boundingRect, xMap, yMap, series, from, to ); } else { // without a bounding rectangle all we can // do is to filter out duplicates of // consecutive points points = qwtToPolylineFilteredF( xMap, yMap, series, from, to, QwtRoundF() ); } } else { // when rounding is not allowed we can't use // qwtToPointsFilteredF points = qwtToPolylineFilteredF( xMap, yMap, series, from, to, QwtNoRoundF() ); } } else { if ( d_data->flags & RoundPoints ) { points = qwtToPointsF( d_data->boundingRect, xMap, yMap, series, from, to, QwtRoundF() ); } else { points = qwtToPointsF( d_data->boundingRect, xMap, yMap, series, from, to, QwtNoRoundF() ); } } return points; } /*! \brief Translate a series of points into a QPolygon - WeedOutPoints & boundingRect().isValid() All points that are mapped to the same position will be one point. Points outside of the bounding rectangle are ignored. - WeedOutPoints & !boundingRect().isValid() All consecutive points that are mapped to the same position will one point - !WeedOutPoints & boundingRect().isValid() Points outside of the bounding rectangle are ignored. \param xMap x map \param yMap y map \param series Series of points to be mapped \param from Index of the first point to be painted \param to Index of the last point to be painted \return Translated polygon */ QPolygon QwtPointMapper::toPoints( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const { QPolygon points; if ( d_data->flags & WeedOutPoints ) { if ( d_data->boundingRect.isValid() ) { points = qwtToPointsFilteredI( d_data->boundingRect, xMap, yMap, series, from, to ); } else { // when we don't have the bounding rectangle all // we can do is to filter out consecutive duplicates points = qwtToPolylineFilteredI( xMap, yMap, series, from, to ); } } else { points = qwtToPointsI( d_data->boundingRect, xMap, yMap, series, from, to ); } return points; } /*! \brief Translate a series into a QImage \param xMap x map \param yMap y map \param series Series of points to be mapped \param from Index of the first point to be painted \param to Index of the last point to be painted \param pen Pen used for drawing a point of the image, where a point is mapped to \param antialiased True, when the dots should be displayed antialiased \param numThreads Number of threads to be used for rendering. If numThreads is set to 0, the system specific ideal thread count is used. \return Image displaying the series */ QImage QwtPointMapper::toImage( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, const QPen &pen, bool antialiased, uint numThreads ) const { Q_UNUSED( antialiased ) #if QWT_USE_THREADS if ( numThreads == 0 ) numThreads = QThread::idealThreadCount(); if ( numThreads <= 0 ) numThreads = 1; #else Q_UNUSED( numThreads ) #endif // a very special optimization for scatter plots // where every sample is mapped to one pixel only. const QRect rect = d_data->boundingRect.toAlignedRect(); QImage image( rect.size(), QImage::Format_ARGB32 ); image.fill( Qt::transparent ); if ( pen.width() <= 1 && pen.color().alpha() == 255 ) { QwtDotsCommand command; command.series = series; command.rgb = pen.color().rgba(); #if QWT_USE_THREADS const int numPoints = ( to - from + 1 ) / numThreads; QList< QFuture > futures; for ( uint i = 0; i < numThreads; i++ ) { const QPoint pos = rect.topLeft(); const int index0 = from + i * numPoints; if ( i == numThreads - 1 ) { command.from = index0; command.to = to; qwtRenderDots( xMap, yMap, command, pos, &image ); } else { command.from = index0; command.to = index0 + numPoints - 1; futures += QtConcurrent::run( &qwtRenderDots, xMap, yMap, command, pos, &image ); } } for ( int i = 0; i < futures.size(); i++ ) futures[i].waitForFinished(); #else command.from = from; command.to = to; qwtRenderDots( xMap, yMap, command, rect.topLeft(), &image ); #endif } else { // fallback implementation: to be replaced later by // setting the pixels of the image like above, TODO ... QPainter painter( &image ); painter.setPen( pen ); painter.setRenderHint( QPainter::Antialiasing, antialiased ); const int chunkSize = 1000; for ( int i = from; i <= to; i += chunkSize ) { const int indexTo = qMin( i + chunkSize - 1, to ); const QPolygon points = toPoints( xMap, yMap, series, i, indexTo ); painter.drawPoints( points ); } } return image; } qsstv_8.2.12/qwt/qwt_point_mapper.h000664 001750 001750 00000005202 12440612574 017346 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_POINT_MAPPER_H #define QWT_POINT_MAPPER_H #include "qwt_global.h" #include "qwt_series_data.h" #include class QwtScaleMap; class QPolygonF; class QPolygon; /*! \brief A helper class for translating a series of points QwtPointMapper is a collection of methods and optimizations for translating a series of points into paint device coordinates. It is used by QwtPlotCurve but might also be useful for similar plot items displaying a QwtSeriesData. */ class QWT_EXPORT QwtPointMapper { public: /*! \brief Flags affecting the transformation process \sa setFlag(), setFlags() */ enum TransformationFlag { //! Round points to integer values RoundPoints = 0x01, /*! Try to remove points, that are translated to the same position. */ WeedOutPoints = 0x02 }; /*! \brief Flags affecting the transformation process \sa setFlag(), setFlags() */ typedef QFlags TransformationFlags; QwtPointMapper(); ~QwtPointMapper(); void setFlags( TransformationFlags ); TransformationFlags flags() const; void setFlag( TransformationFlag, bool on = true ); bool testFlag( TransformationFlag ) const; void setBoundingRect( const QRectF & ); QRectF boundingRect() const; QPolygonF toPolygonF( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const; QPolygon toPolygon( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const; QPolygon toPoints( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const; QPolygonF toPointsF( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to ) const; QImage toImage( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData *series, int from, int to, const QPen &, bool antialiased, uint numThreads ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPointMapper::TransformationFlags ) #endif qsstv_8.2.12/qwt/qwt_point_polar.cpp000664 001750 001750 00000006122 12440612574 017534 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * QwtPolar Widget Library * Copyright (C) 2008 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_point_polar.h" #include "qwt_math.h" #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #endif /*! Convert and assign values from a point in Cartesian coordinates \param p Point in Cartesian coordinates \sa setPoint(), toPoint() */ QwtPointPolar::QwtPointPolar( const QPointF &p ) { d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) ); d_azimuth = qAtan2( p.y(), p.x() ); } /*! Convert and assign values from a point in Cartesian coordinates \param p Point in Cartesian coordinates */ void QwtPointPolar::setPoint( const QPointF &p ) { d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) ); d_azimuth = qAtan2( p.y(), p.x() ); } /*! Convert and return values in Cartesian coordinates \return Converted point in Cartesian coordinates \note Invalid or null points will be returned as QPointF(0.0, 0.0) \sa isValid(), isNull() */ QPointF QwtPointPolar::toPoint() const { if ( d_radius <= 0.0 ) return QPointF( 0.0, 0.0 ); const double x = d_radius * qCos( d_azimuth ); const double y = d_radius * qSin( d_azimuth ); return QPointF( x, y ); } /*! \brief Compare 2 points Two points are equal to each other if radius and azimuth-coordinates are the same. Points are not equal, when the azimuth differs, but other.azimuth() == azimuth() % (2 * PI). \return True if the point is equal to other; otherwise return false. \sa normalized() */ bool QwtPointPolar::operator==( const QwtPointPolar &other ) const { return d_radius == other.d_radius && d_azimuth == other.d_azimuth; } /*! Compare 2 points Two points are equal to each other if radius and azimuth-coordinates are the same. Points are not equal, when the azimuth differs, but other.azimuth() == azimuth() % (2 * PI). \return True if the point is not equal to other; otherwise return false. \sa normalized() */ bool QwtPointPolar::operator!=( const QwtPointPolar &other ) const { return d_radius != other.d_radius || d_azimuth != other.d_azimuth; } /*! Normalize radius and azimuth When the radius is < 0.0 it is set to 0.0. The azimuth is a value >= 0.0 and < 2 * M_PI. \return Normalized point */ QwtPointPolar QwtPointPolar::normalized() const { const double radius = qMax( d_radius, 0.0 ); double azimuth = d_azimuth; if ( azimuth < -2.0 * M_PI || azimuth >= 2 * M_PI ) azimuth = ::fmod( d_azimuth, 2 * M_PI ); if ( azimuth < 0.0 ) azimuth += 2 * M_PI; return QwtPointPolar( azimuth, radius ); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtPointPolar &point ) { debug.nospace() << "QwtPointPolar(" << point.azimuth() << "," << point.radius() << ")"; return debug.space(); } #endif qsstv_8.2.12/qwt/qwt_point_polar.h000664 001750 001750 00000010737 12440612574 017210 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ /*! \file */ #ifndef _QWT_POINT_POLAR_H_ #define _QWT_POINT_POLAR_H_ 1 #include "qwt_global.h" #include "qwt_math.h" #include #ifndef QT_NO_DEBUG_STREAM #include #endif /*! \brief A point in polar coordinates In polar coordinates a point is determined by an angle and a distance. See http://en.wikipedia.org/wiki/Polar_coordinate_system */ class QWT_EXPORT QwtPointPolar { public: QwtPointPolar(); QwtPointPolar( double azimuth, double radius ); QwtPointPolar( const QwtPointPolar & ); QwtPointPolar( const QPointF & ); void setPoint( const QPointF & ); QPointF toPoint() const; bool isValid() const; bool isNull() const; double radius() const; double azimuth() const; double &rRadius(); double &rAzimuth(); void setRadius( double ); void setAzimuth( double ); bool operator==( const QwtPointPolar & ) const; bool operator!=( const QwtPointPolar & ) const; QwtPointPolar normalized() const; private: double d_azimuth; double d_radius; }; /*! Constructs a null point, with a radius and azimuth set to 0.0. \sa QPointF::isNull() */ inline QwtPointPolar::QwtPointPolar(): d_azimuth( 0.0 ), d_radius( 0.0 ) { } /*! Constructs a point with coordinates specified by radius and azimuth. \param azimuth Azimuth \param radius Radius */ inline QwtPointPolar::QwtPointPolar( double azimuth, double radius ): d_azimuth( azimuth ), d_radius( radius ) { } /*! Constructs a point using the values of the point specified. \param other Other point */ inline QwtPointPolar::QwtPointPolar( const QwtPointPolar &other ): d_azimuth( other.d_azimuth ), d_radius( other.d_radius ) { } //! Returns true if radius() >= 0.0 inline bool QwtPointPolar::isValid() const { return d_radius >= 0.0; } //! Returns true if radius() >= 0.0 inline bool QwtPointPolar::isNull() const { return d_radius == 0.0; } //! Returns the radius. inline double QwtPointPolar::radius() const { return d_radius; } //! Returns the azimuth. inline double QwtPointPolar::azimuth() const { return d_azimuth; } //! Returns the radius. inline double &QwtPointPolar::rRadius() { return d_radius; } //! Returns the azimuth. inline double &QwtPointPolar::rAzimuth() { return d_azimuth; } //! Sets the radius to radius. inline void QwtPointPolar::setRadius( double radius ) { d_radius = radius; } //! Sets the atimuth to atimuth. inline void QwtPointPolar::setAzimuth( double azimuth ) { d_azimuth = azimuth; } #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtPointPolar & ); #endif inline QPoint qwtPolar2Pos( const QPoint &pole, double radius, double angle ) { const double x = pole.x() + radius * qCos( angle ); const double y = pole.y() - radius * qSin( angle ); return QPoint( qRound( x ), qRound( y ) ); } inline QPoint qwtDegree2Pos( const QPoint &pole, double radius, double angle ) { return qwtPolar2Pos( pole, radius, angle / 180.0 * M_PI ); } inline QPointF qwtPolar2Pos( const QPointF &pole, double radius, double angle ) { const double x = pole.x() + radius * qCos( angle ); const double y = pole.y() - radius * qSin( angle ); return QPointF( x, y); } inline QPointF qwtDegree2Pos( const QPointF &pole, double radius, double angle ) { return qwtPolar2Pos( pole, radius, angle / 180.0 * M_PI ); } inline QPointF qwtFastPolar2Pos( const QPointF &pole, double radius, double angle ) { #if QT_VERSION < 0x040601 const double x = pole.x() + radius * ::cos( angle ); const double y = pole.y() - radius * ::sin( angle ); #else const double x = pole.x() + radius * qFastCos( angle ); const double y = pole.y() - radius * qFastSin( angle ); #endif return QPointF( x, y); } inline QPointF qwtFastDegree2Pos( const QPointF &pole, double radius, double angle ) { return qwtFastPolar2Pos( pole, radius, angle / 180.0 * M_PI ); } inline QwtPointPolar qwtFastPos2Polar( const QPointF &pos ) { return QwtPointPolar( qwtFastAtan2( pos.y(), pos.x() ), qSqrt( qwtSqr( pos.x() ) + qwtSqr( pos.y() ) ) ); } #endif qsstv_8.2.12/qwt/qwt_raster_data.cpp000664 001750 001750 00000026524 12440612574 017507 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_raster_data.h" #include "qwt_point_3d.h" class QwtRasterData::ContourPlane { public: inline ContourPlane( double z ): d_z( z ) { } inline bool intersect( const QwtPoint3D vertex[3], QPointF line[2], bool ignoreOnPlane ) const; inline double z() const { return d_z; } private: inline int compare( double z ) const; inline QPointF intersection( const QwtPoint3D& p1, const QwtPoint3D &p2 ) const; double d_z; }; inline bool QwtRasterData::ContourPlane::intersect( const QwtPoint3D vertex[3], QPointF line[2], bool ignoreOnPlane ) const { bool found = true; // Are the vertices below (-1), on (0) or above (1) the plan ? const int eq1 = compare( vertex[0].z() ); const int eq2 = compare( vertex[1].z() ); const int eq3 = compare( vertex[2].z() ); /* (a) All the vertices lie below the contour level. (b) Two vertices lie below and one on the contour level. (c) Two vertices lie below and one above the contour level. (d) One vertex lies below and two on the contour level. (e) One vertex lies below, one on and one above the contour level. (f) One vertex lies below and two above the contour level. (g) Three vertices lie on the contour level. (h) Two vertices lie on and one above the contour level. (i) One vertex lies on and two above the contour level. (j) All the vertices lie above the contour level. */ static const int tab[3][3][3] = { // jump table to avoid nested case statements { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } }, { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } }, { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } } }; const int edgeType = tab[eq1+1][eq2+1][eq3+1]; switch ( edgeType ) { case 1: // d(0,0,-1), h(0,0,1) line[0] = vertex[0].toPoint(); line[1] = vertex[1].toPoint(); break; case 2: // d(-1,0,0), h(1,0,0) line[0] = vertex[1].toPoint(); line[1] = vertex[2].toPoint(); break; case 3: // d(0,-1,0), h(0,1,0) line[0] = vertex[2].toPoint(); line[1] = vertex[0].toPoint(); break; case 4: // e(0,-1,1), e(0,1,-1) line[0] = vertex[0].toPoint(); line[1] = intersection( vertex[1], vertex[2] ); break; case 5: // e(-1,0,1), e(1,0,-1) line[0] = vertex[1].toPoint(); line[1] = intersection( vertex[2], vertex[0] ); break; case 6: // e(-1,1,0), e(1,0,-1) line[0] = vertex[2].toPoint(); line[1] = intersection( vertex[0], vertex[1] ); break; case 7: // c(-1,1,-1), f(1,1,-1) line[0] = intersection( vertex[0], vertex[1] ); line[1] = intersection( vertex[1], vertex[2] ); break; case 8: // c(-1,-1,1), f(1,1,-1) line[0] = intersection( vertex[1], vertex[2] ); line[1] = intersection( vertex[2], vertex[0] ); break; case 9: // f(-1,1,1), c(1,-1,-1) line[0] = intersection( vertex[2], vertex[0] ); line[1] = intersection( vertex[0], vertex[1] ); break; case 10: // g(0,0,0) // The CONREC algorithm has no satisfying solution for // what to do, when all vertices are on the plane. if ( ignoreOnPlane ) found = false; else { line[0] = vertex[2].toPoint(); line[1] = vertex[0].toPoint(); } break; default: found = false; } return found; } inline int QwtRasterData::ContourPlane::compare( double z ) const { if ( z > d_z ) return 1; if ( z < d_z ) return -1; return 0; } inline QPointF QwtRasterData::ContourPlane::intersection( const QwtPoint3D& p1, const QwtPoint3D &p2 ) const { const double h1 = p1.z() - d_z; const double h2 = p2.z() - d_z; const double x = ( h2 * p1.x() - h1 * p2.x() ) / ( h2 - h1 ); const double y = ( h2 * p1.y() - h1 * p2.y() ) / ( h2 - h1 ); return QPointF( x, y ); } //! Constructor QwtRasterData::QwtRasterData() { } //! Destructor QwtRasterData::~QwtRasterData() { } /*! Set the bounding interval for the x, y or z coordinates. \param axis Axis \param interval Bounding interval \sa interval() */ void QwtRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval ) { d_intervals[axis] = interval; } /*! \brief Initialize a raster Before the composition of an image QwtPlotSpectrogram calls initRaster(), announcing the area and its resolution that will be requested. The default implementation does nothing, but for data sets that are stored in files, it might be good idea to reimplement initRaster(), where the data is resampled and loaded into memory. \param area Area of the raster \param raster Number of horizontal and vertical pixels \sa initRaster(), value() */ void QwtRasterData::initRaster( const QRectF &area, const QSize &raster ) { Q_UNUSED( area ); Q_UNUSED( raster ); } /*! \brief Discard a raster After the composition of an image QwtPlotSpectrogram calls discardRaster(). The default implementation does nothing, but if data has been loaded in initRaster(), it could deleted now. \sa initRaster(), value() */ void QwtRasterData::discardRaster() { } /*! \brief Pixel hint pixelHint() returns the geometry of a pixel, that can be used to calculate the resolution and alignment of the plot item, that is representing the data. Width and height of the hint need to be the horizontal and vertical distances between 2 neighbored points. The center of the hint has to be the position of any point ( it doesn't matter which one ). An empty hint indicates, that there are values for any detail level. Limiting the resolution of the image might significantly improve the performance and heavily reduce the amount of memory when rendering a QImage from the raster data. The default implementation returns an empty rectangle recommending to render in target device ( f.e. screen ) resolution. \param area In most implementations the resolution of the data doesn't depend on the requested area. \return Bounding rectangle of a pixel */ QRectF QwtRasterData::pixelHint( const QRectF &area ) const { Q_UNUSED( area ); return QRectF(); } /*! Calculate contour lines \param rect Bounding rectangle for the contour lines \param raster Number of data pixels of the raster data \param levels List of limits, where to insert contour lines \param flags Flags to customize the contouring algorithm \return Calculated contour lines An adaption of CONREC, a simple contouring algorithm. http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/ */ QwtRasterData::ContourLines QwtRasterData::contourLines( const QRectF &rect, const QSize &raster, const QList &levels, ConrecFlags flags ) const { ContourLines contourLines; if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() ) return contourLines; const double dx = rect.width() / raster.width(); const double dy = rect.height() / raster.height(); const bool ignoreOnPlane = flags & QwtRasterData::IgnoreAllVerticesOnLevel; const QwtInterval range = interval( Qt::ZAxis ); bool ignoreOutOfRange = false; if ( range.isValid() ) ignoreOutOfRange = flags & IgnoreOutOfRange; QwtRasterData *that = const_cast( this ); that->initRaster( rect, raster ); for ( int y = 0; y < raster.height() - 1; y++ ) { enum Position { Center, TopLeft, TopRight, BottomRight, BottomLeft, NumPositions }; QwtPoint3D xy[NumPositions]; for ( int x = 0; x < raster.width() - 1; x++ ) { const QPointF pos( rect.x() + x * dx, rect.y() + y * dy ); if ( x == 0 ) { xy[TopRight].setX( pos.x() ); xy[TopRight].setY( pos.y() ); xy[TopRight].setZ( value( xy[TopRight].x(), xy[TopRight].y() ) ); xy[BottomRight].setX( pos.x() ); xy[BottomRight].setY( pos.y() + dy ); xy[BottomRight].setZ( value( xy[BottomRight].x(), xy[BottomRight].y() ) ); } xy[TopLeft] = xy[TopRight]; xy[BottomLeft] = xy[BottomRight]; xy[TopRight].setX( pos.x() + dx ); xy[TopRight].setY( pos.y() ); xy[BottomRight].setX( pos.x() + dx ); xy[BottomRight].setY( pos.y() + dy ); xy[TopRight].setZ( value( xy[TopRight].x(), xy[TopRight].y() ) ); xy[BottomRight].setZ( value( xy[BottomRight].x(), xy[BottomRight].y() ) ); double zMin = xy[TopLeft].z(); double zMax = zMin; double zSum = zMin; for ( int i = TopRight; i <= BottomLeft; i++ ) { const double z = xy[i].z(); zSum += z; if ( z < zMin ) zMin = z; if ( z > zMax ) zMax = z; } if ( ignoreOutOfRange ) { if ( !range.contains( zMin ) || !range.contains( zMax ) ) continue; } if ( zMax < levels[0] || zMin > levels[levels.size() - 1] ) { continue; } xy[Center].setX( pos.x() + 0.5 * dx ); xy[Center].setY( pos.y() + 0.5 * dy ); xy[Center].setZ( 0.25 * zSum ); const int numLevels = levels.size(); for ( int l = 0; l < numLevels; l++ ) { const double level = levels[l]; if ( level < zMin || level > zMax ) continue; QPolygonF &lines = contourLines[level]; const ContourPlane plane( level ); QPointF line[2]; QwtPoint3D vertex[3]; for ( int m = TopLeft; m < NumPositions; m++ ) { vertex[0] = xy[m]; vertex[1] = xy[0]; vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft]; const bool intersects = plane.intersect( vertex, line, ignoreOnPlane ); if ( intersects ) { lines += line[0]; lines += line[1]; } } } } } that->discardRaster(); return contourLines; } qsstv_8.2.12/qwt/qwt_raster_data.h000664 001750 001750 00000005174 12440612574 017152 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_RASTER_DATA_H #define QWT_RASTER_DATA_H 1 #include "qwt_global.h" #include "qwt_interval.h" #include #include #include class QwtScaleMap; /*! \brief QwtRasterData defines an interface to any type of raster data. QwtRasterData is an abstract interface, that is used by QwtPlotRasterItem to find the values at the pixels of its raster. Often a raster item is used to display values from a matrix. Then the derived raster data class needs to implement some sort of resampling, that maps the raster of the matrix into the requested raster of the raster item ( depending on resolution and scales of the canvas ). */ class QWT_EXPORT QwtRasterData { public: //! Contour lines typedef QMap ContourLines; //! Flags to modify the contour algorithm enum ConrecFlag { //! Ignore all vertices on the same level IgnoreAllVerticesOnLevel = 0x01, //! Ignore all values, that are out of range IgnoreOutOfRange = 0x02 }; //! Flags to modify the contour algorithm typedef QFlags ConrecFlags; QwtRasterData(); virtual ~QwtRasterData(); virtual void setInterval( Qt::Axis, const QwtInterval & ); const QwtInterval &interval(Qt::Axis) const; virtual QRectF pixelHint( const QRectF & ) const; virtual void initRaster( const QRectF &, const QSize& raster ); virtual void discardRaster(); /*! \return the value at a raster position \param x X value in plot coordinates \param y Y value in plot coordinates */ virtual double value( double x, double y ) const = 0; virtual ContourLines contourLines( const QRectF &rect, const QSize &raster, const QList &levels, ConrecFlags ) const; class Contour3DPoint; class ContourPlane; private: // Disabled copy constructor and operator= QwtRasterData( const QwtRasterData & ); QwtRasterData &operator=( const QwtRasterData & ); QwtInterval d_intervals[3]; }; /*! \return Bounding interval for a axis \sa setInterval */ inline const QwtInterval &QwtRasterData::interval( Qt::Axis axis) const { return d_intervals[axis]; } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtRasterData::ConrecFlags ) #endif qsstv_8.2.12/qwt/qwt_thermo.h000664 001750 001750 00000011137 12440612574 016153 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_THERMO_H #define QWT_THERMO_H #include "qwt_global.h" #include "qwt_abstract_scale.h" #include "qwt_interval.h" class QwtScaleDraw; class QwtColorMap; /*! \brief The Thermometer Widget QwtThermo is a widget which displays a value in an interval. It supports: - a horizontal or vertical layout; - a range; - a scale; - an alarm level. \image html sysinfo.png The fill colors might be calculated from an optional color map If no color map has been assigned QwtThermo uses the following colors/brushes from the widget palette: - QPalette::Base Background of the pipe - QPalette::ButtonText Fill brush below the alarm level - QPalette::Highlight Fill brush for the values above the alarm level - QPalette::WindowText For the axis of the scale - QPalette::Text For the labels of the scale */ class QWT_EXPORT QwtThermo: public QwtAbstractScale { Q_OBJECT Q_ENUMS( ScalePosition ) Q_ENUMS( OriginMode ) Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ) Q_PROPERTY( ScalePosition scalePosition READ scalePosition WRITE setScalePosition ) Q_PROPERTY( OriginMode originMode READ originMode WRITE setOriginMode ) Q_PROPERTY( bool alarmEnabled READ alarmEnabled WRITE setAlarmEnabled ) Q_PROPERTY( double alarmLevel READ alarmLevel WRITE setAlarmLevel ) Q_PROPERTY( double origin READ origin WRITE setOrigin ) Q_PROPERTY( int spacing READ spacing WRITE setSpacing ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) Q_PROPERTY( int pipeWidth READ pipeWidth WRITE setPipeWidth ) Q_PROPERTY( double value READ value WRITE setValue ) public: /*! Position of the scale \sa setScalePosition(), setOrientation() */ enum ScalePosition { //! The slider has no scale NoScale, //! The scale is right of a vertical or below of a horizontal slider LeadingScale, //! The scale is left of a vertical or above of a horizontal slider TrailingScale }; /*! Origin mode. This property specifies where the beginning of the liquid is placed. \sa setOriginMode(), setOrigin() */ enum OriginMode { //! The origin is the minimum of the scale OriginMinimum, //! The origin is the maximum of the scale OriginMaximum, //! The origin is specified using the origin() property OriginCustom }; explicit QwtThermo( QWidget *parent = NULL ); virtual ~QwtThermo(); void setOrientation( Qt::Orientation ); Qt::Orientation orientation() const; void setScalePosition( ScalePosition ); ScalePosition scalePosition() const; void setSpacing( int ); int spacing() const; void setBorderWidth( int w ); int borderWidth() const; void setOriginMode( OriginMode ); OriginMode originMode() const; void setOrigin( double ); double origin() const; void setFillBrush( const QBrush &b ); QBrush fillBrush() const; void setAlarmBrush( const QBrush &b ); QBrush alarmBrush() const; void setAlarmLevel( double v ); double alarmLevel() const; void setAlarmEnabled( bool tf ); bool alarmEnabled() const; void setColorMap( QwtColorMap * ); QwtColorMap *colorMap(); const QwtColorMap *colorMap() const; void setPipeWidth( int w ); int pipeWidth() const; void setRangeFlags( QwtInterval::BorderFlags ); QwtInterval::BorderFlags rangeFlags() const; double value() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; void setScaleDraw( QwtScaleDraw * ); const QwtScaleDraw *scaleDraw() const; public Q_SLOTS: virtual void setValue( double val ); protected: virtual void drawLiquid( QPainter *, const QRect & ) const; virtual void scaleChange(); virtual void paintEvent( QPaintEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void changeEvent( QEvent * ); QwtScaleDraw *scaleDraw(); QRect pipeRect() const; QRect fillRect( const QRect & ) const; QRect alarmRect( const QRect & ) const; private: void layoutThermo( bool ); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_round_scale_draw.cpp000664 001750 001750 00000020151 12440612574 020517 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_round_scale_draw.h" #include "qwt_painter.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include "qwt_math.h" #include #include #include #include class QwtRoundScaleDraw::PrivateData { public: PrivateData(): center( 50.0, 50.0 ), radius( 50.0 ), startAngle( -135.0 ), endAngle( 135.0 ) { } QPointF center; double radius; double startAngle; double endAngle; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The center is set to (50, 50) with a radius of 50. The angle range is set to [-135, 135]. */ QwtRoundScaleDraw::QwtRoundScaleDraw() { d_data = new QwtRoundScaleDraw::PrivateData; setRadius( 50 ); scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle ); } //! Destructor QwtRoundScaleDraw::~QwtRoundScaleDraw() { delete d_data; } /*! Change of radius the scale Radius is the radius of the backbone without ticks and labels. \param radius New Radius \sa moveCenter() */ void QwtRoundScaleDraw::setRadius( double radius ) { d_data->radius = radius; } /*! Get the radius Radius is the radius of the backbone without ticks and labels. \return Radius of the scale \sa setRadius(), extent() */ double QwtRoundScaleDraw::radius() const { return d_data->radius; } /*! Move the center of the scale draw, leaving the radius unchanged \param center New center \sa setRadius() */ void QwtRoundScaleDraw::moveCenter( const QPointF ¢er ) { d_data->center = center; } //! Get the center of the scale QPointF QwtRoundScaleDraw::center() const { return d_data->center; } /*! \brief Adjust the baseline circle segment for round scales. The baseline will be drawn from min(angle1,angle2) to max(angle1, angle2). The default setting is [ -135, 135 ]. An angle of 0 degrees corresponds to the 12 o'clock position, and positive angles count in a clockwise direction. \param angle1 \param angle2 boundaries of the angle interval in degrees. \warning
  • The angle range is limited to [-360, 360] degrees. Angles exceeding this range will be clipped.
  • For angles more or equal than 360 degrees above or below min(angle1, angle2), scale marks will not be drawn.
  • If you need a counterclockwise scale, use QwtScaleDiv::setInterval()
*/ void QwtRoundScaleDraw::setAngleRange( double angle1, double angle2 ) { #if 0 angle1 = qBound( -360.0, angle1, 360.0 ); angle2 = qBound( -360.0, angle2, 360.0 ); #endif d_data->startAngle = angle1; d_data->endAngle = angle2; if ( d_data->startAngle == d_data->endAngle ) { d_data->startAngle -= 1; d_data->endAngle += 1; } scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle ); } /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone() */ void QwtRoundScaleDraw::drawLabel( QPainter *painter, double value ) const { const QwtText label = tickLabel( painter->font(), value ); if ( label.isEmpty() ) return; const double tval = scaleMap().transform( value ); if ( ( tval >= d_data->startAngle + 360.0 ) || ( tval <= d_data->startAngle - 360.0 ) ) { return; } double radius = d_data->radius; if ( hasComponent( QwtAbstractScaleDraw::Ticks ) || hasComponent( QwtAbstractScaleDraw::Backbone ) ) { radius += spacing(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) radius += tickLength( QwtScaleDiv::MajorTick ); const QSizeF sz = label.textSize( painter->font() ); const double arc = qwtRadians( tval ); const double x = d_data->center.x() + ( radius + sz.width() / 2.0 ) * qSin( arc ); const double y = d_data->center.y() - ( radius + sz.height() / 2.0 ) * qCos( arc ); const QRectF r( x - sz.width() / 2, y - sz.height() / 2, sz.width(), sz.height() ); label.draw( painter, r ); } /*! Draw a tick \param painter Painter \param value Value of the tick \param len Lenght of the tick \sa drawBackbone(), drawLabel() */ void QwtRoundScaleDraw::drawTick( QPainter *painter, double value, double len ) const { if ( len <= 0 ) return; const double tval = scaleMap().transform( value ); const double cx = d_data->center.x(); const double cy = d_data->center.y(); const double radius = d_data->radius; if ( ( tval < d_data->startAngle + 360.0 ) || ( tval > d_data->startAngle - 360.0 ) ) { const double arc = qwtRadians( tval ); const double sinArc = qSin( arc ); const double cosArc = qCos( arc ); const double x1 = cx + radius * sinArc; const double x2 = cx + ( radius + len ) * sinArc; const double y1 = cy - radius * cosArc; const double y2 = cy - ( radius + len ) * cosArc; QwtPainter::drawLine( painter, x1, y1, x2, y2 ); } } /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ void QwtRoundScaleDraw::drawBackbone( QPainter *painter ) const { const double deg1 = scaleMap().p1(); const double deg2 = scaleMap().p2(); const int a1 = qRound( qMin( deg1, deg2 ) - 90 ); const int a2 = qRound( qMax( deg1, deg2 ) - 90 ); const double radius = d_data->radius; const double x = d_data->center.x() - radius; const double y = d_data->center.y() - radius; painter->drawArc( QRectF( x, y, 2 * radius, 2 * radius ), -a2 * 16, ( a2 - a1 + 1 ) * 16 ); // counterclockwise } /*! Calculate the extent of the scale The extent is the distance between the baseline to the outermost pixel of the scale draw. radius() + extent() is an upper limit for the radius of the bounding circle. \param font Font used for painting the labels \return Calculated extent \sa setMinimumExtent(), minimumExtent() \warning The implemented algorithm is not too smart and calculates only an upper limit, that might be a few pixels too large */ double QwtRoundScaleDraw::extent( const QFont &font ) const { double d = 0.0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { const QwtScaleDiv &sd = scaleDiv(); const QList &ticks = sd.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double value = ticks[i]; if ( !sd.contains( value ) ) continue; const QwtText label = tickLabel( font, value ); if ( label.isEmpty() ) continue; const double tval = scaleMap().transform( value ); if ( ( tval < d_data->startAngle + 360 ) && ( tval > d_data->startAngle - 360 ) ) { const double arc = qwtRadians( tval ); const QSizeF sz = label.textSize( font ); const double off = qMax( sz.width(), sz.height() ); double x = off * qSin( arc ); double y = off * qCos( arc ); const double dist = qSqrt( x * x + y * y ); if ( dist > d ) d = dist; } } } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { d += maxTickLength(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { const double pw = qMax( 1, penWidth() ); // pen width can be zero d += pw; } if ( hasComponent( QwtAbstractScaleDraw::Labels ) && ( hasComponent( QwtAbstractScaleDraw::Ticks ) || hasComponent( QwtAbstractScaleDraw::Backbone ) ) ) { d += spacing(); } d = qMax( d, minimumExtent() ); return d; } qsstv_8.2.12/qwt/qwt_round_scale_draw.h000664 001750 001750 00000003642 12440612574 020172 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ROUND_SCALE_DRAW_H #define QWT_ROUND_SCALE_DRAW_H #include "qwt_global.h" #include "qwt_abstract_scale_draw.h" #include /*! \brief A class for drawing round scales QwtRoundScaleDraw can be used to draw round scales. The circle segment can be adjusted by setAngleRange(). The geometry of the scale can be specified with moveCenter() and setRadius(). After a scale division has been specified as a QwtScaleDiv object using QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s), the scale can be drawn with the QwtAbstractScaleDraw::draw() member. */ class QWT_EXPORT QwtRoundScaleDraw: public QwtAbstractScaleDraw { public: QwtRoundScaleDraw(); virtual ~QwtRoundScaleDraw(); void setRadius( double radius ); double radius() const; void moveCenter( double x, double y ); void moveCenter( const QPointF & ); QPointF center() const; void setAngleRange( double angle1, double angle2 ); virtual double extent( const QFont & ) const; protected: virtual void drawTick( QPainter *, double val, double len ) const; virtual void drawBackbone( QPainter * ) const; virtual void drawLabel( QPainter *, double val ) const; private: QwtRoundScaleDraw( const QwtRoundScaleDraw & ); QwtRoundScaleDraw &operator=( const QwtRoundScaleDraw &other ); class PrivateData; PrivateData *d_data; }; //! Move the center of the scale draw, leaving the radius unchanged inline void QwtRoundScaleDraw::moveCenter( double x, double y ) { moveCenter( QPointF( x, y ) ); } #endif qsstv_8.2.12/qwt/qwt_transform.cpp000664 001750 001750 00000006270 12440612574 017225 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_transform.h" #include "qwt_math.h" #if QT_VERSION < 0x040601 #define qExp(x) ::exp(x) #endif //! Smallest allowed value for logarithmic scales: 1.0e-150 QT_STATIC_CONST_IMPL double QwtLogTransform::LogMin = 1.0e-150; //! Largest allowed value for logarithmic scales: 1.0e150 QT_STATIC_CONST_IMPL double QwtLogTransform::LogMax = 1.0e150; //! Constructor QwtTransform::QwtTransform() { } //! Destructor QwtTransform::~QwtTransform() { } /*! \param value Value to be bounded \return value unmodified */ double QwtTransform::bounded( double value ) const { return value; } //! Constructor QwtNullTransform::QwtNullTransform(): QwtTransform() { } //! Destructor QwtNullTransform::~QwtNullTransform() { } /*! \param value Value to be transformed \return value unmodified */ double QwtNullTransform::transform( double value ) const { return value; } /*! \param value Value to be transformed \return value unmodified */ double QwtNullTransform::invTransform( double value ) const { return value; } //! \return Clone of the transformation QwtTransform *QwtNullTransform::copy() const { return new QwtNullTransform(); } //! Constructor QwtLogTransform::QwtLogTransform(): QwtTransform() { } //! Destructor QwtLogTransform::~QwtLogTransform() { } /*! \param value Value to be transformed \return log( value ) */ double QwtLogTransform::transform( double value ) const { return ::log( value ); } /*! \param value Value to be transformed \return exp( value ) */ double QwtLogTransform::invTransform( double value ) const { return qExp( value ); } /*! \param value Value to be bounded \return qBound( LogMin, value, LogMax ) */ double QwtLogTransform::bounded( double value ) const { return qBound( LogMin, value, LogMax ); } //! \return Clone of the transformation QwtTransform *QwtLogTransform::copy() const { return new QwtLogTransform(); } /*! Constructor \param exponent Exponent */ QwtPowerTransform::QwtPowerTransform( double exponent ): QwtTransform(), d_exponent( exponent ) { } //! Destructor QwtPowerTransform::~QwtPowerTransform() { } /*! \param value Value to be transformed \return Exponentiation preserving the sign */ double QwtPowerTransform::transform( double value ) const { if ( value < 0.0 ) return -qPow( -value, 1.0 / d_exponent ); else return qPow( value, 1.0 / d_exponent ); } /*! \param value Value to be transformed \return Inverse exponentiation preserving the sign */ double QwtPowerTransform::invTransform( double value ) const { if ( value < 0.0 ) return -qPow( -value, d_exponent ); else return qPow( value, d_exponent ); } //! \return Clone of the transformation QwtTransform *QwtPowerTransform::copy() const { return new QwtPowerTransform( d_exponent ); } qsstv_8.2.12/qwt/qwt_sampling_thread.cpp000664 001750 001750 00000004267 12440612574 020357 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_sampling_thread.h" #include "qwt_system_clock.h" class QwtSamplingThread::PrivateData { public: QwtSystemClock clock; double interval; bool isStopped; }; //! Constructor QwtSamplingThread::QwtSamplingThread( QObject *parent ): QThread( parent ) { d_data = new PrivateData; d_data->interval = 1000; // 1 second d_data->isStopped = true; } //! Destructor QwtSamplingThread::~QwtSamplingThread() { delete d_data; } /*! Change the interval (in ms), when sample() is called. The default interval is 1000.0 ( = 1s ) \param interval Interval \sa interval() */ void QwtSamplingThread::setInterval( double interval ) { if ( interval < 0.0 ) interval = 0.0; d_data->interval = interval; } /*! \return Interval (in ms), between 2 calls of sample() \sa setInterval() */ double QwtSamplingThread::interval() const { return d_data->interval; } /*! \return Time (in ms) since the thread was started \sa QThread::start(), run() */ double QwtSamplingThread::elapsed() const { if ( d_data->isStopped ) return 0.0; return d_data->clock.elapsed(); } /*! Terminate the collecting thread \sa QThread::start(), run() */ void QwtSamplingThread::stop() { d_data->isStopped = true; } /*! Loop collecting samples started from QThread::start() \sa stop() */ void QwtSamplingThread::run() { d_data->clock.start(); d_data->isStopped = false; while ( !d_data->isStopped ) { const double elapsed = d_data->clock.elapsed(); sample( elapsed / 1000.0 ); if ( d_data->interval > 0.0 ) { const double msecs = d_data->interval - ( d_data->clock.elapsed() - elapsed ); if ( msecs > 0.0 ) usleep( qRound( 1000.0 * msecs ) ); } } } qsstv_8.2.12/qwt/qwt_sampling_thread.h000664 001750 001750 00000002101 12440612574 020005 0ustar00jomajoma000000 000000 #ifndef _QWT_SAMPLING_THREAD_H_ #define _QWT_SAMPLING_THREAD_H_ #include "qwt_global.h" #include /*! \brief A thread collecting samples at regular intervals. Continuous signals are converted into a discrete signal by collecting samples at regular intervals. A discrete signal can be displayed by a QwtPlotSeriesItem on a QwtPlot widget. QwtSamplingThread starts a thread calling periodically sample(), to collect and store ( or emit ) a single sample. \sa QwtPlotCurve, QwtPlotSeriesItem */ class QWT_EXPORT QwtSamplingThread: public QThread { Q_OBJECT public: virtual ~QwtSamplingThread(); double interval() const; double elapsed() const; public Q_SLOTS: void setInterval( double interval ); void stop(); protected: explicit QwtSamplingThread( QObject *parent = NULL ); virtual void run(); /*! Collect a sample \param elapsed Time since the thread was started in milliseconds */ virtual void sample( double elapsed ) = 0; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_scale_div.cpp000664 001750 001750 00000016626 12440612574 017151 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_div.h" #include "qwt_math.h" #include /*! Construct a division without ticks \param lowerBound First boundary \param upperBound Second boundary \note lowerBound might be greater than upperBound for inverted scales */ QwtScaleDiv::QwtScaleDiv( double lowerBound, double upperBound ): d_lowerBound( lowerBound ), d_upperBound( upperBound ) { } /*! Construct a scale division \param interval Interval \param ticks List of major, medium and minor ticks */ QwtScaleDiv::QwtScaleDiv( const QwtInterval &interval, QList ticks[NTickTypes] ): d_lowerBound( interval.minValue() ), d_upperBound( interval.maxValue() ) { for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i] = ticks[i]; } /*! Construct a scale division \param lowerBound First boundary \param upperBound Second boundary \param ticks List of major, medium and minor ticks \note lowerBound might be greater than upperBound for inverted scales */ QwtScaleDiv::QwtScaleDiv( double lowerBound, double upperBound, QList ticks[NTickTypes] ): d_lowerBound( lowerBound ), d_upperBound( upperBound ) { for ( int i = 0; i < NTickTypes; i++ ) d_ticks[i] = ticks[i]; } /*! Construct a scale division \param lowerBound First boundary \param upperBound Second boundary \param minorTicks List of minor ticks \param mediumTicks List medium ticks \param majorTicks List of major ticks \note lowerBound might be greater than upperBound for inverted scales */ QwtScaleDiv::QwtScaleDiv( double lowerBound, double upperBound, const QList &minorTicks, const QList &mediumTicks, const QList &majorTicks ): d_lowerBound( lowerBound ), d_upperBound( upperBound ) { d_ticks[ MinorTick ] = minorTicks; d_ticks[ MediumTick ] = mediumTicks; d_ticks[ MajorTick ] = majorTicks; } /*! Change the interval \param lowerBound First boundary \param upperBound Second boundary \note lowerBound might be greater than upperBound for inverted scales */ void QwtScaleDiv::setInterval( double lowerBound, double upperBound ) { d_lowerBound = lowerBound; d_upperBound = upperBound; } /*! Change the interval \param interval Interval */ void QwtScaleDiv::setInterval( const QwtInterval &interval ) { d_lowerBound = interval.minValue(); d_upperBound = interval.maxValue(); } /*! \return lowerBound -> upperBound */ QwtInterval QwtScaleDiv::interval() const { return QwtInterval( d_lowerBound, d_upperBound ); } /*! Set the first boundary \param lowerBound First boundary \sa lowerBiound(), setUpperBound() */ void QwtScaleDiv::setLowerBound( double lowerBound ) { d_lowerBound = lowerBound; } /*! \return First boundary \sa upperBound() */ double QwtScaleDiv::lowerBound() const { return d_lowerBound; } /*! Set the second boundary \param upperBound Second boundary \sa upperBound(), setLowerBound() */ void QwtScaleDiv::setUpperBound( double upperBound ) { d_upperBound = upperBound; } /*! \return upper bound \sa lowerBound() */ double QwtScaleDiv::upperBound() const { return d_upperBound; } /*! \return upperBound() - lowerBound() */ double QwtScaleDiv::range() const { return d_upperBound - d_lowerBound; } /*! \brief Equality operator \return true if this instance is equal to other */ bool QwtScaleDiv::operator==( const QwtScaleDiv &other ) const { if ( d_lowerBound != other.d_lowerBound || d_upperBound != other.d_upperBound ) { return false; } for ( int i = 0; i < NTickTypes; i++ ) { if ( d_ticks[i] != other.d_ticks[i] ) return false; } return true; } /*! \brief Inequality \return true if this instance is not equal to other */ bool QwtScaleDiv::operator!=( const QwtScaleDiv &other ) const { return ( !( *this == other ) ); } //! Check if the scale division is empty( lowerBound() == upperBound() ) bool QwtScaleDiv::isEmpty() const { return ( d_lowerBound == d_upperBound ); } //! Check if the scale division is increasing( lowerBound() <= upperBound() ) bool QwtScaleDiv::isIncreasing() const { return d_lowerBound <= d_upperBound; } /*! Return if a value is between lowerBound() and upperBound() \param value Value \return true/false */ bool QwtScaleDiv::contains( double value ) const { const double min = qMin( d_lowerBound, d_upperBound ); const double max = qMax( d_lowerBound, d_upperBound ); return value >= min && value <= max; } /*! Invert the scale division \sa inverted() */ void QwtScaleDiv::invert() { qSwap( d_lowerBound, d_upperBound ); for ( int i = 0; i < NTickTypes; i++ ) { QList& ticks = d_ticks[i]; const int size = ticks.count(); const int size2 = size / 2; for ( int j = 0; j < size2; j++ ) qSwap( ticks[j], ticks[size - 1 - j] ); } } /*! \return A scale division with inverted boundaries and ticks \sa invert() */ QwtScaleDiv QwtScaleDiv::inverted() const { QwtScaleDiv other = *this; other.invert(); return other; } /*! Return a scale division with an interval [lowerBound, upperBound] where all ticks outside this interval are removed \param lowerBound Lower bound \param upperBound Upper bound \return Scale division with all ticks inside of the given interval \note lowerBound might be greater than upperBound for inverted scales */ QwtScaleDiv QwtScaleDiv::bounded( double lowerBound, double upperBound ) const { const double min = qMin( lowerBound, upperBound ); const double max = qMax( lowerBound, upperBound ); QwtScaleDiv sd; sd.setInterval( lowerBound, upperBound ); for ( int tickType = 0; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList &ticks = d_ticks[ tickType ]; QList boundedTicks; for ( int i = 0; i < ticks.size(); i++ ) { const double tick = ticks[i]; if ( tick >= min && tick <= max ) boundedTicks += tick; } sd.setTicks( tickType, boundedTicks ); } return sd; } /*! Assign ticks \param type MinorTick, MediumTick or MajorTick \param ticks Values of the tick positions */ void QwtScaleDiv::setTicks( int type, const QList &ticks ) { if ( type >= 0 && type < NTickTypes ) d_ticks[type] = ticks; } /*! Return a list of ticks \param type MinorTick, MediumTick or MajorTick \return Tick list */ QList QwtScaleDiv::ticks( int type ) const { if ( type >= 0 && type < NTickTypes ) return d_ticks[type]; return QList(); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtScaleDiv &scaleDiv ) { debug << scaleDiv.lowerBound() << "<->" << scaleDiv.upperBound(); debug << "Major: " << scaleDiv.ticks( QwtScaleDiv::MajorTick ); debug << "Medium: " << scaleDiv.ticks( QwtScaleDiv::MediumTick ); debug << "Minor: " << scaleDiv.ticks( QwtScaleDiv::MinorTick ); return debug; } #endif qsstv_8.2.12/qwt/qwt_scale_div.h000664 001750 001750 00000005304 12440612574 016605 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SCALE_DIV_H #define QWT_SCALE_DIV_H #include "qwt_global.h" #include "qwt_interval.h" #include #ifndef QT_NO_DEBUG_STREAM #include #endif /*! \brief A class representing a scale division A Qwt scale is defined by its boundaries and 3 list for the positions of the major, medium and minor ticks. The upperLimit() might be smaller than the lowerLimit() to indicate inverted scales. Scale divisions can be calculated from a QwtScaleEngine. \sa QwtScaleEngine::divideScale(), QwtPlot::setAxisScaleDiv(), QwtAbstractSlider::setScaleDiv() */ class QWT_EXPORT QwtScaleDiv { public: //! Scale tick types enum TickType { //! No ticks NoTick = -1, //! Minor ticks MinorTick, //! Medium ticks MediumTick, //! Major ticks MajorTick, //! Number of valid tick types NTickTypes }; explicit QwtScaleDiv( double lowerBound = 0.0, double upperBound = 0.0 ); explicit QwtScaleDiv( const QwtInterval &, QList[NTickTypes] ); explicit QwtScaleDiv( double lowerBound, double upperBound, QList[NTickTypes] ); explicit QwtScaleDiv( double lowerBound, double upperBound, const QList &minorTicks, const QList &mediumTicks, const QList &majorTicks ); bool operator==( const QwtScaleDiv & ) const; bool operator!=( const QwtScaleDiv & ) const; void setInterval( double lowerBound, double upperBound ); void setInterval( const QwtInterval & ); QwtInterval interval() const; void setLowerBound( double ); double lowerBound() const; void setUpperBound( double ); double upperBound() const; double range() const; bool contains( double value ) const; void setTicks( int tickType, const QList & ); QList ticks( int tickType ) const; bool isEmpty() const; bool isIncreasing() const; void invert(); QwtScaleDiv inverted() const; QwtScaleDiv bounded( double lowerBound, double upperBound ) const; private: double d_lowerBound; double d_upperBound; QList d_ticks[NTickTypes]; }; Q_DECLARE_TYPEINFO( QwtScaleDiv, Q_MOVABLE_TYPE ); #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtScaleDiv & ); #endif #endif qsstv_8.2.12/qwt/qwt_scale_draw.cpp000664 001750 001750 00000054132 12440612574 017316 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_draw.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include #include #if QT_VERSION < 0x040601 #define qFastSin(x) qSin(x) #define qFastCos(x) qCos(x) #endif class QwtScaleDraw::PrivateData { public: PrivateData(): len( 0 ), alignment( QwtScaleDraw::BottomScale ), labelAlignment( 0 ), labelRotation( 0.0 ) { } QPointF pos; double len; Alignment alignment; Qt::Alignment labelAlignment; double labelRotation; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The position is at (0, 0) with a length of 100. The orientation is QwtAbstractScaleDraw::Bottom. */ QwtScaleDraw::QwtScaleDraw() { d_data = new QwtScaleDraw::PrivateData; setLength( 100 ); } //! Destructor QwtScaleDraw::~QwtScaleDraw() { delete d_data; } /*! Return alignment of the scale \sa setAlignment() \return Alignment of the scale */ QwtScaleDraw::Alignment QwtScaleDraw::alignment() const { return d_data->alignment; } /*! Set the alignment of the scale \param align Alignment of the scale The default alignment is QwtScaleDraw::BottomScale \sa alignment() */ void QwtScaleDraw::setAlignment( Alignment align ) { d_data->alignment = align; } /*! Return the orientation TopScale, BottomScale are horizontal (Qt::Horizontal) scales, LeftScale, RightScale are vertical (Qt::Vertical) scales. \return Orientation of the scale \sa alignment() */ Qt::Orientation QwtScaleDraw::orientation() const { switch ( d_data->alignment ) { case TopScale: case BottomScale: return Qt::Horizontal; case LeftScale: case RightScale: default: return Qt::Vertical; } } /*! \brief Determine the minimum border distance This member function returns the minimum space needed to draw the mark labels at the scale's endpoints. \param font Font \param start Start border distance \param end End border distance */ void QwtScaleDraw::getBorderDistHint( const QFont &font, int &start, int &end ) const { start = 0; end = 0; if ( !hasComponent( QwtAbstractScaleDraw::Labels ) ) return; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); if ( ticks.count() == 0 ) return; // Find the ticks, that are mapped to the borders. // minTick is the tick, that is mapped to the top/left-most position // in widget coordinates. double minTick = ticks[0]; double minPos = scaleMap().transform( minTick ); double maxTick = minTick; double maxPos = minPos; for ( int i = 1; i < ticks.count(); i++ ) { const double tickPos = scaleMap().transform( ticks[i] ); if ( tickPos < minPos ) { minTick = ticks[i]; minPos = tickPos; } if ( tickPos > scaleMap().transform( maxTick ) ) { maxTick = ticks[i]; maxPos = tickPos; } } double e = 0.0; double s = 0.0; if ( orientation() == Qt::Vertical ) { s = -labelRect( font, minTick ).top(); s -= qAbs( minPos - qRound( scaleMap().p2() ) ); e = labelRect( font, maxTick ).bottom(); e -= qAbs( maxPos - scaleMap().p1() ); } else { s = -labelRect( font, minTick ).left(); s -= qAbs( minPos - scaleMap().p1() ); e = labelRect( font, maxTick ).right(); e -= qAbs( maxPos - scaleMap().p2() ); } if ( s < 0.0 ) s = 0.0; if ( e < 0.0 ) e = 0.0; start = qCeil( s ); end = qCeil( e ); } /*! Determine the minimum distance between two labels, that is necessary that the texts don't overlap. \param font Font \return The maximum width of a label \sa getBorderDistHint() */ int QwtScaleDraw::minLabelDist( const QFont &font ) const { if ( !hasComponent( QwtAbstractScaleDraw::Labels ) ) return 0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); if ( ticks.isEmpty() ) return 0; const QFontMetrics fm( font ); const bool vertical = ( orientation() == Qt::Vertical ); QRectF bRect1; QRectF bRect2 = labelRect( font, ticks[0] ); if ( vertical ) { bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() ); } double maxDist = 0.0; for ( int i = 1; i < ticks.count(); i++ ) { bRect1 = bRect2; bRect2 = labelRect( font, ticks[i] ); if ( vertical ) { bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() ); } double dist = fm.leading(); // space between the labels if ( bRect1.right() > 0 ) dist += bRect1.right(); if ( bRect2.left() < 0 ) dist += -bRect2.left(); if ( dist > maxDist ) maxDist = dist; } double angle = qwtRadians( labelRotation() ); if ( vertical ) angle += M_PI / 2; const double sinA = qFastSin( angle ); // qreal -> double if ( qFuzzyCompare( sinA + 1.0, 1.0 ) ) return qCeil( maxDist ); const int fmHeight = fm.ascent() - 2; // The distance we need until there is // the height of the label font. This height is needed // for the neighbored label. double labelDist = fmHeight / qFastSin( angle ) * qFastCos( angle ); if ( labelDist < 0 ) labelDist = -labelDist; // For text orientations close to the scale orientation if ( labelDist > maxDist ) labelDist = maxDist; // For text orientations close to the opposite of the // scale orientation if ( labelDist < fmHeight ) labelDist = fmHeight; return qCeil( labelDist ); } /*! Calculate the width/height that is needed for a vertical/horizontal scale. The extent is calculated from the pen width of the backbone, the major tick length, the spacing and the maximum width/height of the labels. \param font Font used for painting the labels \return Extent \sa minLength() */ double QwtScaleDraw::extent( const QFont &font ) const { double d = 0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { if ( orientation() == Qt::Vertical ) d = maxLabelWidth( font ); else d = maxLabelHeight( font ); if ( d > 0 ) d += spacing(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { d += maxTickLength(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { const double pw = qMax( 1, penWidth() ); // pen width can be zero d += pw; } d = qMax( d, minimumExtent() ); return d; } /*! Calculate the minimum length that is needed to draw the scale \param font Font used for painting the labels \return Minimum length that is needed to draw the scale \sa extent() */ int QwtScaleDraw::minLength( const QFont &font ) const { int startDist, endDist; getBorderDistHint( font, startDist, endDist ); const QwtScaleDiv &sd = scaleDiv(); const uint minorCount = sd.ticks( QwtScaleDiv::MinorTick ).count() + sd.ticks( QwtScaleDiv::MediumTick ).count(); const uint majorCount = sd.ticks( QwtScaleDiv::MajorTick ).count(); int lengthForLabels = 0; if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) lengthForLabels = minLabelDist( font ) * majorCount; int lengthForTicks = 0; if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { const double pw = qMax( 1, penWidth() ); // penwidth can be zero lengthForTicks = qCeil( ( majorCount + minorCount ) * ( pw + 1.0 ) ); } return startDist + endDist + qMax( lengthForLabels, lengthForTicks ); } /*! Find the position, where to paint a label The position has a distance that depends on the length of the ticks in direction of the alignment(). \param value Value \return Position, where to paint a label */ QPointF QwtScaleDraw::labelPosition( double value ) const { const double tval = scaleMap().transform( value ); double dist = spacing(); if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) dist += qMax( 1, penWidth() ); if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) dist += tickLength( QwtScaleDiv::MajorTick ); double px = 0; double py = 0; switch ( alignment() ) { case RightScale: { px = d_data->pos.x() + dist; py = tval; break; } case LeftScale: { px = d_data->pos.x() - dist; py = tval; break; } case BottomScale: { px = tval; py = d_data->pos.y() + dist; break; } case TopScale: { px = tval; py = d_data->pos.y() - dist; break; } } return QPointF( px, py ); } /*! Draw a tick \param painter Painter \param value Value of the tick \param len Length of the tick \sa drawBackbone(), drawLabel() */ void QwtScaleDraw::drawTick( QPainter *painter, double value, double len ) const { if ( len <= 0 ) return; const bool roundingAlignment = QwtPainter::roundingAlignment( painter ); QPointF pos = d_data->pos; double tval = scaleMap().transform( value ); if ( roundingAlignment ) tval = qRound( tval ); const int pw = penWidth(); int a = 0; if ( pw > 1 && roundingAlignment ) a = 1; switch ( alignment() ) { case LeftScale: { double x1 = pos.x() + a; double x2 = pos.x() + a - pw - len; if ( roundingAlignment ) { x1 = qRound( x1 ); x2 = qRound( x2 ); } QwtPainter::drawLine( painter, x1, tval, x2, tval ); break; } case RightScale: { double x1 = pos.x(); double x2 = pos.x() + pw + len; if ( roundingAlignment ) { x1 = qRound( x1 ); x2 = qRound( x2 ); } QwtPainter::drawLine( painter, x1, tval, x2, tval ); break; } case BottomScale: { double y1 = pos.y(); double y2 = pos.y() + pw + len; if ( roundingAlignment ) { y1 = qRound( y1 ); y2 = qRound( y2 ); } QwtPainter::drawLine( painter, tval, y1, tval, y2 ); break; } case TopScale: { double y1 = pos.y() + a; double y2 = pos.y() - pw - len + a; if ( roundingAlignment ) { y1 = qRound( y1 ); y2 = qRound( y2 ); } QwtPainter::drawLine( painter, tval, y1, tval, y2 ); break; } } } /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ void QwtScaleDraw::drawBackbone( QPainter *painter ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); const QPointF &pos = d_data->pos; const double len = d_data->len; const int pw = qMax( penWidth(), 1 ); // pos indicates a border not the center of the backbone line // so we need to shift its position depending on the pen width // and the alignment of the scale double off; if ( doAlign ) { if ( alignment() == LeftScale || alignment() == TopScale ) off = ( pw - 1 ) / 2; else off = pw / 2; } else { off = 0.5 * penWidth(); } switch ( alignment() ) { case LeftScale: { double x = pos.x() - off; if ( doAlign ) x = qRound( x ); QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len ); break; } case RightScale: { double x = pos.x() + off; if ( doAlign ) x = qRound( x ); QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len ); break; } case TopScale: { double y = pos.y() - off; if ( doAlign ) y = qRound( y ); QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y ); break; } case BottomScale: { double y = pos.y() + off; if ( doAlign ) y = qRound( y ); QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y ); break; } } } /*! \brief Move the position of the scale The meaning of the parameter pos depends on the alignment:
QwtScaleDraw::LeftScale
The origin is the topmost point of the backbone. The backbone is a vertical line. Scale marks and labels are drawn at the left of the backbone.
QwtScaleDraw::RightScale
The origin is the topmost point of the backbone. The backbone is a vertical line. Scale marks and labels are drawn at the right of the backbone.
QwtScaleDraw::TopScale
The origin is the leftmost point of the backbone. The backbone is a horizontal line. Scale marks and labels are drawn above the backbone.
QwtScaleDraw::BottomScale
The origin is the leftmost point of the backbone. The backbone is a horizontal line Scale marks and labels are drawn below the backbone.
\param pos Origin of the scale \sa pos(), setLength() */ void QwtScaleDraw::move( const QPointF &pos ) { d_data->pos = pos; updateMap(); } /*! \return Origin of the scale \sa move(), length() */ QPointF QwtScaleDraw::pos() const { return d_data->pos; } /*! Set the length of the backbone. The length doesn't include the space needed for overlapping labels. \param length Length of the backbone \sa move(), minLabelDist() */ void QwtScaleDraw::setLength( double length ) { #if 1 if ( length >= 0 && length < 10 ) length = 10; // why should we accept negative lengths ??? if ( length < 0 && length > -10 ) length = -10; #else length = qMax( length, 10 ); #endif d_data->len = length; updateMap(); } /*! \return the length of the backbone \sa setLength(), pos() */ double QwtScaleDraw::length() const { return d_data->len; } /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone(), boundingLabelRect() */ void QwtScaleDraw::drawLabel( QPainter *painter, double value ) const { QwtText lbl = tickLabel( painter->font(), value ); if ( lbl.isEmpty() ) return; QPointF pos = labelPosition( value ); QSizeF labelSize = lbl.textSize( painter->font() ); const QTransform transform = labelTransformation( pos, labelSize ); painter->save(); painter->setWorldTransform( transform, true ); lbl.draw ( painter, QRect( QPoint( 0, 0 ), labelSize.toSize() ) ); painter->restore(); } /*! \brief Find the bounding rectangle for the label. The coordinates of the rectangle are absolute ( calculated from pos() ). in direction of the tick. \param font Font used for painting \param value Value \return Bounding rectangle \sa labelRect() */ QRect QwtScaleDraw::boundingLabelRect( const QFont &font, double value ) const { QwtText lbl = tickLabel( font, value ); if ( lbl.isEmpty() ) return QRect(); const QPointF pos = labelPosition( value ); QSizeF labelSize = lbl.textSize( font ); const QTransform transform = labelTransformation( pos, labelSize ); return transform.mapRect( QRect( QPoint( 0, 0 ), labelSize.toSize() ) ); } /*! Calculate the transformation that is needed to paint a label depending on its alignment and rotation. \param pos Position where to paint the label \param size Size of the label \return Transformation matrix \sa setLabelAlignment(), setLabelRotation() */ QTransform QwtScaleDraw::labelTransformation( const QPointF &pos, const QSizeF &size ) const { QTransform transform; transform.translate( pos.x(), pos.y() ); transform.rotate( labelRotation() ); int flags = labelAlignment(); if ( flags == 0 ) { switch ( alignment() ) { case RightScale: { if ( flags == 0 ) flags = Qt::AlignRight | Qt::AlignVCenter; break; } case LeftScale: { if ( flags == 0 ) flags = Qt::AlignLeft | Qt::AlignVCenter; break; } case BottomScale: { if ( flags == 0 ) flags = Qt::AlignHCenter | Qt::AlignBottom; break; } case TopScale: { if ( flags == 0 ) flags = Qt::AlignHCenter | Qt::AlignTop; break; } } } double x, y; if ( flags & Qt::AlignLeft ) x = -size.width(); else if ( flags & Qt::AlignRight ) x = 0.0; else // Qt::AlignHCenter x = -( 0.5 * size.width() ); if ( flags & Qt::AlignTop ) y = -size.height(); else if ( flags & Qt::AlignBottom ) y = 0; else // Qt::AlignVCenter y = -( 0.5 * size.height() ); transform.translate( x, y ); return transform; } /*! Find the bounding rectangle for the label. The coordinates of the rectangle are relative to spacing + tick length from the backbone in direction of the tick. \param font Font used for painting \param value Value \return Bounding rectangle that is needed to draw a label */ QRectF QwtScaleDraw::labelRect( const QFont &font, double value ) const { QwtText lbl = tickLabel( font, value ); if ( lbl.isEmpty() ) return QRectF( 0.0, 0.0, 0.0, 0.0 ); const QPointF pos = labelPosition( value ); const QSizeF labelSize = lbl.textSize( font ); const QTransform transform = labelTransformation( pos, labelSize ); QRectF br = transform.mapRect( QRectF( QPointF( 0, 0 ), labelSize ) ); br.translate( -pos.x(), -pos.y() ); return br; } /*! Calculate the size that is needed to draw a label \param font Label font \param value Value \return Size that is needed to draw a label */ QSizeF QwtScaleDraw::labelSize( const QFont &font, double value ) const { return labelRect( font, value ).size(); } /*! Rotate all labels. When changing the rotation, it might be necessary to adjust the label flags too. Finding a useful combination is often the result of try and error. \param rotation Angle in degrees. When changing the label rotation, the label flags often needs to be adjusted too. \sa setLabelAlignment(), labelRotation(), labelAlignment(). */ void QwtScaleDraw::setLabelRotation( double rotation ) { d_data->labelRotation = rotation; } /*! \return the label rotation \sa setLabelRotation(), labelAlignment() */ double QwtScaleDraw::labelRotation() const { return d_data->labelRotation; } /*! \brief Change the label flags Labels are aligned to the point tick length + spacing away from the backbone. The alignment is relative to the orientation of the label text. In case of an flags of 0 the label will be aligned depending on the orientation of the scale: QwtScaleDraw::TopScale: Qt::AlignHCenter | Qt::AlignTop\n QwtScaleDraw::BottomScale: Qt::AlignHCenter | Qt::AlignBottom\n QwtScaleDraw::LeftScale: Qt::AlignLeft | Qt::AlignVCenter\n QwtScaleDraw::RightScale: Qt::AlignRight | Qt::AlignVCenter\n Changing the alignment is often necessary for rotated labels. \param alignment Or'd Qt::AlignmentFlags see \sa setLabelRotation(), labelRotation(), labelAlignment() \warning The various alignments might be confusing. The alignment of the label is not the alignment of the scale and is not the alignment of the flags ( QwtText::flags() ) returned from QwtAbstractScaleDraw::label(). */ void QwtScaleDraw::setLabelAlignment( Qt::Alignment alignment ) { d_data->labelAlignment = alignment; } /*! \return the label flags \sa setLabelAlignment(), labelRotation() */ Qt::Alignment QwtScaleDraw::labelAlignment() const { return d_data->labelAlignment; } /*! \param font Font \return the maximum width of a label */ int QwtScaleDraw::maxLabelWidth( const QFont &font ) const { double maxWidth = 0.0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( scaleDiv().contains( v ) ) { const double w = labelSize( font, ticks[i] ).width(); if ( w > maxWidth ) maxWidth = w; } } return qCeil( maxWidth ); } /*! \param font Font \return the maximum height of a label */ int QwtScaleDraw::maxLabelHeight( const QFont &font ) const { double maxHeight = 0.0; const QList &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( scaleDiv().contains( v ) ) { const double h = labelSize( font, ticks[i] ).height(); if ( h > maxHeight ) maxHeight = h; } } return qCeil( maxHeight ); } void QwtScaleDraw::updateMap() { const QPointF pos = d_data->pos; double len = d_data->len; QwtScaleMap &sm = scaleMap(); if ( orientation() == Qt::Vertical ) sm.setPaintInterval( pos.y() + len, pos.y() ); else sm.setPaintInterval( pos.x(), pos.x() + len ); } qsstv_8.2.12/qwt/qwt_scale_draw.h000664 001750 001750 00000006132 12440612574 016760 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SCALE_DRAW_H #define QWT_SCALE_DRAW_H #include "qwt_global.h" #include "qwt_abstract_scale_draw.h" #include #include #include /*! \brief A class for drawing scales QwtScaleDraw can be used to draw linear or logarithmic scales. A scale has a position, an alignment and a length, which can be specified . The labels can be rotated and aligned to the ticks using setLabelRotation() and setLabelAlignment(). After a scale division has been specified as a QwtScaleDiv object using QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s), the scale can be drawn with the QwtAbstractScaleDraw::draw() member. */ class QWT_EXPORT QwtScaleDraw: public QwtAbstractScaleDraw { public: /*! Alignment of the scale draw \sa setAlignment(), alignment() */ enum Alignment { //! The scale is below BottomScale, //! The scale is above TopScale, //! The scale is left LeftScale, //! The scale is right RightScale }; QwtScaleDraw(); virtual ~QwtScaleDraw(); void getBorderDistHint( const QFont &, int &start, int &end ) const; int minLabelDist( const QFont & ) const; int minLength( const QFont & ) const; virtual double extent( const QFont & ) const; void move( double x, double y ); void move( const QPointF & ); void setLength( double length ); Alignment alignment() const; void setAlignment( Alignment ); Qt::Orientation orientation() const; QPointF pos() const; double length() const; void setLabelAlignment( Qt::Alignment ); Qt::Alignment labelAlignment() const; void setLabelRotation( double rotation ); double labelRotation() const; int maxLabelHeight( const QFont & ) const; int maxLabelWidth( const QFont & ) const; QPointF labelPosition( double val ) const; QRectF labelRect( const QFont &, double val ) const; QSizeF labelSize( const QFont &, double val ) const; QRect boundingLabelRect( const QFont &, double val ) const; protected: QTransform labelTransformation( const QPointF &, const QSizeF & ) const; virtual void drawTick( QPainter *, double val, double len ) const; virtual void drawBackbone( QPainter * ) const; virtual void drawLabel( QPainter *, double val ) const; private: QwtScaleDraw( const QwtScaleDraw & ); QwtScaleDraw &operator=( const QwtScaleDraw &other ); void updateMap(); class PrivateData; PrivateData *d_data; }; /*! Move the position of the scale \param x X coordinate \param y Y coordinate \sa move(const QPointF &) */ inline void QwtScaleDraw::move( double x, double y ) { move( QPointF( x, y ) ); } #endif qsstv_8.2.12/qwt/qwt_scale_engine.cpp000664 001750 001750 00000067051 12440612574 017632 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_engine.h" #include "qwt_math.h" #include "qwt_scale_map.h" #include #include #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #define qExp(x) ::exp(x) #endif static inline double qwtLog( double base, double value ) { return log( value ) / log( base ); } static inline QwtInterval qwtLogInterval( double base, const QwtInterval &interval ) { return QwtInterval( qwtLog( base, interval.minValue() ), qwtLog( base, interval.maxValue() ) ); } static inline QwtInterval qwtPowInterval( double base, const QwtInterval &interval ) { return QwtInterval( qPow( base, interval.minValue() ), qPow( base, interval.maxValue() ) ); } #if 1 // this version often doesn't find the best ticks: f.e for 15: 5, 10 static double qwtStepSize( double intervalSize, int maxSteps, uint base ) { const double minStep = QwtScaleArithmetic::divideInterval( intervalSize, maxSteps, base ); if ( minStep != 0.0 ) { // # ticks per interval const int numTicks = qCeil( qAbs( intervalSize / minStep ) ) - 1; // Do the minor steps fit into the interval? if ( qwtFuzzyCompare( ( numTicks + 1 ) * qAbs( minStep ), qAbs( intervalSize ), intervalSize ) > 0 ) { // The minor steps doesn't fit into the interval return 0.5 * intervalSize; } } return minStep; } #else static double qwtStepSize( double intervalSize, int maxSteps, uint base ) { if ( maxSteps <= 0 ) return 0.0; if ( maxSteps > 2 ) { for ( int numSteps = maxSteps; numSteps > 1; numSteps-- ) { const double stepSize = intervalSize / numSteps; const double p = ::floor( ::log( stepSize ) / ::log( base ) ); const double fraction = qPow( base, p ); for ( uint n = base; n > 1; n /= 2 ) { if ( qFuzzyCompare( stepSize, n * fraction ) ) return stepSize; if ( n == 3 && ( base % 2 ) == 0 ) { if ( qFuzzyCompare( stepSize, 2 * fraction ) ) return stepSize; } } } } return intervalSize * 0.5; } #endif static const double _eps = 1.0e-6; /*! Ceil a value, relative to an interval \param value Value to be ceiled \param intervalSize Interval size \return Rounded value \sa floorEps() */ double QwtScaleArithmetic::ceilEps( double value, double intervalSize ) { const double eps = _eps * intervalSize; value = ( value - eps ) / intervalSize; return ::ceil( value ) * intervalSize; } /*! Floor a value, relative to an interval \param value Value to be floored \param intervalSize Interval size \return Rounded value \sa floorEps() */ double QwtScaleArithmetic::floorEps( double value, double intervalSize ) { const double eps = _eps * intervalSize; value = ( value + eps ) / intervalSize; return ::floor( value ) * intervalSize; } /*! \brief Divide an interval into steps \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$ \param intervalSize Interval size \param numSteps Number of steps \return Step size */ double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps ) { if ( numSteps == 0.0 || intervalSize == 0.0 ) return 0.0; return ( intervalSize - ( _eps * intervalSize ) ) / numSteps; } /*! Calculate a step size for a given interval \param intervalSize Interval size \param numSteps Number of steps \param base Base for the division ( usually 10 ) \return Calculated step size */ double QwtScaleArithmetic::divideInterval( double intervalSize, int numSteps, uint base ) { if ( numSteps <= 0 ) return 0.0; const double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps ); if ( v == 0.0 ) return 0.0; const double lx = qwtLog( base, qFabs( v ) ); const double p = ::floor( lx ); const double fraction = qPow( base, lx - p ); uint n = base; while ( ( n > 1 ) && ( fraction <= n / 2 ) ) n /= 2; double stepSize = n * qPow( base, p ); if ( v < 0 ) stepSize = -stepSize; return stepSize; } class QwtScaleEngine::PrivateData { public: PrivateData(): attributes( QwtScaleEngine::NoAttribute ), lowerMargin( 0.0 ), upperMargin( 0.0 ), referenceValue( 0.0 ), base( 10 ), transform( NULL ) { } ~PrivateData() { delete transform; } QwtScaleEngine::Attributes attributes; double lowerMargin; double upperMargin; double referenceValue; uint base; QwtTransform* transform; }; /*! Constructor \param base Base of the scale engine \sa setBase() */ QwtScaleEngine::QwtScaleEngine( uint base ) { d_data = new PrivateData; setBase( base ); } //! Destructor QwtScaleEngine::~QwtScaleEngine () { delete d_data; } /*! Assign a transformation \param transform Transformation The transformation object is used as factory for clones that are returned by transformation() The scale engine takes ownership of the transformation. \sa QwtTransform::copy(), transformation() */ void QwtScaleEngine::setTransformation( QwtTransform *transform ) { if ( transform != d_data->transform ) { delete d_data->transform; d_data->transform = transform; } } /*! Create and return a clone of the transformation of the engine. When the engine has no special transformation NULL is returned, indicating no transformation. \return A clone of the transfomation \sa setTransformation() */ QwtTransform *QwtScaleEngine::transformation() const { QwtTransform *transform = NULL; if ( d_data->transform ) transform = d_data->transform->copy(); return transform; } /*! \return the margin at the lower end of the scale The default margin is 0. \sa setMargins() */ double QwtScaleEngine::lowerMargin() const { return d_data->lowerMargin; } /*! \return the margin at the upper end of the scale The default margin is 0. \sa setMargins() */ double QwtScaleEngine::upperMargin() const { return d_data->upperMargin; } /*! \brief Specify margins at the scale's endpoints \param lower minimum distance between the scale's lower boundary and the smallest enclosed value \param upper minimum distance between the scale's upper boundary and the greatest enclosed value Margins can be used to leave a minimum amount of space between the enclosed intervals and the boundaries of the scale. \warning \li QwtLogScaleEngine measures the margins in decades. \sa upperMargin(), lowerMargin() */ void QwtScaleEngine::setMargins( double lower, double upper ) { d_data->lowerMargin = qMax( lower, 0.0 ); d_data->upperMargin = qMax( upper, 0.0 ); } /*! Calculate a step size for an interval size \param intervalSize Interval size \param numSteps Number of steps \return Step size */ double QwtScaleEngine::divideInterval( double intervalSize, int numSteps ) const { return QwtScaleArithmetic::divideInterval( intervalSize, numSteps, d_data->base ); } /*! Check if an interval "contains" a value \param interval Interval \param value Value \return True, when the value is inside the interval */ bool QwtScaleEngine::contains( const QwtInterval &interval, double value ) const { if ( !interval.isValid() ) return false; if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 ) return false; if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 ) return false; return true; } /*! Remove ticks from a list, that are not inside an interval \param ticks Tick list \param interval Interval \return Stripped tick list */ QList QwtScaleEngine::strip( const QList& ticks, const QwtInterval &interval ) const { if ( !interval.isValid() || ticks.count() == 0 ) return QList(); if ( contains( interval, ticks.first() ) && contains( interval, ticks.last() ) ) { return ticks; } QList strippedTicks; for ( int i = 0; i < ticks.count(); i++ ) { if ( contains( interval, ticks[i] ) ) strippedTicks += ticks[i]; } return strippedTicks; } /*! \brief Build an interval around a value In case of v == 0.0 the interval is [-0.5, 0.5], otherwide it is [0.5 * v, 1.5 * v] \param value Initial value \return Calculated interval */ QwtInterval QwtScaleEngine::buildInterval( double value ) const { const double delta = ( value == 0.0 ) ? 0.5 : qAbs( 0.5 * value ); if ( DBL_MAX - delta < value ) return QwtInterval( DBL_MAX - delta, DBL_MAX ); if ( -DBL_MAX + delta > value ) return QwtInterval( -DBL_MAX, -DBL_MAX + delta ); return QwtInterval( value - delta, value + delta ); } /*! Change a scale attribute \param attribute Attribute to change \param on On/Off \sa Attribute, testAttribute() */ void QwtScaleEngine::setAttribute( Attribute attribute, bool on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; } /*! \return True, if attribute is enabled. \param attribute Attribute to be tested \sa Attribute, setAttribute() */ bool QwtScaleEngine::testAttribute( Attribute attribute ) const { return ( d_data->attributes & attribute ); } /*! Change the scale attribute \param attributes Set scale attributes \sa Attribute, attributes() */ void QwtScaleEngine::setAttributes( Attributes attributes ) { d_data->attributes = attributes; } /*! \return Scale attributes \sa Attribute, setAttributes(), testAttribute() */ QwtScaleEngine::Attributes QwtScaleEngine::attributes() const { return d_data->attributes; } /*! \brief Specify a reference point \param r new reference value The reference point is needed if options IncludeReference or Symmetric are active. Its default value is 0.0. \sa Attribute */ void QwtScaleEngine::setReference( double r ) { d_data->referenceValue = r; } /*! \return the reference value \sa setReference(), setAttribute() */ double QwtScaleEngine::reference() const { return d_data->referenceValue; } /*! Set the base of the scale engine While a base of 10 is what 99.9% of all applications need certain scales might need a different base: f.e 2 The default setting is 10 \param base Base of the engine \sa base() */ void QwtScaleEngine::setBase( uint base ) { d_data->base = qMax( base, 2U ); } /*! \return base Base of the scale engine \sa setBase() */ uint QwtScaleEngine::base() const { return d_data->base; } /*! Constructor \param base Base of the scale engine \sa setBase() */ QwtLinearScaleEngine::QwtLinearScaleEngine( uint base ): QwtScaleEngine( base ) { } //! Destructor QwtLinearScaleEngine::~QwtLinearScaleEngine() { } /*! Align and divide an interval \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Out) \sa setAttribute() */ void QwtLinearScaleEngine::autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const { QwtInterval interval( x1, x2 ); interval = interval.normalized(); interval.setMinValue( interval.minValue() - lowerMargin() ); interval.setMaxValue( interval.maxValue() + upperMargin() ); if ( testAttribute( QwtScaleEngine::Symmetric ) ) interval = interval.symmetrize( reference() ); if ( testAttribute( QwtScaleEngine::IncludeReference ) ) interval = interval.extend( reference() ); if ( interval.width() == 0.0 ) interval = buildInterval( interval.minValue() ); stepSize = QwtScaleArithmetic::divideInterval( interval.width(), qMax( maxNumSteps, 1 ), base() ); if ( !testAttribute( QwtScaleEngine::Floating ) ) interval = align( interval, stepSize ); x1 = interval.minValue(); x2 = interval.maxValue(); if ( testAttribute( QwtScaleEngine::Inverted ) ) { qSwap( x1, x2 ); stepSize = -stepSize; } } /*! \brief Calculate a scale division for an interval \param x1 First interval limit \param x2 Second interval limit \param maxMajorSteps Maximum for the number of major steps \param maxMinorSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0, the engine calculates one. \return Calculated scale division */ QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize ) const { QwtInterval interval = QwtInterval( x1, x2 ).normalized(); if ( interval.width() <= 0 ) return QwtScaleDiv(); stepSize = qAbs( stepSize ); if ( stepSize == 0.0 ) { if ( maxMajorSteps < 1 ) maxMajorSteps = 1; stepSize = QwtScaleArithmetic::divideInterval( interval.width(), maxMajorSteps, base() ); } QwtScaleDiv scaleDiv; if ( stepSize != 0.0 ) { QList ticks[QwtScaleDiv::NTickTypes]; buildTicks( interval, stepSize, maxMinorSteps, ticks ); scaleDiv = QwtScaleDiv( interval, ticks ); } if ( x1 > x2 ) scaleDiv.invert(); return scaleDiv; } /*! \brief Calculate ticks for an interval \param interval Interval \param stepSize Step size \param maxMinorSteps Maximum number of minor steps \param ticks Arrays to be filled with the calculated ticks \sa buildMajorTicks(), buildMinorTicks */ void QwtLinearScaleEngine::buildTicks( const QwtInterval& interval, double stepSize, int maxMinorSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const { const QwtInterval boundingInterval = align( interval, stepSize ); ticks[QwtScaleDiv::MajorTick] = buildMajorTicks( boundingInterval, stepSize ); if ( maxMinorSteps > 0 ) { buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize, ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] ); } for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) { ticks[i] = strip( ticks[i], interval ); // ticks very close to 0.0 are // explicitely set to 0.0 for ( int j = 0; j < ticks[i].count(); j++ ) { if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 ) ticks[i][j] = 0.0; } } } /*! \brief Calculate major ticks for an interval \param interval Interval \param stepSize Step size \return Calculated ticks */ QList QwtLinearScaleEngine::buildMajorTicks( const QwtInterval &interval, double stepSize ) const { int numTicks = qRound( interval.width() / stepSize ) + 1; if ( numTicks > 10000 ) numTicks = 10000; QList ticks; ticks += interval.minValue(); for ( int i = 1; i < numTicks - 1; i++ ) ticks += interval.minValue() + i * stepSize; ticks += interval.maxValue(); return ticks; } /*! \brief Calculate minor/medium ticks for major ticks \param majorTicks Major ticks \param maxMinorSteps Maximum number of minor steps \param stepSize Step size \param minorTicks Array to be filled with the calculated minor ticks \param mediumTicks Array to be filled with the calculated medium ticks */ void QwtLinearScaleEngine::buildMinorTicks( const QList& majorTicks, int maxMinorSteps, double stepSize, QList &minorTicks, QList &mediumTicks ) const { double minStep = qwtStepSize( stepSize, maxMinorSteps, base() ); if ( minStep == 0.0 ) return; // # ticks per interval const int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1; int medIndex = -1; if ( numTicks % 2 ) medIndex = numTicks / 2; // calculate minor ticks for ( int i = 0; i < majorTicks.count(); i++ ) { double val = majorTicks[i]; for ( int k = 0; k < numTicks; k++ ) { val += minStep; double alignedValue = val; if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 ) alignedValue = 0.0; if ( k == medIndex ) mediumTicks += alignedValue; else minorTicks += alignedValue; } } } /*! \brief Align an interval to a step size The limits of an interval are aligned that both are integer multiples of the step size. \param interval Interval \param stepSize Step size \return Aligned interval */ QwtInterval QwtLinearScaleEngine::align( const QwtInterval &interval, double stepSize ) const { double x1 = interval.minValue(); double x2 = interval.maxValue(); if ( -DBL_MAX + stepSize <= x1 ) { const double x = QwtScaleArithmetic::floorEps( x1, stepSize ); if ( qwtFuzzyCompare( x1, x, stepSize ) != 0 ) x1 = x; } if ( DBL_MAX - stepSize >= x2 ) { const double x = QwtScaleArithmetic::ceilEps( x2, stepSize ); if ( qwtFuzzyCompare( x2, x, stepSize ) != 0 ) x2 = x; } return QwtInterval( x1, x2 ); } /*! Constructor \param base Base of the scale engine \sa setBase() */ QwtLogScaleEngine::QwtLogScaleEngine( uint base ): QwtScaleEngine( base ) { setTransformation( new QwtLogTransform() ); } //! Destructor QwtLogScaleEngine::~QwtLogScaleEngine() { } /*! Align and divide an interval \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Out) \sa QwtScaleEngine::setAttribute() */ void QwtLogScaleEngine::autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const { if ( x1 > x2 ) qSwap( x1, x2 ); const double logBase = base(); QwtInterval interval( x1 / qPow( logBase, lowerMargin() ), x2 * qPow( logBase, upperMargin() ) ); if ( interval.maxValue() / interval.minValue() < logBase ) { // scale width is less than one step -> try to build a linear scale QwtLinearScaleEngine linearScaler; linearScaler.setAttributes( attributes() ); linearScaler.setReference( reference() ); linearScaler.setMargins( lowerMargin(), upperMargin() ); linearScaler.autoScale( maxNumSteps, x1, x2, stepSize ); QwtInterval linearInterval = QwtInterval( x1, x2 ).normalized(); linearInterval = linearInterval.limited( LOG_MIN, LOG_MAX ); if ( linearInterval.maxValue() / linearInterval.minValue() < logBase ) { // the aligned scale is still less than one step if ( stepSize < 0.0 ) stepSize = -qwtLog( logBase, qAbs( stepSize ) ); else stepSize = qwtLog( logBase, stepSize ); return; } } double logRef = 1.0; if ( reference() > LOG_MIN / 2 ) logRef = qMin( reference(), LOG_MAX / 2 ); if ( testAttribute( QwtScaleEngine::Symmetric ) ) { const double delta = qMax( interval.maxValue() / logRef, logRef / interval.minValue() ); interval.setInterval( logRef / delta, logRef * delta ); } if ( testAttribute( QwtScaleEngine::IncludeReference ) ) interval = interval.extend( logRef ); interval = interval.limited( LOG_MIN, LOG_MAX ); if ( interval.width() == 0.0 ) interval = buildInterval( interval.minValue() ); stepSize = divideInterval( qwtLogInterval( logBase, interval ).width(), qMax( maxNumSteps, 1 ) ); if ( stepSize < 1.0 ) stepSize = 1.0; if ( !testAttribute( QwtScaleEngine::Floating ) ) interval = align( interval, stepSize ); x1 = interval.minValue(); x2 = interval.maxValue(); if ( testAttribute( QwtScaleEngine::Inverted ) ) { qSwap( x1, x2 ); stepSize = -stepSize; } } /*! \brief Calculate a scale division for an interval \param x1 First interval limit \param x2 Second interval limit \param maxMajorSteps Maximum for the number of major steps \param maxMinorSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0, the engine calculates one. \return Calculated scale division */ QwtScaleDiv QwtLogScaleEngine::divideScale( double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize ) const { QwtInterval interval = QwtInterval( x1, x2 ).normalized(); interval = interval.limited( LOG_MIN, LOG_MAX ); if ( interval.width() <= 0 ) return QwtScaleDiv(); const double logBase = base(); if ( interval.maxValue() / interval.minValue() < logBase ) { // scale width is less than one decade -> build linear scale QwtLinearScaleEngine linearScaler; linearScaler.setAttributes( attributes() ); linearScaler.setReference( reference() ); linearScaler.setMargins( lowerMargin(), upperMargin() ); if ( stepSize != 0.0 ) { if ( stepSize < 0.0 ) stepSize = -qPow( logBase, -stepSize ); else stepSize = qPow( logBase, stepSize ); } return linearScaler.divideScale( x1, x2, maxMajorSteps, maxMinorSteps, stepSize ); } stepSize = qAbs( stepSize ); if ( stepSize == 0.0 ) { if ( maxMajorSteps < 1 ) maxMajorSteps = 1; stepSize = divideInterval( qwtLogInterval( logBase, interval ).width(), maxMajorSteps ); if ( stepSize < 1.0 ) stepSize = 1.0; // major step must be >= 1 decade } QwtScaleDiv scaleDiv; if ( stepSize != 0.0 ) { QList ticks[QwtScaleDiv::NTickTypes]; buildTicks( interval, stepSize, maxMinorSteps, ticks ); scaleDiv = QwtScaleDiv( interval, ticks ); } if ( x1 > x2 ) scaleDiv.invert(); return scaleDiv; } /*! \brief Calculate ticks for an interval \param interval Interval \param maxMinorSteps Maximum number of minor steps \param stepSize Step size \param ticks Arrays to be filled with the calculated ticks \sa buildMajorTicks(), buildMinorTicks */ void QwtLogScaleEngine::buildTicks( const QwtInterval& interval, double stepSize, int maxMinorSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const { const QwtInterval boundingInterval = align( interval, stepSize ); ticks[QwtScaleDiv::MajorTick] = buildMajorTicks( boundingInterval, stepSize ); if ( maxMinorSteps > 0 ) { buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize, ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] ); } for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) ticks[i] = strip( ticks[i], interval ); } /*! \brief Calculate major ticks for an interval \param interval Interval \param stepSize Step size \return Calculated ticks */ QList QwtLogScaleEngine::buildMajorTicks( const QwtInterval &interval, double stepSize ) const { double width = qwtLogInterval( base(), interval ).width(); int numTicks = qRound( width / stepSize ) + 1; if ( numTicks > 10000 ) numTicks = 10000; const double lxmin = ::log( interval.minValue() ); const double lxmax = ::log( interval.maxValue() ); const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 ); QList ticks; ticks += interval.minValue(); for ( int i = 1; i < numTicks - 1; i++ ) ticks += qExp( lxmin + double( i ) * lstep ); ticks += interval.maxValue(); return ticks; } /*! \brief Calculate minor/medium ticks for major ticks \param majorTicks Major ticks \param maxMinorSteps Maximum number of minor steps \param stepSize Step size \param minorTicks Array to be filled with the calculated minor ticks \param mediumTicks Array to be filled with the calculated medium ticks */ void QwtLogScaleEngine::buildMinorTicks( const QList &majorTicks, int maxMinorSteps, double stepSize, QList &minorTicks, QList &mediumTicks ) const { const double logBase = base(); if ( stepSize < 1.1 ) // major step width is one base { double minStep = divideInterval( stepSize, maxMinorSteps + 1 ); if ( minStep == 0.0 ) return; const int numSteps = qRound( stepSize / minStep ); int mediumTickIndex = -1; if ( ( numSteps > 2 ) && ( numSteps % 2 == 0 ) ) mediumTickIndex = numSteps / 2; for ( int i = 0; i < majorTicks.count() - 1; i++ ) { const double v = majorTicks[i]; const double s = logBase / numSteps; if ( s >= 1.0 ) { for ( int j = 2; j < numSteps; j++ ) { minorTicks += v * j * s; } } else { for ( int j = 1; j < numSteps; j++ ) { const double tick = v + j * v * ( logBase - 1 ) / numSteps; if ( j == mediumTickIndex ) mediumTicks += tick; else minorTicks += tick; } } } } else { double minStep = divideInterval( stepSize, maxMinorSteps ); if ( minStep == 0.0 ) return; if ( minStep < 1.0 ) minStep = 1.0; // # subticks per interval int numTicks = qRound( stepSize / minStep ) - 1; // Do the minor steps fit into the interval? if ( qwtFuzzyCompare( ( numTicks + 1 ) * minStep, stepSize, stepSize ) > 0 ) { numTicks = 0; } if ( numTicks < 1 ) return; int mediumTickIndex = -1; if ( ( numTicks > 2 ) && ( numTicks % 2 ) ) mediumTickIndex = numTicks / 2; // substep factor = base^substeps const qreal minFactor = qMax( qPow( logBase, minStep ), qreal( logBase ) ); for ( int i = 0; i < majorTicks.count(); i++ ) { double tick = majorTicks[i]; for ( int j = 0; j < numTicks; j++ ) { tick *= minFactor; if ( j == mediumTickIndex ) mediumTicks += tick; else minorTicks += tick; } } } } /*! \brief Align an interval to a step size The limits of an interval are aligned that both are integer multiples of the step size. \param interval Interval \param stepSize Step size \return Aligned interval */ QwtInterval QwtLogScaleEngine::align( const QwtInterval &interval, double stepSize ) const { const QwtInterval intv = qwtLogInterval( base(), interval ); double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize ); if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 ) x1 = interval.minValue(); double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize ); if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 ) x2 = interval.maxValue(); return qwtPowInterval( base(), QwtInterval( x1, x2 ) ); } qsstv_8.2.12/qwt/qwt_scale_engine.h000664 001750 001750 00000014241 12440612574 017270 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SCALE_ENGINE_H #define QWT_SCALE_ENGINE_H #include "qwt_global.h" #include "qwt_scale_div.h" #include "qwt_interval.h" class QwtTransform; /*! \brief Arithmetic including a tolerance */ class QWT_EXPORT QwtScaleArithmetic { public: static double ceilEps( double value, double intervalSize ); static double floorEps( double value, double intervalSize ); static double divideEps( double interval, double steps ); static double divideInterval( double interval, int numSteps, uint base ); }; /*! \brief Base class for scale engines. A scale engine tries to find "reasonable" ranges and step sizes for scales. The layout of the scale can be varied with setAttribute(). Qwt offers implementations for logarithmic and linear scales. */ class QWT_EXPORT QwtScaleEngine { public: /*! Layout attributes \sa setAttribute(), testAttribute(), reference(), lowerMargin(), upperMargin() */ enum Attribute { //! No attributes NoAttribute = 0x00, //! Build a scale which includes the reference() value. IncludeReference = 0x01, //! Build a scale which is symmetric to the reference() value. Symmetric = 0x02, /*! The endpoints of the scale are supposed to be equal the outmost included values plus the specified margins (see setMargins()). If this attribute is *not* set, the endpoints of the scale will be integer multiples of the step size. */ Floating = 0x04, //! Turn the scale upside down. Inverted = 0x08 }; //! Layout attributes typedef QFlags Attributes; explicit QwtScaleEngine( uint base = 10 ); virtual ~QwtScaleEngine(); void setBase( uint base ); uint base() const; void setAttribute( Attribute, bool on = true ); bool testAttribute( Attribute ) const; void setAttributes( Attributes ); Attributes attributes() const; void setReference( double reference ); double reference() const; void setMargins( double lower, double upper ); double lowerMargin() const; double upperMargin() const; /*! Align and divide an interval \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Return value) */ virtual void autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const = 0; /*! \brief Calculate a scale division \param x1 First interval limit \param x2 Second interval limit \param maxMajorSteps Maximum for the number of major steps \param maxMinorSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0.0, the scaleEngine calculates one. \return Calculated scale division */ virtual QwtScaleDiv divideScale( double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize = 0.0 ) const = 0; void setTransformation( QwtTransform * ); QwtTransform *transformation() const; protected: bool contains( const QwtInterval &, double val ) const; QList strip( const QList&, const QwtInterval & ) const; double divideInterval( double interval, int numSteps ) const; QwtInterval buildInterval( double v ) const; private: class PrivateData; PrivateData *d_data; }; /*! \brief A scale engine for linear scales The step size will fit into the pattern \f$\left\{ 1,2,5\right\} \cdot 10^{n}\f$, where n is an integer. */ class QWT_EXPORT QwtLinearScaleEngine: public QwtScaleEngine { public: QwtLinearScaleEngine( uint base = 10 ); virtual ~QwtLinearScaleEngine(); virtual void autoScale( int maxSteps, double &x1, double &x2, double &stepSize ) const; virtual QwtScaleDiv divideScale( double x1, double x2, int numMajorSteps, int numMinorSteps, double stepSize = 0.0 ) const; protected: QwtInterval align( const QwtInterval&, double stepSize ) const; void buildTicks( const QwtInterval &, double stepSize, int maxMinSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const; QList buildMajorTicks( const QwtInterval &interval, double stepSize ) const; void buildMinorTicks( const QList& majorTicks, int maxMinorSteps, double stepSize, QList &minorTicks, QList &mediumTicks ) const; }; /*! \brief A scale engine for logarithmic scales The step size is measured in *decades* and the major step size will be adjusted to fit the pattern \f$\left\{ 1,2,3,5\right\} \cdot 10^{n}\f$, where n is a natural number including zero. \warning the step size as well as the margins are measured in *decades*. */ class QWT_EXPORT QwtLogScaleEngine: public QwtScaleEngine { public: QwtLogScaleEngine( uint base = 10 ); virtual ~QwtLogScaleEngine(); virtual void autoScale( int maxSteps, double &x1, double &x2, double &stepSize ) const; virtual QwtScaleDiv divideScale( double x1, double x2, int numMajorSteps, int numMinorSteps, double stepSize = 0.0 ) const; protected: QwtInterval align( const QwtInterval&, double stepSize ) const; void buildTicks( const QwtInterval &, double stepSize, int maxMinSteps, QList ticks[QwtScaleDiv::NTickTypes] ) const; QList buildMajorTicks( const QwtInterval &interval, double stepSize ) const; void buildMinorTicks( const QList& majorTicks, int maxMinorSteps, double stepSize, QList &minorTicks, QList &mediumTicks ) const; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtScaleEngine::Attributes ) #endif qsstv_8.2.12/qwt/qwt_scale_map.cpp000664 001750 001750 00000012751 12440612574 017137 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_map.h" #include "qwt_math.h" #include #include /*! \brief Constructor The scale and paint device intervals are both set to [0,1]. */ QwtScaleMap::QwtScaleMap(): d_s1( 0.0 ), d_s2( 1.0 ), d_p1( 0.0 ), d_p2( 1.0 ), d_cnv( 1.0 ), d_ts1( 0.0 ), d_transform( NULL ) { } //! Copy constructor QwtScaleMap::QwtScaleMap( const QwtScaleMap& other ): d_s1( other.d_s1 ), d_s2( other.d_s2 ), d_p1( other.d_p1 ), d_p2( other.d_p2 ), d_cnv( other.d_cnv ), d_ts1( other.d_ts1 ), d_transform( NULL ) { if ( other.d_transform ) d_transform = other.d_transform->copy(); } /*! Destructor */ QwtScaleMap::~QwtScaleMap() { delete d_transform; } //! Assignment operator QwtScaleMap &QwtScaleMap::operator=( const QwtScaleMap & other ) { d_s1 = other.d_s1; d_s2 = other.d_s2; d_p1 = other.d_p1; d_p2 = other.d_p2; d_cnv = other.d_cnv; d_ts1 = other.d_ts1; delete d_transform; d_transform = NULL; if ( other.d_transform ) d_transform = other.d_transform->copy(); return *this; } /*! Initialize the map with a transformation */ void QwtScaleMap::setTransformation( QwtTransform *transform ) { if ( transform != d_transform ) { delete d_transform; d_transform = transform; } setScaleInterval( d_s1, d_s2 ); } //! Get the transformation const QwtTransform *QwtScaleMap::transformation() const { return d_transform; } /*! \brief Specify the borders of the scale interval \param s1 first border \param s2 second border \warning scales might be aligned to transformation depending boundaries */ void QwtScaleMap::setScaleInterval( double s1, double s2 ) { d_s1 = s1; d_s2 = s2; if ( d_transform ) { d_s1 = d_transform->bounded( d_s1 ); d_s2 = d_transform->bounded( d_s2 ); } updateFactor(); } /*! \brief Specify the borders of the paint device interval \param p1 first border \param p2 second border */ void QwtScaleMap::setPaintInterval( double p1, double p2 ) { d_p1 = p1; d_p2 = p2; updateFactor(); } void QwtScaleMap::updateFactor() { d_ts1 = d_s1; double ts2 = d_s2; if ( d_transform ) { d_ts1 = d_transform->transform( d_ts1 ); ts2 = d_transform->transform( ts2 ); } d_cnv = 1.0; if ( d_ts1 != ts2 ) d_cnv = ( d_p2 - d_p1 ) / ( ts2 - d_ts1 ); } /*! Transform a rectangle from scale to paint coordinates \param xMap X map \param yMap Y map \param rect Rectangle in scale coordinates \return Rectangle in paint coordinates \sa invTransform() */ QRectF QwtScaleMap::transform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) { double x1 = xMap.transform( rect.left() ); double x2 = xMap.transform( rect.right() ); double y1 = yMap.transform( rect.top() ); double y2 = yMap.transform( rect.bottom() ); if ( x2 < x1 ) qSwap( x1, x2 ); if ( y2 < y1 ) qSwap( y1, y2 ); if ( qwtFuzzyCompare( x1, 0.0, x2 - x1 ) == 0 ) x1 = 0.0; if ( qwtFuzzyCompare( x2, 0.0, x2 - x1 ) == 0 ) x2 = 0.0; if ( qwtFuzzyCompare( y1, 0.0, y2 - y1 ) == 0 ) y1 = 0.0; if ( qwtFuzzyCompare( y2, 0.0, y2 - y1 ) == 0 ) y2 = 0.0; return QRectF( x1, y1, x2 - x1 + 1, y2 - y1 + 1 ); } /*! Transform a rectangle from paint to scale coordinates \param xMap X map \param yMap Y map \param pos Position in paint coordinates \return Position in scale coordinates \sa transform() */ QPointF QwtScaleMap::invTransform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QPointF &pos ) { return QPointF( xMap.invTransform( pos.x() ), yMap.invTransform( pos.y() ) ); } /*! Transform a point from scale to paint coordinates \param xMap X map \param yMap Y map \param pos Position in scale coordinates \return Position in paint coordinates \sa invTransform() */ QPointF QwtScaleMap::transform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QPointF &pos ) { return QPointF( xMap.transform( pos.x() ), yMap.transform( pos.y() ) ); } /*! Transform a rectangle from paint to scale coordinates \param xMap X map \param yMap Y map \param rect Rectangle in paint coordinates \return Rectangle in scale coordinates \sa transform() */ QRectF QwtScaleMap::invTransform( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) { const double x1 = xMap.invTransform( rect.left() ); const double x2 = xMap.invTransform( rect.right() - 1 ); const double y1 = yMap.invTransform( rect.top() ); const double y2 = yMap.invTransform( rect.bottom() - 1 ); const QRectF r( x1, y1, x2 - x1, y2 - y1 ); return r.normalized(); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtScaleMap &map ) { debug.nospace() << "QwtScaleMap(" << map.transformation() << ", s:" << map.s1() << "->" << map.s2() << ", p:" << map.p1() << "->" << map.p2() << ")"; return debug.space(); } #endif qsstv_8.2.12/qwt/qwt_scale_map.h000664 001750 001750 00000007301 12440612574 016577 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SCALE_MAP_H #define QWT_SCALE_MAP_H #include "qwt_global.h" #include "qwt_transform.h" #include #ifndef QT_NO_DEBUG_STREAM #include #endif class QRectF; /*! \brief A scale map QwtScaleMap offers transformations from the coordinate system of a scale into the linear coordinate system of a paint device and vice versa. */ class QWT_EXPORT QwtScaleMap { public: QwtScaleMap(); QwtScaleMap( const QwtScaleMap& ); ~QwtScaleMap(); QwtScaleMap &operator=( const QwtScaleMap & ); void setTransformation( QwtTransform * ); const QwtTransform *transformation() const; void setPaintInterval( double p1, double p2 ); void setScaleInterval( double s1, double s2 ); double transform( double s ) const; double invTransform( double p ) const; double p1() const; double p2() const; double s1() const; double s2() const; double pDist() const; double sDist() const; static QRectF transform( const QwtScaleMap &, const QwtScaleMap &, const QRectF & ); static QRectF invTransform( const QwtScaleMap &, const QwtScaleMap &, const QRectF & ); static QPointF transform( const QwtScaleMap &, const QwtScaleMap &, const QPointF & ); static QPointF invTransform( const QwtScaleMap &, const QwtScaleMap &, const QPointF & ); bool isInverting() const; private: void updateFactor(); double d_s1, d_s2; // scale interval boundaries double d_p1, d_p2; // paint device interval boundaries double d_cnv; // conversion factor double d_ts1; QwtTransform *d_transform; }; /*! \return First border of the scale interval */ inline double QwtScaleMap::s1() const { return d_s1; } /*! \return Second border of the scale interval */ inline double QwtScaleMap::s2() const { return d_s2; } /*! \return First border of the paint interval */ inline double QwtScaleMap::p1() const { return d_p1; } /*! \return Second border of the paint interval */ inline double QwtScaleMap::p2() const { return d_p2; } /*! \return qwtAbs(p2() - p1()) */ inline double QwtScaleMap::pDist() const { return qAbs( d_p2 - d_p1 ); } /*! \return qwtAbs(s2() - s1()) */ inline double QwtScaleMap::sDist() const { return qAbs( d_s2 - d_s1 ); } /*! Transform a point related to the scale interval into an point related to the interval of the paint device \param s Value relative to the coordinates of the scale \return Transformed value \sa invTransform() */ inline double QwtScaleMap::transform( double s ) const { if ( d_transform ) s = d_transform->transform( s ); return d_p1 + ( s - d_ts1 ) * d_cnv; } /*! Transform an paint device value into a value in the interval of the scale. \param p Value relative to the coordinates of the paint device \return Transformed value \sa transform() */ inline double QwtScaleMap::invTransform( double p ) const { double s = d_ts1 + ( p - d_p1 ) / d_cnv; if ( d_transform ) s = d_transform->invTransform( s ); return s; } //! \return True, when ( p1() < p2() ) != ( s1() < s2() ) inline bool QwtScaleMap::isInverting() const { return ( ( d_p1 < d_p2 ) != ( d_s1 < d_s2 ) ); } #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtScaleMap & ); #endif #endif qsstv_8.2.12/qwt/qwt_scale_widget.cpp000664 001750 001750 00000054200 12440612574 017640 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_scale_widget.h" #include "qwt_painter.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include "qwt_math.h" #include "qwt_scale_div.h" #include "qwt_text.h" #include "qwt_scale_engine.h" #include #include #include #include #include class QwtScaleWidget::PrivateData { public: PrivateData(): scaleDraw( NULL ) { colorBar.colorMap = NULL; } ~PrivateData() { delete scaleDraw; delete colorBar.colorMap; } QwtScaleDraw *scaleDraw; int borderDist[2]; int minBorderDist[2]; int scaleLength; int margin; int titleOffset; int spacing; QwtText title; QwtScaleWidget::LayoutFlags layoutFlags; struct t_colorBar { bool isEnabled; int width; QwtInterval interval; QwtColorMap *colorMap; } colorBar; }; /*! \brief Create a scale with the position QwtScaleWidget::Left \param parent Parent widget */ QwtScaleWidget::QwtScaleWidget( QWidget *parent ): QWidget( parent ) { initScale( QwtScaleDraw::LeftScale ); } /*! \brief Constructor \param align Alignment. \param parent Parent widget */ QwtScaleWidget::QwtScaleWidget( QwtScaleDraw::Alignment align, QWidget *parent ): QWidget( parent ) { initScale( align ); } //! Destructor QwtScaleWidget::~QwtScaleWidget() { delete d_data; } //! Initialize the scale void QwtScaleWidget::initScale( QwtScaleDraw::Alignment align ) { d_data = new PrivateData; d_data->layoutFlags = 0; if ( align == QwtScaleDraw::RightScale ) d_data->layoutFlags |= TitleInverted; d_data->borderDist[0] = 0; d_data->borderDist[1] = 0; d_data->minBorderDist[0] = 0; d_data->minBorderDist[1] = 0; d_data->margin = 4; d_data->titleOffset = 0; d_data->spacing = 2; d_data->scaleDraw = new QwtScaleDraw; d_data->scaleDraw->setAlignment( align ); d_data->scaleDraw->setLength( 10 ); d_data->scaleDraw->setScaleDiv( QwtLinearScaleEngine().divideScale( 0.0, 100.0, 10, 5 ) ); d_data->colorBar.colorMap = new QwtLinearColorMap(); d_data->colorBar.isEnabled = false; d_data->colorBar.width = 10; const int flags = Qt::AlignHCenter | Qt::TextExpandTabs | Qt::TextWordWrap; d_data->title.setRenderFlags( flags ); d_data->title.setFont( font() ); QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->scaleDraw->orientation() == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } /*! Toggle an layout flag \param flag Layout flag \param on true/false \sa testLayoutFlag(), LayoutFlag */ void QwtScaleWidget::setLayoutFlag( LayoutFlag flag, bool on ) { if ( ( ( d_data->layoutFlags & flag ) != 0 ) != on ) { if ( on ) d_data->layoutFlags |= flag; else d_data->layoutFlags &= ~flag; } } /*! Test a layout flag \param flag Layout flag \return true/false \sa setLayoutFlag(), LayoutFlag */ bool QwtScaleWidget::testLayoutFlag( LayoutFlag flag ) const { return ( d_data->layoutFlags & flag ); } /*! Give title new text contents \param title New title \sa title(), setTitle(const QwtText &); */ void QwtScaleWidget::setTitle( const QString &title ) { if ( d_data->title.text() != title ) { d_data->title.setText( title ); layoutScale(); } } /*! Give title new text contents \param title New title \sa title() \warning The title flags are interpreted in direction of the label, AlignTop, AlignBottom can't be set as the title will always be aligned to the scale. */ void QwtScaleWidget::setTitle( const QwtText &title ) { QwtText t = title; const int flags = title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom ); t.setRenderFlags( flags ); if ( t != d_data->title ) { d_data->title = t; layoutScale(); } } /*! Change the alignment \param alignment New alignment \sa alignment() */ void QwtScaleWidget::setAlignment( QwtScaleDraw::Alignment alignment ) { if ( d_data->scaleDraw ) d_data->scaleDraw->setAlignment( alignment ); if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) { QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); if ( d_data->scaleDraw->orientation() == Qt::Vertical ) policy.transpose(); setSizePolicy( policy ); setAttribute( Qt::WA_WState_OwnSizePolicy, false ); } layoutScale(); } /*! \return position \sa setPosition() */ QwtScaleDraw::Alignment QwtScaleWidget::alignment() const { if ( !scaleDraw() ) return QwtScaleDraw::LeftScale; return scaleDraw()->alignment(); } /*! Specify distances of the scale's endpoints from the widget's borders. The actual borders will never be less than minimum border distance. \param dist1 Left or top Distance \param dist2 Right or bottom distance \sa borderDist() */ void QwtScaleWidget::setBorderDist( int dist1, int dist2 ) { if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] ) { d_data->borderDist[0] = dist1; d_data->borderDist[1] = dist2; layoutScale(); } } /*! \brief Specify the margin to the colorBar/base line. \param margin Margin \sa margin() */ void QwtScaleWidget::setMargin( int margin ) { margin = qMax( 0, margin ); if ( margin != d_data->margin ) { d_data->margin = margin; layoutScale(); } } /*! \brief Specify the distance between color bar, scale and title \param spacing Spacing \sa spacing() */ void QwtScaleWidget::setSpacing( int spacing ) { spacing = qMax( 0, spacing ); if ( spacing != d_data->spacing ) { d_data->spacing = spacing; layoutScale(); } } /*! \brief Change the alignment for the labels. \sa QwtScaleDraw::setLabelAlignment(), setLabelRotation() */ void QwtScaleWidget::setLabelAlignment( Qt::Alignment alignment ) { d_data->scaleDraw->setLabelAlignment( alignment ); layoutScale(); } /*! \brief Change the rotation for the labels. See QwtScaleDraw::setLabelRotation(). \param rotation Rotation \sa QwtScaleDraw::setLabelRotation(), setLabelFlags() */ void QwtScaleWidget::setLabelRotation( double rotation ) { d_data->scaleDraw->setLabelRotation( rotation ); layoutScale(); } /*! Set a scale draw scaleDraw has to be created with new and will be deleted in ~QwtScaleWidget() or the next call of setScaleDraw(). scaleDraw will be initialized with the attributes of the previous scaleDraw object. \param scaleDraw ScaleDraw object \sa scaleDraw() */ void QwtScaleWidget::setScaleDraw( QwtScaleDraw *scaleDraw ) { if ( ( scaleDraw == NULL ) || ( scaleDraw == d_data->scaleDraw ) ) return; const QwtScaleDraw* sd = d_data->scaleDraw; if ( sd ) { scaleDraw->setAlignment( sd->alignment() ); scaleDraw->setScaleDiv( sd->scaleDiv() ); QwtTransform *transform = NULL; if ( sd->scaleMap().transformation() ) transform = sd->scaleMap().transformation()->copy(); scaleDraw->setTransformation( transform ); } delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; layoutScale(); } /*! \return scaleDraw of this scale \sa setScaleDraw(), QwtScaleDraw::setScaleDraw() */ const QwtScaleDraw *QwtScaleWidget::scaleDraw() const { return d_data->scaleDraw; } /*! \return scaleDraw of this scale \sa QwtScaleDraw::setScaleDraw() */ QwtScaleDraw *QwtScaleWidget::scaleDraw() { return d_data->scaleDraw; } /*! \return title \sa setTitle() */ QwtText QwtScaleWidget::title() const { return d_data->title; } /*! \return start border distance \sa setBorderDist() */ int QwtScaleWidget::startBorderDist() const { return d_data->borderDist[0]; } /*! \return end border distance \sa setBorderDist() */ int QwtScaleWidget::endBorderDist() const { return d_data->borderDist[1]; } /*! \return margin \sa setMargin() */ int QwtScaleWidget::margin() const { return d_data->margin; } /*! \return distance between scale and title \sa setMargin() */ int QwtScaleWidget::spacing() const { return d_data->spacing; } /*! \brief paintEvent */ void QwtScaleWidget::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); draw( &painter ); } /*! \brief draw the scale */ void QwtScaleWidget::draw( QPainter *painter ) const { d_data->scaleDraw->draw( painter, palette() ); if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 && d_data->colorBar.interval.isValid() ) { drawColorBar( painter, colorBarRect( contentsRect() ) ); } QRect r = contentsRect(); if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) { r.setLeft( r.left() + d_data->borderDist[0] ); r.setWidth( r.width() - d_data->borderDist[1] ); } else { r.setTop( r.top() + d_data->borderDist[0] ); r.setHeight( r.height() - d_data->borderDist[1] ); } if ( !d_data->title.isEmpty() ) drawTitle( painter, d_data->scaleDraw->alignment(), r ); } /*! Calculate the the rectangle for the color bar \param rect Bounding rectangle for all components of the scale \return Rectangle for the color bar */ QRectF QwtScaleWidget::colorBarRect( const QRectF& rect ) const { QRectF cr = rect; if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) { cr.setLeft( cr.left() + d_data->borderDist[0] ); cr.setWidth( cr.width() - d_data->borderDist[1] + 1 ); } else { cr.setTop( cr.top() + d_data->borderDist[0] ); cr.setHeight( cr.height() - d_data->borderDist[1] + 1 ); } switch ( d_data->scaleDraw->alignment() ) { case QwtScaleDraw::LeftScale: { cr.setLeft( cr.right() - d_data->margin - d_data->colorBar.width ); cr.setWidth( d_data->colorBar.width ); break; } case QwtScaleDraw::RightScale: { cr.setLeft( cr.left() + d_data->margin ); cr.setWidth( d_data->colorBar.width ); break; } case QwtScaleDraw::BottomScale: { cr.setTop( cr.top() + d_data->margin ); cr.setHeight( d_data->colorBar.width ); break; } case QwtScaleDraw::TopScale: { cr.setTop( cr.bottom() - d_data->margin - d_data->colorBar.width ); cr.setHeight( d_data->colorBar.width ); break; } } return cr; } /*! Event handler for resize events \param event Resize event */ void QwtScaleWidget::resizeEvent( QResizeEvent *event ) { Q_UNUSED( event ); layoutScale( false ); } /*! Recalculate the scale's geometry and layout based on the current geometry and fonts. \param update_geometry Notify the layout system and call update to redraw the scale */ void QwtScaleWidget::layoutScale( bool update_geometry ) { int bd0, bd1; getBorderDistHint( bd0, bd1 ); if ( d_data->borderDist[0] > bd0 ) bd0 = d_data->borderDist[0]; if ( d_data->borderDist[1] > bd1 ) bd1 = d_data->borderDist[1]; int colorBarWidth = 0; if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() ) colorBarWidth = d_data->colorBar.width + d_data->spacing; const QRectF r = contentsRect(); double x, y, length; if ( d_data->scaleDraw->orientation() == Qt::Vertical ) { y = r.top() + bd0; length = r.height() - ( bd0 + bd1 ); if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale ) x = r.right() - 1.0 - d_data->margin - colorBarWidth; else x = r.left() + d_data->margin + colorBarWidth; } else { x = r.left() + bd0; length = r.width() - ( bd0 + bd1 ); if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale ) y = r.top() + d_data->margin + colorBarWidth; else y = r.bottom() - 1.0 - d_data->margin - colorBarWidth; } d_data->scaleDraw->move( x, y ); d_data->scaleDraw->setLength( length ); const int extent = qCeil( d_data->scaleDraw->extent( font() ) ); d_data->titleOffset = d_data->margin + d_data->spacing + colorBarWidth + extent; if ( update_geometry ) { updateGeometry(); update(); } } /*! Draw the color bar of the scale widget \param painter Painter \param rect Bounding rectangle for the color bar \sa setColorBarEnabled() */ void QwtScaleWidget::drawColorBar( QPainter *painter, const QRectF& rect ) const { if ( !d_data->colorBar.interval.isValid() ) return; const QwtScaleDraw* sd = d_data->scaleDraw; QwtPainter::drawColorBar( painter, *d_data->colorBar.colorMap, d_data->colorBar.interval.normalized(), sd->scaleMap(), sd->orientation(), rect ); } /*! Rotate and paint a title according to its position into a given rectangle. \param painter Painter \param align Alignment \param rect Bounding rectangle */ void QwtScaleWidget::drawTitle( QPainter *painter, QwtScaleDraw::Alignment align, const QRectF &rect ) const { QRectF r = rect; double angle; int flags = d_data->title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ); switch ( align ) { case QwtScaleDraw::LeftScale: angle = -90.0; flags |= Qt::AlignTop; r.setRect( r.left(), r.bottom(), r.height(), r.width() - d_data->titleOffset ); break; case QwtScaleDraw::RightScale: angle = -90.0; flags |= Qt::AlignTop; r.setRect( r.left() + d_data->titleOffset, r.bottom(), r.height(), r.width() - d_data->titleOffset ); break; case QwtScaleDraw::BottomScale: angle = 0.0; flags |= Qt::AlignBottom; r.setTop( r.top() + d_data->titleOffset ); break; case QwtScaleDraw::TopScale: default: angle = 0.0; flags |= Qt::AlignTop; r.setBottom( r.bottom() - d_data->titleOffset ); break; } if ( d_data->layoutFlags & TitleInverted ) { if ( align == QwtScaleDraw::LeftScale || align == QwtScaleDraw::RightScale ) { angle = -angle; r.setRect( r.x() + r.height(), r.y() - r.width(), r.width(), r.height() ); } } painter->save(); painter->setFont( font() ); painter->setPen( palette().color( QPalette::Text ) ); painter->translate( r.x(), r.y() ); if ( angle != 0.0 ) painter->rotate( angle ); QwtText title = d_data->title; title.setRenderFlags( flags ); title.draw( painter, QRectF( 0.0, 0.0, r.width(), r.height() ) ); painter->restore(); } /*! \brief Notify a change of the scale This virtual function can be overloaded by derived classes. The default implementation updates the geometry and repaints the widget. */ void QwtScaleWidget::scaleChange() { layoutScale(); } /*! \return a size hint */ QSize QwtScaleWidget::sizeHint() const { return minimumSizeHint(); } /*! \return a minimum size hint */ QSize QwtScaleWidget::minimumSizeHint() const { const Qt::Orientation o = d_data->scaleDraw->orientation(); // Border Distance cannot be less than the scale borderDistHint // Note, the borderDistHint is already included in minHeight/minWidth int length = 0; int mbd1, mbd2; getBorderDistHint( mbd1, mbd2 ); length += qMax( 0, d_data->borderDist[0] - mbd1 ); length += qMax( 0, d_data->borderDist[1] - mbd2 ); length += d_data->scaleDraw->minLength( font() ); int dim = dimForLength( length, font() ); if ( length < dim ) { // compensate for long titles length = dim; dim = dimForLength( length, font() ); } QSize size( length + 2, dim ); if ( o == Qt::Vertical ) size.transpose(); int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); return size + QSize( left + right, top + bottom ); } /*! \brief Find the height of the title for a given width. \param width Width \return height Height */ int QwtScaleWidget::titleHeightForWidth( int width ) const { return qCeil( d_data->title.heightForWidth( width, font() ) ); } /*! \brief Find the minimum dimension for a given length. dim is the height, length the width seen in direction of the title. \param length width for horizontal, height for vertical scales \param scaleFont Font of the scale \return height for horizontal, width for vertical scales */ int QwtScaleWidget::dimForLength( int length, const QFont &scaleFont ) const { const int extent = qCeil( d_data->scaleDraw->extent( scaleFont ) ); int dim = d_data->margin + extent + 1; if ( !d_data->title.isEmpty() ) dim += titleHeightForWidth( length ) + d_data->spacing; if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() ) dim += d_data->colorBar.width + d_data->spacing; return dim; } /*! \brief Calculate a hint for the border distances. This member function calculates the distance of the scale's endpoints from the widget borders which is required for the mark labels to fit into the widget. The maximum of this distance an the minimum border distance is returned. \param start Return parameter for the border width at the beginning of the scale \param end Return parameter for the border width at the end of the scale \warning
  • The minimum border distance depends on the font.
\sa setMinBorderDist(), getMinBorderDist(), setBorderDist() */ void QwtScaleWidget::getBorderDistHint( int &start, int &end ) const { d_data->scaleDraw->getBorderDistHint( font(), start, end ); if ( start < d_data->minBorderDist[0] ) start = d_data->minBorderDist[0]; if ( end < d_data->minBorderDist[1] ) end = d_data->minBorderDist[1]; } /*! Set a minimum value for the distances of the scale's endpoints from the widget borders. This is useful to avoid that the scales are "jumping", when the tick labels or their positions change often. \param start Minimum for the start border \param end Minimum for the end border \sa getMinBorderDist(), getBorderDistHint() */ void QwtScaleWidget::setMinBorderDist( int start, int end ) { d_data->minBorderDist[0] = start; d_data->minBorderDist[1] = end; } /*! Get the minimum value for the distances of the scale's endpoints from the widget borders. \param start Return parameter for the border width at the beginning of the scale \param end Return parameter for the border width at the end of the scale \sa setMinBorderDist(), getBorderDistHint() */ void QwtScaleWidget::getMinBorderDist( int &start, int &end ) const { start = d_data->minBorderDist[0]; end = d_data->minBorderDist[1]; } /*! \brief Assign a scale division The scale division determines where to set the tick marks. \param scaleDiv Scale Division \sa For more information about scale divisions, see QwtScaleDiv. */ void QwtScaleWidget::setScaleDiv( const QwtScaleDiv &scaleDiv ) { QwtScaleDraw *sd = d_data->scaleDraw; if ( sd->scaleDiv() != scaleDiv ) { sd->setScaleDiv( scaleDiv ); layoutScale(); Q_EMIT scaleDivChanged(); } } /*! Set the transformation \param transformation Transformation \sa QwtAbstractScaleDraw::scaleDraw(), QwtScaleMap */ void QwtScaleWidget::setTransformation( QwtTransform *transformation ) { d_data->scaleDraw->setTransformation( transformation ); layoutScale(); } /*! En/disable a color bar associated to the scale \sa isColorBarEnabled(), setColorBarWidth() */ void QwtScaleWidget::setColorBarEnabled( bool on ) { if ( on != d_data->colorBar.isEnabled ) { d_data->colorBar.isEnabled = on; layoutScale(); } } /*! \return true, when the color bar is enabled \sa setColorBarEnabled(), setColorBarWidth() */ bool QwtScaleWidget::isColorBarEnabled() const { return d_data->colorBar.isEnabled; } /*! Set the width of the color bar \param width Width \sa colorBarWidth(), setColorBarEnabled() */ void QwtScaleWidget::setColorBarWidth( int width ) { if ( width != d_data->colorBar.width ) { d_data->colorBar.width = width; if ( isColorBarEnabled() ) layoutScale(); } } /*! \return Width of the color bar \sa setColorBarEnabled(), setColorBarEnabled() */ int QwtScaleWidget::colorBarWidth() const { return d_data->colorBar.width; } /*! \return Value interval for the color bar \sa setColorMap(), colorMap() */ QwtInterval QwtScaleWidget::colorBarInterval() const { return d_data->colorBar.interval; } /*! Set the color map and value interval, that are used for displaying the color bar. \param interval Value interval \param colorMap Color map \sa colorMap(), colorBarInterval() */ void QwtScaleWidget::setColorMap( const QwtInterval &interval, QwtColorMap *colorMap ) { d_data->colorBar.interval = interval; if ( colorMap != d_data->colorBar.colorMap ) { delete d_data->colorBar.colorMap; d_data->colorBar.colorMap = colorMap; } if ( isColorBarEnabled() ) layoutScale(); } /*! \return Color map \sa setColorMap(), colorBarInterval() */ const QwtColorMap *QwtScaleWidget::colorMap() const { return d_data->colorBar.colorMap; } qsstv_8.2.12/qwt/qwt_transform.h000664 001750 001750 00000006667 12440612574 016704 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_TRANSFORM_H #define QWT_TRANSFORM_H #include "qwt_global.h" /*! \brief A transformation between coordinate systems QwtTransform manipulates values, when being mapped between the scale and the paint device coordinate system. A transformation consists of 2 methods: - transform - invTransform where one is is the inverse function of the other. When p1, p2 are the boundaries of the paint device coordinates and s1, s2 the boundaries of the scale, QwtScaleMap uses the following calculations: - p = p1 + ( p2 - p1 ) * ( T( s ) - T( s1 ) / ( T( s2 ) - T( s1 ) ); - s = invT ( T( s1 ) + ( T( s2 ) - T( s1 ) ) * ( p - p1 ) / ( p2 - p1 ) ); */ class QWT_EXPORT QwtTransform { public: QwtTransform(); virtual ~QwtTransform(); /*! Modify value to be a valid value for the transformation. The default implementation does nothing. */ virtual double bounded( double value ) const; /*! Transformation function \param value Value \return Modified value \sa invTransform() */ virtual double transform( double value ) const = 0; /*! Inverse transformation function \param value Value \return Modified value \sa transform() */ virtual double invTransform( double value ) const = 0; //! Virtualized copy operation virtual QwtTransform *copy() const = 0; }; /*! \brief Null transformation QwtNullTransform returns the values unmodified. */ class QWT_EXPORT QwtNullTransform: public QwtTransform { public: QwtNullTransform(); virtual ~QwtNullTransform(); virtual double transform( double value ) const; virtual double invTransform( double value ) const; virtual QwtTransform *copy() const; }; /*! \brief Logarithmic transformation QwtLogTransform modifies the values using log() and exp(). \note In the calculations of QwtScaleMap the base of the log function has no effect on the mapping. So QwtLogTransform can be used for log2(), log10() or any other logarithmic scale. */ class QWT_EXPORT QwtLogTransform: public QwtTransform { public: QwtLogTransform(); virtual ~QwtLogTransform(); virtual double transform( double value ) const; virtual double invTransform( double value ) const; virtual double bounded( double value ) const; virtual QwtTransform *copy() const; QT_STATIC_CONST double LogMin; QT_STATIC_CONST double LogMax; }; /*! \brief A transformation using pow() QwtPowerTransform preserves the sign of a value. F.e. a transformation with a factor of 2 transforms a value of -3 to -9 and v.v. Thus QwtPowerTransform can be used for scales including negative values. */ class QWT_EXPORT QwtPowerTransform: public QwtTransform { public: QwtPowerTransform( double exponent ); virtual ~QwtPowerTransform(); virtual double transform( double value ) const; virtual double invTransform( double value ) const; virtual QwtTransform *copy() const; private: const double d_exponent; }; #endif qsstv_8.2.12/qwt/qwt_samples.h000664 001750 001750 00000011540 12440612574 016317 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SAMPLES_H #define QWT_SAMPLES_H 1 #include "qwt_global.h" #include "qwt_interval.h" #include #include //! \brief A sample of the types (x1-x2, y) or (x, y1-y2) class QWT_EXPORT QwtIntervalSample { public: QwtIntervalSample(); QwtIntervalSample( double, const QwtInterval & ); QwtIntervalSample( double value, double min, double max ); bool operator==( const QwtIntervalSample & ) const; bool operator!=( const QwtIntervalSample & ) const; //! Value double value; //! Interval QwtInterval interval; }; /*! Constructor The value is set to 0.0, the interval is invalid */ inline QwtIntervalSample::QwtIntervalSample(): value( 0.0 ) { } //! Constructor inline QwtIntervalSample::QwtIntervalSample( double v, const QwtInterval &intv ): value( v ), interval( intv ) { } //! Constructor inline QwtIntervalSample::QwtIntervalSample( double v, double min, double max ): value( v ), interval( min, max ) { } //! Compare operator inline bool QwtIntervalSample::operator==( const QwtIntervalSample &other ) const { return value == other.value && interval == other.interval; } //! Compare operator inline bool QwtIntervalSample::operator!=( const QwtIntervalSample &other ) const { return !( *this == other ); } //! \brief A sample of the types (x1...xn, y) or (x, y1..yn) class QWT_EXPORT QwtSetSample { public: QwtSetSample(); QwtSetSample( double, const QVector & = QVector() ); bool operator==( const QwtSetSample &other ) const; bool operator!=( const QwtSetSample &other ) const; double added() const; //! value double value; //! Vector of values associated to value QVector set; }; /*! Constructor The value is set to 0.0 */ inline QwtSetSample::QwtSetSample(): value( 0.0 ) { } /*! Constructor \param v Value \param s Set of values */ inline QwtSetSample::QwtSetSample( double v, const QVector< double > &s ): value( v ), set( s ) { } //! Compare operator inline bool QwtSetSample::operator==( const QwtSetSample &other ) const { return value == other.value && set == other.set; } //! Compare operator inline bool QwtSetSample::operator!=( const QwtSetSample &other ) const { return !( *this == other ); } //! \return All values of the set added inline double QwtSetSample::added() const { double y = 0.0; for ( int i = 0; i < set.size(); i++ ) y += set[i]; return y; } /*! \brief Open-High-Low-Close sample used in financial charts In financial charts the movement of a price in a time interval is often represented by the opening/closing prices and the lowest/highest prices in this interval. \sa QwtTradingChartData */ class QWT_EXPORT QwtOHLCSample { public: QwtOHLCSample( double time = 0.0, double open = 0.0, double high = 0.0, double low = 0.0, double close = 0.0 ); QwtInterval boundingInterval() const; bool isValid() const; /*! Time of the sample, usually a number representing a specific interval - like a day. */ double time; //! Opening price double open; //! Highest price double high; //! Lowest price double low; //! Closing price double close; }; /*! Constructor \param t Time value \param o Open value \param h High value \param l Low value \param c Close value */ inline QwtOHLCSample::QwtOHLCSample( double t, double o, double h, double l, double c ): time( t ), open( o ), high( h ), low( l ), close( c ) { } /*! \brief Check if a sample is valid A sample is valid, when all of the following checks are true: - low <= high - low <= open <= high - low <= close <= high \return True, when the sample is valid */ inline bool QwtOHLCSample::isValid() const { return ( low <= high ) && ( open >= low ) && ( open <= high ) && ( close >= low ) && ( close <= high ); } /*! \brief Calculate the bounding interval of the OHLC values For valid samples the limits of this interval are always low/high. \return Bounding interval \sa isValid() */ inline QwtInterval QwtOHLCSample::boundingInterval() const { double minY = open; minY = qMin( minY, high ); minY = qMin( minY, low ); minY = qMin( minY, close ); double maxY = open; maxY = qMax( maxY, high ); maxY = qMax( maxY, low ); maxY = qMax( maxY, close ); return QwtInterval( minY, maxY ); } #endif qsstv_8.2.12/qwt/qwt.h000664 001750 001750 00000001000 12440612574 014561 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_H #define QWT_H #include "qwt_global.h" /*! Some constants for use within Qwt. */ namespace Qwt { }; #endif qsstv_8.2.12/qwt/qwt_plot_item.cpp000664 001750 001750 00000037146 12440612574 017214 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_item.h" #include "qwt_text.h" #include "qwt_plot.h" #include "qwt_legend_data.h" #include "qwt_scale_div.h" #include "qwt_graphic.h" #include class QwtPlotItem::PrivateData { public: PrivateData(): plot( NULL ), isVisible( true ), attributes( 0 ), interests( 0 ), renderHints( 0 ), renderThreadCount( 1 ), z( 0.0 ), xAxis( QwtPlot::xBottom ), yAxis( QwtPlot::yLeft ), legendIconSize( 8, 8 ) { } mutable QwtPlot *plot; bool isVisible; QwtPlotItem::ItemAttributes attributes; QwtPlotItem::ItemInterests interests; QwtPlotItem::RenderHints renderHints; uint renderThreadCount; double z; int xAxis; int yAxis; QwtText title; QSize legendIconSize; }; /*! Constructor \param title Title of the item */ QwtPlotItem::QwtPlotItem( const QwtText &title ) { d_data = new PrivateData; d_data->title = title; } //! Destroy the QwtPlotItem QwtPlotItem::~QwtPlotItem() { attach( NULL ); delete d_data; } /*! \brief Attach the item to a plot. This method will attach a QwtPlotItem to the QwtPlot argument. It will first detach the QwtPlotItem from any plot from a previous call to attach (if necessary). If a NULL argument is passed, it will detach from any QwtPlot it was attached to. \param plot Plot widget \sa detach() */ void QwtPlotItem::attach( QwtPlot *plot ) { if ( plot == d_data->plot ) return; if ( d_data->plot ) d_data->plot->attachItem( this, false ); d_data->plot = plot; if ( d_data->plot ) d_data->plot->attachItem( this, true ); } /*! \brief This method detaches a QwtPlotItem from any QwtPlot it has been associated with. detach() is equivalent to calling attach( NULL ) \sa attach() */ void QwtPlotItem::detach() { attach( NULL ); } /*! Return rtti for the specific class represented. QwtPlotItem is simply a virtual interface class, and base classes will implement this method with specific rtti values so a user can differentiate them. The rtti value is useful for environments, where the runtime type information is disabled and it is not possible to do a dynamic_cast<...>. \return rtti value \sa RttiValues */ int QwtPlotItem::rtti() const { return Rtti_PlotItem; } //! Return attached plot QwtPlot *QwtPlotItem::plot() const { return d_data->plot; } /*! Plot items are painted in increasing z-order. \return setZ(), QwtPlotDict::itemList() */ double QwtPlotItem::z() const { return d_data->z; } /*! \brief Set the z value Plot items are painted in increasing z-order. \param z Z-value \sa z(), QwtPlotDict::itemList() */ void QwtPlotItem::setZ( double z ) { if ( d_data->z != z ) { if ( d_data->plot ) // update the z order d_data->plot->attachItem( this, false ); d_data->z = z; if ( d_data->plot ) d_data->plot->attachItem( this, true ); itemChanged(); } } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QString &title ) { setTitle( QwtText( title ) ); } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QwtText &title ) { if ( d_data->title != title ) { d_data->title = title; legendChanged(); #if 0 itemChanged(); #endif } } /*! \return Title of the item \sa setTitle() */ const QwtText &QwtPlotItem::title() const { return d_data->title; } /*! Toggle an item attribute \param attribute Attribute type \param on true/false \sa testItemAttribute(), ItemInterest */ void QwtPlotItem::setItemAttribute( ItemAttribute attribute, bool on ) { if ( d_data->attributes.testFlag( attribute ) != on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; if ( attribute == QwtPlotItem::Legend ) legendChanged(); itemChanged(); } } /*! Test an item attribute \param attribute Attribute type \return true/false \sa setItemAttribute(), ItemInterest */ bool QwtPlotItem::testItemAttribute( ItemAttribute attribute ) const { return d_data->attributes.testFlag( attribute ); } /*! Toggle an item interest \param interest Interest type \param on true/false \sa testItemInterest(), ItemAttribute */ void QwtPlotItem::setItemInterest( ItemInterest interest, bool on ) { if ( d_data->interests.testFlag( interest ) != on ) { if ( on ) d_data->interests |= interest; else d_data->interests &= ~interest; itemChanged(); } } /*! Test an item interest \param interest Interest type \return true/false \sa setItemInterest(), ItemAttribute */ bool QwtPlotItem::testItemInterest( ItemInterest interest ) const { return d_data->interests.testFlag( interest ); } /*! Toggle an render hint \param hint Render hint \param on true/false \sa testRenderHint(), RenderHint */ void QwtPlotItem::setRenderHint( RenderHint hint, bool on ) { if ( d_data->renderHints.testFlag( hint ) != on ) { if ( on ) d_data->renderHints |= hint; else d_data->renderHints &= ~hint; itemChanged(); } } /*! Test a render hint \param hint Render hint \return true/false \sa setRenderHint(), RenderHint */ bool QwtPlotItem::testRenderHint( RenderHint hint ) const { return d_data->renderHints.testFlag( hint ); } /*! On multi core systems rendering of certain plot item ( f.e QwtPlotRasterItem ) can be done in parallel in several threads. The default setting is set to 1. \param numThreads Number of threads to be used for rendering. If numThreads is set to 0, the system specific ideal thread count is used. The default thread count is 1 ( = no additional threads ) */ void QwtPlotItem::setRenderThreadCount( uint numThreads ) { d_data->renderThreadCount = numThreads; } /*! \return Number of threads to be used for rendering. If numThreads() is set to 0, the system specific ideal thread count is used. */ uint QwtPlotItem::renderThreadCount() const { return d_data->renderThreadCount; } /*! Set the size of the legend icon The default setting is 8x8 pixels \param size Size \sa legendIconSize(), legendIcon() */ void QwtPlotItem::setLegendIconSize( const QSize &size ) { if ( d_data->legendIconSize != size ) { d_data->legendIconSize = size; legendChanged(); } } /*! \return Legend icon size \sa setLegendIconSize(), legendIcon() */ QSize QwtPlotItem::legendIconSize() const { return d_data->legendIconSize; } /*! \return Icon representing the item on the legend The default implementation returns an invalid icon \param index Index of the legend entry ( usually there is only one ) \param size Icon size \sa setLegendIconSize(), legendData() */ QwtGraphic QwtPlotItem::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ) Q_UNUSED( size ) return QwtGraphic(); } /*! \brief Return a default icon from a brush The default icon is a filled rectangle used in several derived classes as legendIcon(). \param brush Fill brush \param size Icon size \return A filled rectangle */ QwtGraphic QwtPlotItem::defaultIcon( const QBrush &brush, const QSizeF &size ) const { QwtGraphic icon; if ( !size.isEmpty() ) { icon.setDefaultSize( size ); QRectF r( 0, 0, size.width(), size.height() ); QPainter painter( &icon ); painter.fillRect( r, brush ); } return icon; } //! Show the item void QwtPlotItem::show() { setVisible( true ); } //! Hide the item void QwtPlotItem::hide() { setVisible( false ); } /*! Show/Hide the item \param on Show if true, otherwise hide \sa isVisible(), show(), hide() */ void QwtPlotItem::setVisible( bool on ) { if ( on != d_data->isVisible ) { d_data->isVisible = on; itemChanged(); } } /*! \return true if visible \sa setVisible(), show(), hide() */ bool QwtPlotItem::isVisible() const { return d_data->isVisible; } /*! Update the legend and call QwtPlot::autoRefresh() for the parent plot. \sa QwtPlot::legendChanged(), QwtPlot::autoRefresh() */ void QwtPlotItem::itemChanged() { if ( d_data->plot ) d_data->plot->autoRefresh(); } /*! Update the legend of the parent plot. \sa QwtPlot::updateLegend(), itemChanged() */ void QwtPlotItem::legendChanged() { if ( testItemAttribute( QwtPlotItem::Legend ) && d_data->plot ) d_data->plot->updateLegend( this ); } /*! Set X and Y axis The item will painted according to the coordinates of its Axes. \param xAxis X Axis ( QwtPlot::xBottom or QwtPlot::xTop ) \param yAxis Y Axis ( QwtPlot::yLeft or QwtPlot::yRight ) \sa setXAxis(), setYAxis(), xAxis(), yAxis(), QwtPlot::Axis */ void QwtPlotItem::setAxes( int xAxis, int yAxis ) { if ( xAxis == QwtPlot::xBottom || xAxis == QwtPlot::xTop ) d_data->xAxis = xAxis; if ( yAxis == QwtPlot::yLeft || yAxis == QwtPlot::yRight ) d_data->yAxis = yAxis; itemChanged(); } /*! Set the X axis The item will painted according to the coordinates its Axes. \param axis X Axis ( QwtPlot::xBottom or QwtPlot::xTop ) \sa setAxes(), setYAxis(), xAxis(), QwtPlot::Axis */ void QwtPlotItem::setXAxis( int axis ) { if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { d_data->xAxis = axis; itemChanged(); } } /*! Set the Y axis The item will painted according to the coordinates its Axes. \param axis Y Axis ( QwtPlot::yLeft or QwtPlot::yRight ) \sa setAxes(), setXAxis(), yAxis(), QwtPlot::Axis */ void QwtPlotItem::setYAxis( int axis ) { if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) { d_data->yAxis = axis; itemChanged(); } } //! Return xAxis int QwtPlotItem::xAxis() const { return d_data->xAxis; } //! Return yAxis int QwtPlotItem::yAxis() const { return d_data->yAxis; } /*! \return An invalid bounding rect: QRectF(1.0, 1.0, -2.0, -2.0) \note A width or height < 0.0 is ignored by the autoscaler */ QRectF QwtPlotItem::boundingRect() const { return QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid } /*! \brief Calculate a hint for the canvas margin When the QwtPlotItem::Margins flag is enabled the plot item indicates, that it needs some margins at the borders of the canvas. This is f.e. used by bar charts to reserve space for displaying the bars. The margins are in target device coordinates ( pixels on screen ) \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas in painter coordinates \param left Returns the left margin \param top Returns the top margin \param right Returns the right margin \param bottom Returns the bottom margin \return The default implementation returns 0 for all margins \sa QwtPlot::getCanvasMarginsHint(), QwtPlot::updateCanvasMargins() */ void QwtPlotItem::getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, double &left, double &top, double &right, double &bottom ) const { Q_UNUSED( xMap ); Q_UNUSED( yMap ); Q_UNUSED( canvasRect ); // use QMargins, when we don't need to support Qt < 4.6 anymore left = top = right = bottom = 0.0; } /*! \brief Return all information, that is needed to represent the item on the legend Most items are represented by one entry on the legend showing an icon and a text, but f.e. QwtPlotMultiBarChart displays one entry for each bar. QwtLegendData is basically a list of QVariants that makes it possible to overload and reimplement legendData() to return almost any type of information, that is understood by the receiver that acts as the legend. The default implementation returns one entry with the title() of the item and the legendIcon(). \return Data, that is needed to represent the item on the legend \sa title(), legendIcon(), QwtLegend, QwtPlotLegendItem */ QList QwtPlotItem::legendData() const { QwtLegendData data; QwtText label = title(); label.setRenderFlags( label.renderFlags() & Qt::AlignLeft ); QVariant titleValue; qVariantSetValue( titleValue, label ); data.setValue( QwtLegendData::TitleRole, titleValue ); const QwtGraphic graphic = legendIcon( 0, legendIconSize() ); if ( !graphic.isNull() ) { QVariant iconValue; qVariantSetValue( iconValue, graphic ); data.setValue( QwtLegendData::IconRole, iconValue ); } QList list; list += data; return list; } /*! \brief Update the item to changes of the axes scale division Update the item, when the axes of plot have changed. The default implementation does nothing, but items that depend on the scale division (like QwtPlotGrid()) have to reimplement updateScaleDiv() updateScaleDiv() is only called when the ScaleInterest interest is enabled. The default implementation does nothing. \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes(), ScaleInterest */ void QwtPlotItem::updateScaleDiv( const QwtScaleDiv &xScaleDiv, const QwtScaleDiv &yScaleDiv ) { Q_UNUSED( xScaleDiv ); Q_UNUSED( yScaleDiv ); } /*! \brief Update the item to changes of the legend info Plot items that want to display a legend ( not those, that want to be displayed on a legend ! ) will have to implement updateLegend(). updateLegend() is only called when the LegendInterest interest is enabled. The default implementation does nothing. \param item Plot item to be displayed on a legend \param data Attributes how to display item on the legend \sa QwtPlotLegendItem \note Plot items, that want to be displayed on a legend need to enable the QwtPlotItem::Legend flag and to implement legendData() and legendIcon() */ void QwtPlotItem::updateLegend( const QwtPlotItem *item, const QList &data ) { Q_UNUSED( item ); Q_UNUSED( data ); } /*! \brief Calculate the bounding scale rectangle of 2 maps \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Bounding scale rect of the scale maps, not normalized */ QRectF QwtPlotItem::scaleRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { return QRectF( xMap.s1(), yMap.s1(), xMap.sDist(), yMap.sDist() ); } /*! \brief Calculate the bounding paint rectangle of 2 maps \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Bounding paint rectangle of the scale maps, not normalized */ QRectF QwtPlotItem::paintRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { const QRectF rect( xMap.p1(), yMap.p1(), xMap.pDist(), yMap.pDist() ); return rect; } qsstv_8.2.12/qwt/qwt.pro000664 001750 001750 00000012162 12440612574 015145 0ustar00jomajoma000000 000000 #------------------------------------------------- # # Project created by QtCreator 2014-03-11T09:49:32 # #------------------------------------------------- QT += core gui concurrent greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = qwt TEMPLATE = lib CONFIG += staticlib SOURCES += \ qwt_point_3d.cpp \ qwt_abstract_legend.cpp \ qwt_pixel_matrix.cpp \ qwt_plot_xml.cpp \ qwt_math.cpp \ qwt_sampling_thread.cpp \ qwt_plot_seriesitem.cpp \ qwt_legend_data.cpp \ qwt_point_polar.cpp \ qwt_transform.cpp \ qwt_plot_magnifier.cpp \ qwt_plot_dict.cpp \ qwt_plot_textlabel.cpp \ qwt_scale_map.cpp \ qwt_painter_command.cpp \ qwt_analog_clock.cpp \ qwt_compass_rose.cpp \ qwt_plot_panner.cpp \ qwt_event_pattern.cpp \ qwt_date_scale_draw.cpp \ qwt_point_data.cpp \ qwt_column_symbol.cpp \ qwt_text_label.cpp \ qwt_plot_zoneitem.cpp \ qwt_compass.cpp \ qwt_scale_div.cpp \ qwt_plot_spectrocurve.cpp \ qwt_matrix_raster_data.cpp \ qwt_interval_symbol.cpp \ qwt_system_clock.cpp \ qwt_round_scale_draw.cpp \ qwt_arrow_button.cpp \ qwt_plot_directpainter.cpp \ qwt_interval.cpp \ qwt_widget_overlay.cpp \ qwt_spline.cpp \ qwt_text_engine.cpp \ qwt_series_data.cpp \ qwt_legend_label.cpp \ qwt_plot_picker.cpp \ qwt_plot_abstract_barchart.cpp \ qwt_abstract_scale_draw.cpp \ qwt_plot_grid.cpp \ qwt_color_map.cpp \ qwt_curve_fitter.cpp \ qwt_abstract_scale.cpp \ qwt_plot_scaleitem.cpp \ qwt_dial_needle.cpp \ qwt_plot_shapeitem.cpp \ qwt_plot_barchart.cpp \ qwt_raster_data.cpp \ qwt_magnifier.cpp \ qwt_panner.cpp \ qwt_clipper.cpp \ qwt_picker_machine.cpp \ qwt_null_paintdevice.cpp \ qwt_plot_marker.cpp \ qwt_dyngrid_layout.cpp \ qwt_plot_zoomer.cpp \ qwt_plot_rescaler.cpp \ qwt_plot_intervalcurve.cpp \ qwt_plot_item.cpp \ qwt_text.cpp \ qwt_date.cpp \ qwt_plot_spectrogram.cpp \ qwt_counter.cpp \ qwt_plot_axis.cpp \ qwt_plot_histogram.cpp \ qwt_plot_tradingcurve.cpp \ qwt_abstract_slider.cpp \ qwt_plot_multi_barchart.cpp \ qwt_point_mapper.cpp \ qwt_dial.cpp \ qwt_plot_legenditem.cpp \ qwt_knob.cpp \ qwt_legend.cpp \ qwt_scale_draw.cpp \ qwt_scale_widget.cpp \ qwt_thermo.cpp \ qwt_slider.cpp \ qwt_graphic.cpp \ qwt_plot_rasteritem.cpp \ qwt_plot_renderer.cpp \ qwt_scale_engine.cpp \ qwt_plot_canvas.cpp \ qwt_wheel.cpp \ qwt_plot_curve.cpp \ qwt_plot.cpp \ qwt_date_scale_engine.cpp \ qwt_painter.cpp \ qwt_picker.cpp \ qwt_plot_layout.cpp \ qwt_symbol.cpp HEADERS += \ qwt.h \ qwt_compat.h \ qwt_clipper.h \ qwt_global.h \ qwt_sampling_thread.h \ qwt_system_clock.h \ qwt_plot_magnifier.h \ qwt_arrow_button.h \ qwt_plot_panner.h \ qwt_plot_svgitem.h \ qwt_plot_dict.h \ qwt_plot_zoneitem.h \ qwt_plot_textlabel.h \ qwt_date_scale_draw.h \ qwt_text_label.h \ qwt_round_scale_draw.h \ qwt_legend_label.h \ qwt_plot_seriesitem.h \ qwt_matrix_raster_data.h \ qwt_abstract_legend.h \ qwt_compass.h \ qwt_plot_spectrocurve.h \ qwt_analog_clock.h \ qwt_legend_data.h \ qwt_compass_rose.h \ qwt_interval_symbol.h \ qwt_date_scale_engine.h \ qwt_pixel_matrix.h \ qwt_dyngrid_layout.h \ qwt_magnifier.h \ qwt_spline.h \ qwt_plot_grid.h \ qwt_plot_abstract_barchart.h \ qwt_plot_scaleitem.h \ qwt_raster_data.h \ qwt_point_mapper.h \ qwt_scale_div.h \ qwt_plot_picker.h \ qwt_abstract_scale.h \ qwt_panner.h \ qwt_plot_directpainter.h \ qwt_scale_draw.h \ qwt_plot_layout.h \ qwt_plot_shapeitem.h \ qwt_math.h \ qwt_null_paintdevice.h \ qwt_plot_marker.h \ qwt_legend.h \ qwt_slider.h \ qwt_transform.h \ qwt_scale_widget.h \ qwt_date.h \ qwt_plot_barchart.h \ qwt_point_data.h \ qwt_plot_spectrogram.h \ qwt_abstract_scale_draw.h \ qwt_plot_legenditem.h \ qwt_curve_fitter.h \ qwt_scale_map.h \ qwt_painter_command.h \ qwt_column_symbol.h \ qwt_plot_rescaler.h \ qwt_point_3d.h \ qwt_plot_intervalcurve.h \ qwt_plot_multi_barchart.h \ qwt_widget_overlay.h \ qwt_dial_needle.h \ qwt_plot_zoomer.h \ qwt_plot_histogram.h \ qwt_counter.h \ qwt_abstract_slider.h \ qwt_plot_renderer.h \ qwt_point_polar.h \ qwt_thermo.h \ qwt_knob.h \ qwt_plot_rasteritem.h \ qwt_series_store.h \ qwt_text_engine.h \ qwt_wheel.h \ qwt_plot_canvas.h \ qwt_samples.h \ qwt_dial.h \ qwt_color_map.h \ qwt_plot_tradingcurve.h \ qwt_graphic.h \ qwt_picker_machine.h \ qwt_event_pattern.h \ qwt_painter.h \ qwt_text.h \ qwt_symbol.h \ qwt_scale_engine.h \ qwt_interval.h \ qwt_plot_item.h \ qwt_plot.h \ qwt_series_data.h \ qwt_picker.h \ qwt_plot_curve.h unix:!symbian { maemo5 { target.path = /opt/usr/lib } else { target.path = /usr/lib } INSTALLS += target } qsstv_8.2.12/qwt/qwt_knob.cpp000664 001750 001750 00000047716 12440612574 016155 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_knob.h" #include "qwt_round_scale_draw.h" #include "qwt_math.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include #include #include #include #include #include #include #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #define qFabs(x) ::fabs(x) #define qFastCos(x) qCos(x) #define qFastSin(x) qSin(x) #endif static QSize qwtKnobSizeHint( const QwtKnob *knob, int min ) { int knobWidth = knob->knobWidth(); if ( knobWidth <= 0 ) knobWidth = qMax( 3 * knob->markerSize(), min ); // Add the scale radial thickness to the knobWidth const int extent = qCeil( knob->scaleDraw()->extent( knob->font() ) ); const int d = 2 * ( extent + 4 ) + knobWidth; int left, right, top, bottom; knob->getContentsMargins( &left, &top, &right, &bottom ); return QSize( d + left + right, d + top + bottom ); } static inline double qwtToScaleAngle( double angle ) { // the map is counter clockwise with the origin // at 90° using angles from -180° -> 180° double a = 90.0 - angle; if ( a <= -180.0 ) a += 360.0; else if ( a >= 180.0 ) a -= 360.0; return a; } static double qwtToDegrees( double value ) { return qwtNormalizeDegrees( 90.0 - value ); } class QwtKnob::PrivateData { public: PrivateData(): knobStyle( QwtKnob::Raised ), markerStyle( QwtKnob::Notch ), borderWidth( 2 ), borderDist( 4 ), scaleDist( 4 ), maxScaleTicks( 11 ), knobWidth( 0 ), alignment( Qt::AlignCenter ), markerSize( 8 ), totalAngle( 270.0 ), mouseOffset( 0.0 ) { } QwtKnob::KnobStyle knobStyle; QwtKnob::MarkerStyle markerStyle; int borderWidth; int borderDist; int scaleDist; int maxScaleTicks; int knobWidth; Qt::Alignment alignment; int markerSize; double totalAngle; double mouseOffset; }; /*! \brief Constructor Construct a knob with an angle of 270°. The style is QwtKnob::Raised and the marker style is QwtKnob::Notch. The width of the knob is set to 50 pixels. \param parent Parent widget \sa setTotalAngle() */ QwtKnob::QwtKnob( QWidget* parent ): QwtAbstractSlider( parent ) { d_data = new PrivateData; setScaleDraw( new QwtRoundScaleDraw() ); setTotalAngle( 270.0 ); setScale( 0.0, 10.0 ); setValue( 0.0 ); setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); } //! Destructor QwtKnob::~QwtKnob() { delete d_data; } /*! \brief Set the knob type \param knobStyle Knob type \sa knobStyle(), setBorderWidth() */ void QwtKnob::setKnobStyle( KnobStyle knobStyle ) { if ( d_data->knobStyle != knobStyle ) { d_data->knobStyle = knobStyle; update(); } } /*! \return Marker type of the knob \sa setKnobStyle(), setBorderWidth() */ QwtKnob::KnobStyle QwtKnob::knobStyle() const { return d_data->knobStyle; } /*! \brief Set the marker type of the knob \param markerStyle Marker type \sa markerStyle(), setMarkerSize() */ void QwtKnob::setMarkerStyle( MarkerStyle markerStyle ) { if ( d_data->markerStyle != markerStyle ) { d_data->markerStyle = markerStyle; update(); } } /*! \return Marker type of the knob \sa setMarkerStyle(), setMarkerSize() */ QwtKnob::MarkerStyle QwtKnob::markerStyle() const { return d_data->markerStyle; } /*! \brief Set the total angle by which the knob can be turned \param angle Angle in degrees. The angle has to be between [10, 360] degrees. Angles above 360 ( so that the knob can be turned several times around its axis ) have to be set using setNumTurns(). The default angle is 270 degrees. \sa totalAngle(), setNumTurns() */ void QwtKnob::setTotalAngle ( double angle ) { angle = qBound( 10.0, angle, 360.0 ); if ( angle != d_data->totalAngle ) { d_data->totalAngle = angle; scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 0.5 * d_data->totalAngle ); updateGeometry(); update(); } } /*! \return the total angle \sa setTotalAngle(), setNumTurns(), numTurns() */ double QwtKnob::totalAngle() const { return d_data->totalAngle; } /*! \brief Set the number of turns When numTurns > 1 the knob can be turned several times around its axis - otherwise the total angle is floored to 360°. \sa numTurns(), totalAngle(), setTotalAngle() */ void QwtKnob::setNumTurns( int numTurns ) { numTurns = qMax( numTurns, 1 ); if ( numTurns == 1 && d_data->totalAngle <= 360.0 ) return; const double angle = numTurns * 360.0; if ( angle != d_data->totalAngle ) { d_data->totalAngle = angle; scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 0.5 * d_data->totalAngle ); updateGeometry(); update(); } } /*! \return Number of turns. When the total angle is below 360° numTurns() is ceiled to 1. \sa setNumTurns(), setTotalAngle(), totalAngle() */ int QwtKnob::numTurns() const { return qCeil( d_data->totalAngle / 360.0 ); } /*! Change the scale draw of the knob For changing the labels of the scales, it is necessary to derive from QwtRoundScaleDraw and overload QwtRoundScaleDraw::label(). \sa scaleDraw() */ void QwtKnob::setScaleDraw( QwtRoundScaleDraw *scaleDraw ) { setAbstractScaleDraw( scaleDraw ); setTotalAngle( d_data->totalAngle ); } /*! \return the scale draw of the knob \sa setScaleDraw() */ const QwtRoundScaleDraw *QwtKnob::scaleDraw() const { return static_cast( abstractScaleDraw() ); } /*! \return the scale draw of the knob \sa setScaleDraw() */ QwtRoundScaleDraw *QwtKnob::scaleDraw() { return static_cast( abstractScaleDraw() ); } /*! Calculate the bounding rectangle of the knob without the scale \return Bounding rectangle of the knob \sa knobWidth(), alignment(), QWidget::contentsRect() */ QRect QwtKnob::knobRect() const { const QRect cr = contentsRect(); const int extent = qCeil( scaleDraw()->extent( font() ) ); const int d = extent + d_data->scaleDist; int w = d_data->knobWidth; if ( w <= 0 ) { const int dim = qMin( cr.width(), cr.height() ); w = dim - 2 * ( d ); w = qMax( 0, w ); } QRect r( 0, 0, w, w ); if ( d_data->alignment & Qt::AlignLeft ) { r.moveLeft( cr.left() + d ); } else if ( d_data->alignment & Qt::AlignRight ) { r.moveRight( cr.right() - d ); } else { r.moveCenter( QPoint( cr.center().x(), r.center().y() ) ); } if ( d_data->alignment & Qt::AlignTop ) { r.moveTop( cr.top() + d ); } else if ( d_data->alignment & Qt::AlignBottom ) { r.moveBottom( cr.bottom() - d ); } else { r.moveCenter( QPoint( r.center().x(), cr.center().y() ) ); } return r; } /*! \brief Determine what to do when the user presses a mouse button. \param pos Mouse position \retval True, when pos is inside the circle of the knob. \sa scrolledTo() */ bool QwtKnob::isScrollPosition( const QPoint &pos ) const { const QRect kr = knobRect(); const QRegion region( kr, QRegion::Ellipse ); if ( region.contains( pos ) && ( pos != kr.center() ) ) { const double angle = QLineF( kr.center(), pos ).angle(); const double valueAngle = qwtToDegrees( transform( value() ) ); d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle ); return true; } return false; } /*! \brief Determine the value for a new position of the mouse \param pos Mouse position \return Value for the mouse position \sa isScrollPosition() */ double QwtKnob::scrolledTo( const QPoint &pos ) const { double angle = QLineF( rect().center(), pos ).angle(); angle = qwtNormalizeDegrees( angle - d_data->mouseOffset ); if ( scaleMap().pDist() > 360.0 ) { angle = qwtToDegrees( angle ); const double v = transform( value() ); int numTurns = qFloor( ( v - scaleMap().p1() ) / 360.0 ); double valueAngle = qwtNormalizeDegrees( v ); if ( qAbs( valueAngle - angle ) > 180.0 ) { numTurns += ( angle > valueAngle ) ? -1 : 1; } angle += scaleMap().p1() + numTurns * 360.0; if ( !wrapping() ) { const double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() ); d_data->mouseOffset += ( boundedAngle - angle ); angle = boundedAngle; } } else { angle = qwtToScaleAngle( angle ); const double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() ); if ( !wrapping() ) d_data->mouseOffset += ( boundedAngle - angle ); angle = boundedAngle; } return invTransform( angle ); } /*! Handle QEvent::StyleChange and QEvent::FontChange; \param event Change event */ void QwtKnob::changeEvent( QEvent *event ) { switch( event->type() ) { case QEvent::StyleChange: case QEvent::FontChange: { updateGeometry(); update(); break; } default: break; } } /*! Repaint the knob \param event Paint event */ void QwtKnob::paintEvent( QPaintEvent *event ) { const QRectF knobRect = this->knobRect(); QPainter painter( this ); painter.setClipRegion( event->region() ); QStyleOption opt; opt.init(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.setRenderHint( QPainter::Antialiasing, true ); if ( !knobRect.contains( event->region().boundingRect() ) ) { scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist ); scaleDraw()->moveCenter( knobRect.center() ); scaleDraw()->draw( &painter, palette() ); } drawKnob( &painter, knobRect ); drawMarker( &painter, knobRect, qwtNormalizeDegrees( transform( value() ) ) ); painter.setRenderHint( QPainter::Antialiasing, false ); if ( hasFocus() ) drawFocusIndicator( &painter ); } /*! \brief Draw the knob \param painter painter \param knobRect Bounding rectangle of the knob (without scale) */ void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const { double dim = qMin( knobRect.width(), knobRect.height() ); dim -= d_data->borderWidth * 0.5; QRectF aRect( 0, 0, dim, dim ); aRect.moveCenter( knobRect.center() ); QPen pen( Qt::NoPen ); if ( d_data->borderWidth > 0 ) { QColor c1 = palette().color( QPalette::Light ); QColor c2 = palette().color( QPalette::Dark ); QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 0.3, c1 ); gradient.setColorAt( 0.7, c2 ); gradient.setColorAt( 1.0, c2 ); pen = QPen( gradient, d_data->borderWidth ); } QBrush brush; switch( d_data->knobStyle ) { case QwtKnob::Raised: { double off = 0.3 * knobRect.width(); QRadialGradient gradient( knobRect.center(), knobRect.width(), knobRect.topLeft() + QPointF( off, off ) ); gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) ); gradient.setColorAt( 1.0, palette().color( QPalette::Button ) ); brush = QBrush( gradient ); break; } case QwtKnob::Styled: { QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3, knobRect.center().y() - knobRect.height() / 2, knobRect.width() * 1.3, knobRect.center().x(), knobRect.center().y() - knobRect.height() / 2); const QColor c = palette().color( QPalette::Button ); gradient.setColorAt(0, c.lighter(110)); gradient.setColorAt(qreal(0.5), c); gradient.setColorAt(qreal(0.501), c.darker(102)); gradient.setColorAt(1, c.darker(115)); brush = QBrush( gradient ); break; } case QwtKnob::Sunken: { QLinearGradient gradient( knobRect.topLeft(), knobRect.bottomRight() ); gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) ); gradient.setColorAt( 0.5, palette().color( QPalette::Button ) ); gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) ); brush = QBrush( gradient ); break; } case QwtKnob::Flat: default: brush = palette().brush( QPalette::Button ); } painter->setPen( pen ); painter->setBrush( brush ); painter->drawEllipse( aRect ); } /*! \brief Draw the marker at the knob's front \param painter Painter \param rect Bounding rectangle of the knob without scale \param angle Angle of the marker in degrees ( clockwise, 0 at the 12 o'clock position ) */ void QwtKnob::drawMarker( QPainter *painter, const QRectF &rect, double angle ) const { if ( d_data->markerStyle == NoMarker || !isValid() ) return; const double radians = qwtRadians( angle ); const double sinA = -qFastSin( radians ); const double cosA = qFastCos( radians ); const double xm = rect.center().x(); const double ym = rect.center().y(); const double margin = 4.0; double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin; if ( radius < 1.0 ) radius = 1.0; int markerSize = d_data->markerSize; if ( markerSize <= 0 ) markerSize = qRound( 0.4 * radius ); switch ( d_data->markerStyle ) { case Notch: case Nub: { const double dotWidth = qMin( double( markerSize ), radius); const double dotCenterDist = radius - 0.5 * dotWidth; if ( dotCenterDist > 0.0 ) { const QPointF center( xm - sinA * dotCenterDist, ym - cosA * dotCenterDist ); QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth ); ellipse.moveCenter( center ); QColor c1 = palette().color( QPalette::Light ); QColor c2 = palette().color( QPalette::Mid ); if ( d_data->markerStyle == Notch ) qSwap( c1, c2 ); QLinearGradient gradient( ellipse.topLeft(), ellipse.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 1.0, c2 ); painter->setPen( Qt::NoPen ); painter->setBrush( gradient ); painter->drawEllipse( ellipse ); } break; } case Dot: { const double dotWidth = qMin( double( markerSize ), radius); const double dotCenterDist = radius - 0.5 * dotWidth; if ( dotCenterDist > 0.0 ) { const QPointF center( xm - sinA * dotCenterDist, ym - cosA * dotCenterDist ); QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth ); ellipse.moveCenter( center ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().color( QPalette::ButtonText ) ); painter->drawEllipse( ellipse ); } break; } case Tick: { const double rb = qMax( radius - markerSize, 1.0 ); const double re = radius; const QLineF line( xm - sinA * rb, ym - cosA * rb, xm - sinA * re, ym - cosA * re ); QPen pen( palette().color( QPalette::ButtonText ), 0 ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->drawLine ( line ); break; } case Triangle: { const double rb = qMax( radius - markerSize, 1.0 ); const double re = radius; painter->translate( rect.center() ); painter->rotate( angle - 90.0 ); QPolygonF polygon; polygon += QPointF( re, 0.0 ); polygon += QPointF( rb, 0.5 * ( re - rb ) ); polygon += QPointF( rb, -0.5 * ( re - rb ) ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().color( QPalette::ButtonText ) ); painter->drawPolygon( polygon ); painter->resetTransform(); break; } default: break; } } /*! Draw the focus indicator \param painter Painter */ void QwtKnob::drawFocusIndicator( QPainter *painter ) const { const QRect cr = contentsRect(); int w = d_data->knobWidth; if ( w <= 0 ) { w = qMin( cr.width(), cr.height() ); } else { const int extent = qCeil( scaleDraw()->extent( font() ) ); w += 2 * ( extent + d_data->scaleDist ); } QRect focusRect( 0, 0, w, w ); focusRect.moveCenter( cr.center() ); QwtPainter::drawFocusRect( painter, this, focusRect ); } /*! \brief Set the alignment of the knob Similar to a QLabel::alignment() the flags decide how to align the knob inside of contentsRect(). The default setting is Qt::AlignCenter \param alignment Or'd alignment flags \sa alignment(), setKnobWidth(), knobRect() */ void QwtKnob::setAlignment( Qt::Alignment alignment ) { if ( d_data->alignment != alignment ) { d_data->alignment = alignment; update(); } } /*! \return Alignment of the knob inside of contentsRect() \sa setAlignment(), knobWidth(), knobRect() */ Qt::Alignment QwtKnob::alignment() const { return d_data->alignment; } /*! \brief Change the knob's width. Setting a fixed value for the diameter of the knob is helpful for aligning several knobs in a row. \param width New width \sa knobWidth(), setAlignment() \note Modifies the sizePolicy() */ void QwtKnob::setKnobWidth( int width ) { width = qMax( width, 0 ); if ( width != d_data->knobWidth ) { QSizePolicy::Policy policy; if ( width > 0 ) policy = QSizePolicy::Minimum; else policy = QSizePolicy::MinimumExpanding; setSizePolicy( policy, policy ); d_data->knobWidth = width; updateGeometry(); update(); } } //! Return the width of the knob int QwtKnob::knobWidth() const { return d_data->knobWidth; } /*! \brief Set the knob's border width \param borderWidth new border width */ void QwtKnob::setBorderWidth( int borderWidth ) { d_data->borderWidth = qMax( borderWidth, 0 ); updateGeometry(); update(); } //! Return the border width int QwtKnob::borderWidth() const { return d_data->borderWidth; } /*! \brief Set the size of the marker When setting a size <= 0 the marker will automatically scaled to 40% of the radius of the knob. \sa markerSize(), markerStyle() */ void QwtKnob::setMarkerSize( int size ) { if ( d_data->markerSize != size ) { d_data->markerSize = size; update(); } } /*! \return Marker size \sa setMarkerSize() */ int QwtKnob::markerSize() const { return d_data->markerSize; } /*! \return sizeHint() */ QSize QwtKnob::sizeHint() const { const QSize hint = qwtKnobSizeHint( this, 50 ); return hint.expandedTo( QApplication::globalStrut() ); } /*! \return Minimum size hint \sa sizeHint() */ QSize QwtKnob::minimumSizeHint() const { return qwtKnobSizeHint( this, 20 ); } qsstv_8.2.12/qwt/qwt_slider.h000664 001750 001750 00000006650 12440612574 016143 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SLIDER_H #define QWT_SLIDER_H #include "qwt_global.h" #include "qwt_abstract_slider.h" class QwtScaleDraw; /*! \brief The Slider Widget QwtSlider is a slider widget which operates on an interval of type double. Its position is related to a scale showing the current value. The slider can be customized by having a through, a groove - or both. \image html sliders.png */ class QWT_EXPORT QwtSlider: public QwtAbstractSlider { Q_OBJECT Q_ENUMS( ScalePosition BackgroundStyle ) Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ) Q_PROPERTY( ScalePosition scalePosition READ scalePosition WRITE setScalePosition ) Q_PROPERTY( bool trough READ hasTrough WRITE setTrough ) Q_PROPERTY( bool groove READ hasGroove WRITE setGroove ) Q_PROPERTY( QSize handleSize READ handleSize WRITE setHandleSize ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) Q_PROPERTY( int spacing READ spacing WRITE setSpacing ) public: /*! Position of the scale \sa QwtSlider(), setScalePosition(), setOrientation() */ enum ScalePosition { //! The slider has no scale NoScale, //! The scale is right of a vertical or below a horizontal slider LeadingScale, //! The scale is left of a vertical or above a horizontal slider TrailingScale }; explicit QwtSlider( QWidget *parent = NULL ); explicit QwtSlider( Qt::Orientation, QWidget *parent = NULL ); virtual ~QwtSlider(); void setOrientation( Qt::Orientation ); Qt::Orientation orientation() const; void setScalePosition( ScalePosition ); ScalePosition scalePosition() const; void setTrough( bool ); bool hasTrough() const; void setGroove( bool ); bool hasGroove() const; void setHandleSize( const QSize & ); QSize handleSize() const; void setBorderWidth( int bw ); int borderWidth() const; void setSpacing( int ); int spacing() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; void setScaleDraw( QwtScaleDraw * ); const QwtScaleDraw *scaleDraw() const; void setUpdateInterval( int ); int updateInterval() const; protected: virtual double scrolledTo( const QPoint & ) const; virtual bool isScrollPosition( const QPoint & ) const; virtual void drawSlider ( QPainter *, const QRect & ) const; virtual void drawHandle( QPainter *, const QRect &, int pos ) const; virtual void mousePressEvent( QMouseEvent * ); virtual void mouseReleaseEvent( QMouseEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void paintEvent ( QPaintEvent * ); virtual void changeEvent( QEvent * ); virtual void timerEvent( QTimerEvent * ); virtual void scaleChange(); QRect sliderRect() const; QRect handleRect() const; private: QwtScaleDraw *scaleDraw(); void layoutSlider( bool ); void initSlider( Qt::Orientation ); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_abstract_legend.cpp000664 001750 001750 00000001641 12440612574 020330 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_legend.h" /*! Constructor \param parent Parent widget */ QwtAbstractLegend::QwtAbstractLegend( QWidget *parent ): QFrame( parent ) { } //! Destructor QwtAbstractLegend::~QwtAbstractLegend() { } /*! Return the extent, that is needed for elements to scroll the legend ( usually scrollbars ), \param orientation Orientation \return Extent of the corresponding scroll element */ int QwtAbstractLegend::scrollExtent( Qt::Orientation orientation ) const { Q_UNUSED( orientation ); return 0; } qsstv_8.2.12/qwt/qwt_painter_command.h000664 001750 001750 00000007340 12440612574 020016 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PAINTER_COMMAND_H #define QWT_PAINTER_COMMAND_H #include "qwt_global.h" #include #include #include #include class QPainterPath; /*! QwtPainterCommand represents the attributes of a paint operation how it is used between QPainter and QPaintDevice It is used by QwtGraphic to record and replay paint operations \sa QwtGraphic::commands() */ class QWT_EXPORT QwtPainterCommand { public: //! Type of the paint command enum Type { //! Invalid command Invalid = -1, //! Draw a QPainterPath Path, //! Draw a QPixmap Pixmap, //! Draw a QImage Image, //! QPainter state change State }; //! Attributes how to paint a QPixmap struct PixmapData { QRectF rect; QPixmap pixmap; QRectF subRect; }; //! Attributes how to paint a QImage struct ImageData { QRectF rect; QImage image; QRectF subRect; Qt::ImageConversionFlags flags; }; //! Attributes of a state change struct StateData { QPaintEngine::DirtyFlags flags; QPen pen; QBrush brush; QPointF brushOrigin; QBrush backgroundBrush; Qt::BGMode backgroundMode; QFont font; QMatrix matrix; QTransform transform; Qt::ClipOperation clipOperation; QRegion clipRegion; QPainterPath clipPath; bool isClipEnabled; QPainter::RenderHints renderHints; QPainter::CompositionMode compositionMode; qreal opacity; }; QwtPainterCommand(); QwtPainterCommand(const QwtPainterCommand &); QwtPainterCommand( const QPainterPath & ); QwtPainterCommand( const QRectF &rect, const QPixmap &, const QRectF& subRect ); QwtPainterCommand( const QRectF &rect, const QImage &, const QRectF& subRect, Qt::ImageConversionFlags ); QwtPainterCommand( const QPaintEngineState & ); ~QwtPainterCommand(); QwtPainterCommand &operator=(const QwtPainterCommand & ); Type type() const; QPainterPath *path(); const QPainterPath *path() const; PixmapData* pixmapData(); const PixmapData* pixmapData() const; ImageData* imageData(); const ImageData* imageData() const; StateData* stateData(); const StateData* stateData() const; private: void copy( const QwtPainterCommand & ); void reset(); Type d_type; union { QPainterPath *d_path; PixmapData *d_pixmapData; ImageData *d_imageData; StateData *d_stateData; }; }; //! \return Type of the command inline QwtPainterCommand::Type QwtPainterCommand::type() const { return d_type; } //! \return Painter path to be painted inline const QPainterPath *QwtPainterCommand::path() const { return d_path; } //! \return Attributes how to paint a QPixmap inline const QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData() const { return d_pixmapData; } //! \return Attributes how to paint a QImage inline const QwtPainterCommand::ImageData * QwtPainterCommand::imageData() const { return d_imageData; } //! \return Attributes of a state change inline const QwtPainterCommand::StateData * QwtPainterCommand::stateData() const { return d_stateData; } #endif qsstv_8.2.12/qwt/qwt_abstract_legend.h000664 001750 001750 00000003763 12440612574 020004 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_LEGEND_H #define QWT_ABSTRACT_LEGEND_H #include "qwt_global.h" #include "qwt_legend_data.h" #include #include class QVariant; /*! \brief Abstract base class for legend widgets Legends, that need to be under control of the QwtPlot layout system need to be derived from QwtAbstractLegend. \note Other type of legends can be implemented by connecting to the QwtPlot::legendDataChanged() signal. But as these legends are unknown to the plot layout system the layout code ( on screen and for QwtPlotRenderer ) need to be organized in application code. \sa QwtLegend */ class QWT_EXPORT QwtAbstractLegend : public QFrame { Q_OBJECT public: explicit QwtAbstractLegend( QWidget *parent = NULL ); virtual ~QwtAbstractLegend(); /*! Render the legend into a given rectangle. \param painter Painter \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \sa renderLegend() is used by QwtPlotRenderer */ virtual void renderLegend( QPainter *painter, const QRectF &rect, bool fillBackground ) const = 0; //! \return True, when no plot item is inserted virtual bool isEmpty() const = 0; virtual int scrollExtent( Qt::Orientation ) const; public Q_SLOTS: /*! \brief Update the entries for a plot item \param itemInfo Info about an item \param data List of legend entry attributes for the item */ virtual void updateLegend( const QVariant &itemInfo, const QList &data ) = 0; }; #endif qsstv_8.2.12/qwt/qwt_knob.h000664 001750 001750 00000011240 12440612574 015601 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_KNOB_H #define QWT_KNOB_H #include "qwt_global.h" #include "qwt_abstract_slider.h" class QwtRoundScaleDraw; /*! \brief The Knob Widget The QwtKnob widget imitates look and behavior of a volume knob on a radio. It looks similar to QDial - not to QwtDial. The value range of a knob might be divided into several turns. The layout of the knob depends on the knobWidth(). - width > 0 The diameter of the knob is fixed and the knob is aligned according to the alignment() flags inside of the contentsRect(). - width <= 0 The knob is extended to the minimum of width/height of the contentsRect() and aligned in the other direction according to alignment(). Setting a fixed knobWidth() is helpful to align several knobs with different scale labels. \image html knob.png */ class QWT_EXPORT QwtKnob: public QwtAbstractSlider { Q_OBJECT Q_ENUMS ( KnobStyle MarkerStyle ) Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle ) Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth ) Q_PROPERTY( Qt::Alignment alignment READ alignment WRITE setAlignment ) Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle ) Q_PROPERTY( int numTurns READ numTurns WRITE setNumTurns ) Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle ) Q_PROPERTY( int markerSize READ markerSize WRITE setMarkerSize ) Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth ) public: /*! \brief Style of the knob surface Depending on the KnobStyle the surface of the knob is filled from the brushes of the widget palette(). \sa setKnobStyle(), knobStyle() */ enum KnobStyle { //! Fill the knob with a brush from QPalette::Button. Flat, //! Build a gradient from QPalette::Midlight and QPalette::Button Raised, /*! Build a gradient from QPalette::Midlight, QPalette::Button and QPalette::Midlight */ Sunken, /*! Build a radial gradient from QPalette::Button like it is used for QDial in various Qt styles. */ Styled }; /*! \brief Marker type The marker indicates the current value on the knob The default setting is a Notch marker. \sa setMarkerStyle(), setMarkerSize() */ enum MarkerStyle { //! Don't paint any marker NoMarker = -1, //! Paint a single tick in QPalette::ButtonText color Tick, //! Paint a triangle in QPalette::ButtonText color Triangle, //! Paint a circle in QPalette::ButtonText color Dot, /*! Draw a raised ellipse with a gradient build from QPalette::Light and QPalette::Mid */ Nub, /*! Draw a sunken ellipse with a gradient build from QPalette::Light and QPalette::Mid */ Notch }; explicit QwtKnob( QWidget* parent = NULL ); virtual ~QwtKnob(); void setAlignment( Qt::Alignment ); Qt::Alignment alignment() const; void setKnobWidth( int ); int knobWidth() const; void setNumTurns( int ); int numTurns() const; void setTotalAngle ( double angle ); double totalAngle() const; void setKnobStyle( KnobStyle ); KnobStyle knobStyle() const; void setBorderWidth( int bw ); int borderWidth() const; void setMarkerStyle( MarkerStyle ); MarkerStyle markerStyle() const; void setMarkerSize( int ); int markerSize() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; void setScaleDraw( QwtRoundScaleDraw * ); const QwtRoundScaleDraw *scaleDraw() const; QwtRoundScaleDraw *scaleDraw(); QRect knobRect() const; protected: virtual void paintEvent( QPaintEvent * ); virtual void changeEvent( QEvent * ); virtual void drawKnob( QPainter *, const QRectF & ) const; virtual void drawFocusIndicator( QPainter * ) const; virtual void drawMarker( QPainter *, const QRectF &, double arc ) const; virtual double scrolledTo( const QPoint & ) const; virtual bool isScrollPosition( const QPoint & ) const; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_spline.h000664 001750 001750 00000004601 12440612574 016145 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SPLINE_H #define QWT_SPLINE_H #include "qwt_global.h" #include #include /*! \brief A class for spline interpolation The QwtSpline class is used for cubical spline interpolation. Two types of splines, natural and periodic, are supported. \par Usage:
  1. First call setPoints() to determine the spline coefficients for a tabulated function y(x).
  2. After the coefficients have been set up, the interpolated function value for an argument x can be determined by calling QwtSpline::value().
\par Example: \code #include QPolygonF interpolate(const QPolygonF& points, int numValues) { QwtSpline spline; if ( !spline.setPoints(points) ) return points; QPolygonF interpolatedPoints(numValues); const double delta = (points[numPoints - 1].x() - points[0].x()) / (points.size() - 1); for(i = 0; i < points.size(); i++) / interpolate { const double x = points[0].x() + i * delta; interpolatedPoints[i].setX(x); interpolatedPoints[i].setY(spline.value(x)); } return interpolatedPoints; } \endcode */ class QWT_EXPORT QwtSpline { public: //! Spline type enum SplineType { //! A natural spline Natural, //! A periodic spline Periodic }; QwtSpline(); QwtSpline( const QwtSpline & ); ~QwtSpline(); QwtSpline &operator=( const QwtSpline & ); void setSplineType( SplineType ); SplineType splineType() const; bool setPoints( const QPolygonF& points ); QPolygonF points() const; void reset(); bool isValid() const; double value( double x ) const; const QVector &coefficientsA() const; const QVector &coefficientsB() const; const QVector &coefficientsC() const; protected: bool buildNaturalSpline( const QPolygonF & ); bool buildPeriodicSpline( const QPolygonF & ); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_abstract_scale.cpp000664 001750 001750 00000024304 12440612574 020162 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_scale.h" #include "qwt_scale_engine.h" #include "qwt_scale_draw.h" #include "qwt_scale_div.h" #include "qwt_scale_map.h" #include "qwt_interval.h" class QwtAbstractScale::PrivateData { public: PrivateData(): maxMajor( 5 ), maxMinor( 3 ), stepSize( 0.0 ) { scaleEngine = new QwtLinearScaleEngine(); scaleDraw = new QwtScaleDraw(); } ~PrivateData() { delete scaleEngine; delete scaleDraw; } QwtScaleEngine *scaleEngine; QwtAbstractScaleDraw *scaleDraw; int maxMajor; int maxMinor; double stepSize; }; /*! Constructor \param parent Parent widget Creates a default QwtScaleDraw and a QwtLinearScaleEngine. The initial scale boundaries are set to [ 0.0, 100.0 ] The scaleStepSize() is initialized to 0.0, scaleMaxMajor() to 5 and scaleMaxMajor to 3. */ QwtAbstractScale::QwtAbstractScale( QWidget *parent ): QWidget( parent ) { d_data = new PrivateData; rescale( 0.0, 100.0, d_data->stepSize ); } //! Destructor QwtAbstractScale::~QwtAbstractScale() { delete d_data; } /*! Set the lower bound of the scale \param value Lower bound \sa lowerBound(), setScale(), setUpperBound() \note For inverted scales the lower bound is greater than the upper bound */ void QwtAbstractScale::setLowerBound( double value ) { setScale( value, upperBound() ); } /*! \return Lower bound of the scale \sa setLowerBound(), setScale(), upperBound() */ double QwtAbstractScale::lowerBound() const { return d_data->scaleDraw->scaleDiv().lowerBound(); } /*! Set the upper bound of the scale \param value Upper bound \sa upperBound(), setScale(), setLowerBound() \note For inverted scales the lower bound is greater than the upper bound */ void QwtAbstractScale::setUpperBound( double value ) { setScale( lowerBound(), value ); } /*! \return Upper bound of the scale \sa setUpperBound(), setScale(), lowerBound() */ double QwtAbstractScale::upperBound() const { return d_data->scaleDraw->scaleDiv().upperBound(); } /*! \brief Specify a scale. Define a scale by an interval The ticks are calculated using scaleMaxMinor(), scaleMaxMajor() and scaleStepSize(). \param lowerBound lower limit of the scale interval \param upperBound upper limit of the scale interval \note For inverted scales the lower bound is greater than the upper bound */ void QwtAbstractScale::setScale( double lowerBound, double upperBound ) { rescale( lowerBound, upperBound, d_data->stepSize ); } /*! \brief Specify a scale. Define a scale by an interval The ticks are calculated using scaleMaxMinor(), scaleMaxMajor() and scaleStepSize(). \param interval Interval */ void QwtAbstractScale::setScale( const QwtInterval &interval ) { setScale( interval.minValue(), interval.maxValue() ); } /*! \brief Specify a scale. scaleMaxMinor(), scaleMaxMajor() and scaleStepSize() and have no effect. \param scaleDiv Scale division \sa setAutoScale() */ void QwtAbstractScale::setScale( const QwtScaleDiv &scaleDiv ) { if ( scaleDiv != d_data->scaleDraw->scaleDiv() ) { #if 1 if ( d_data->scaleEngine ) { d_data->scaleDraw->setTransformation( d_data->scaleEngine->transformation() ); } #endif d_data->scaleDraw->setScaleDiv( scaleDiv ); scaleChange(); } } /*! \brief Set the maximum number of major tick intervals. The scale's major ticks are calculated automatically such that the number of major intervals does not exceed ticks. The default value is 5. \param ticks Maximal number of major ticks. \sa scaleMaxMajor(), setScaleMaxMinor(), setScaleStepSize(), QwtScaleEngine::divideInterval() */ void QwtAbstractScale::setScaleMaxMajor( int ticks ) { if ( ticks != d_data->maxMajor ) { d_data->maxMajor = ticks; updateScaleDraw(); } } /*! \return Maximal number of major tick intervals \sa setScaleMaxMajor(), scaleMaxMinor() */ int QwtAbstractScale::scaleMaxMajor() const { return d_data->maxMajor; } /*! \brief Set the maximum number of minor tick intervals The scale's minor ticks are calculated automatically such that the number of minor intervals does not exceed ticks. The default value is 3. \param ticks Maximal number of minor ticks. \sa scaleMaxMajor(), setScaleMaxMinor(), setScaleStepSize(), QwtScaleEngine::divideInterval() */ void QwtAbstractScale::setScaleMaxMinor( int ticks ) { if ( ticks != d_data->maxMinor ) { d_data->maxMinor = ticks; updateScaleDraw(); } } /*! \return Maximal number of minor tick intervals \sa setScaleMaxMinor(), scaleMaxMajor() */ int QwtAbstractScale::scaleMaxMinor() const { return d_data->maxMinor; } /*! \brief Set the step size used for calculating a scale division The step size is hint for calculating the intervals for the major ticks of the scale. A value of 0.0 is interpreted as no hint. \param stepSize Hint for the step size of the scale \sa scaleStepSize(), QwtScaleEngine::divideScale() \note Position and distance between the major ticks also depends on scaleMaxMajor(). */ void QwtAbstractScale::setScaleStepSize( double stepSize ) { if ( stepSize != d_data->stepSize ) { d_data->stepSize = stepSize; updateScaleDraw(); } } /*! \return Hint for the step size of the scale \sa setScaleStepSize(), QwtScaleEngine::divideScale() */ double QwtAbstractScale::scaleStepSize() const { return d_data->stepSize; } /*! \brief Set a scale draw scaleDraw has to be created with new and will be deleted in the destructor or the next call of setAbstractScaleDraw(). \sa abstractScaleDraw() */ void QwtAbstractScale::setAbstractScaleDraw( QwtAbstractScaleDraw *scaleDraw ) { if ( scaleDraw == NULL || scaleDraw == d_data->scaleDraw ) return; if ( d_data->scaleDraw != NULL ) scaleDraw->setScaleDiv( d_data->scaleDraw->scaleDiv() ); delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; } /*! \return Scale draw \sa setAbstractScaleDraw() */ QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() { return d_data->scaleDraw; } /*! \return Scale draw \sa setAbstractScaleDraw() */ const QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() const { return d_data->scaleDraw; } /*! \brief Set a scale engine The scale engine is responsible for calculating the scale division and provides a transformation between scale and widget coordinates. scaleEngine has to be created with new and will be deleted in the destructor or the next call of setScaleEngine. */ void QwtAbstractScale::setScaleEngine( QwtScaleEngine *scaleEngine ) { if ( scaleEngine != NULL && scaleEngine != d_data->scaleEngine ) { delete d_data->scaleEngine; d_data->scaleEngine = scaleEngine; } } /*! \return Scale engine \sa setScaleEngine() */ const QwtScaleEngine *QwtAbstractScale::scaleEngine() const { return d_data->scaleEngine; } /*! \return Scale engine \sa setScaleEngine() */ QwtScaleEngine *QwtAbstractScale::scaleEngine() { return d_data->scaleEngine; } /*! \return Scale boundaries and positions of the ticks The scale division might have been assigned explicitly or calculated implicitly by rescale(). */ const QwtScaleDiv &QwtAbstractScale::scaleDiv() const { return d_data->scaleDraw->scaleDiv(); } /*! \return Map to translate between scale and widget coordinates */ const QwtScaleMap &QwtAbstractScale::scaleMap() const { return d_data->scaleDraw->scaleMap(); } /*! Translate a scale value into a widget coordinate \param value Scale value \return Corresponding widget coordinate for value \sa scaleMap(), invTransform() */ int QwtAbstractScale::transform( double value ) const { return qRound( d_data->scaleDraw->scaleMap().transform( value ) ); } /*! Translate a widget coordinate into a scale value \param value Widget coordinate \return Corresponding scale coordinate for value \sa scaleMap(), transform() */ double QwtAbstractScale::invTransform( int value ) const { return d_data->scaleDraw->scaleMap().invTransform( value ); } /*! \return True, when the scale is increasing in opposite direction to the widget coordinates */ bool QwtAbstractScale::isInverted() const { return d_data->scaleDraw->scaleMap().isInverting(); } /*! \return The boundary with the smaller value \sa maximum(), lowerBound(), upperBound() */ double QwtAbstractScale::minimum() const { return qMin( d_data->scaleDraw->scaleDiv().lowerBound(), d_data->scaleDraw->scaleDiv().upperBound() ); } /*! \return The boundary with the larger value \sa minimum(), lowerBound(), upperBound() */ double QwtAbstractScale::maximum() const { return qMax( d_data->scaleDraw->scaleDiv().lowerBound(), d_data->scaleDraw->scaleDiv().upperBound() ); } //! Notify changed scale void QwtAbstractScale::scaleChange() { } /*! Recalculate the scale division and update the scale. \param lowerBound Lower limit of the scale interval \param upperBound Upper limit of the scale interval \param stepSize Major step size \sa scaleChange() */ void QwtAbstractScale::rescale( double lowerBound, double upperBound, double stepSize ) { const QwtScaleDiv scaleDiv = d_data->scaleEngine->divideScale( lowerBound, upperBound, d_data->maxMajor, d_data->maxMinor, stepSize ); if ( scaleDiv != d_data->scaleDraw->scaleDiv() ) { #if 1 d_data->scaleDraw->setTransformation( d_data->scaleEngine->transformation() ); #endif d_data->scaleDraw->setScaleDiv( scaleDiv ); scaleChange(); } } void QwtAbstractScale::updateScaleDraw() { rescale( d_data->scaleDraw->scaleDiv().lowerBound(), d_data->scaleDraw->scaleDiv().upperBound(), d_data->stepSize ); } qsstv_8.2.12/qwt/qwt_panner.cpp000664 001750 001750 00000030227 12440612574 016474 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_panner.h" #include "qwt_picker.h" #include "qwt_painter.h" #include #include #include #include #include static QVector qwtActivePickers( QWidget *w ) { QVector pickers; QObjectList children = w->children(); for ( int i = 0; i < children.size(); i++ ) { QwtPicker *picker = qobject_cast( children[i] ); if ( picker && picker->isEnabled() ) pickers += picker; } return pickers; } class QwtPanner::PrivateData { public: PrivateData(): button( Qt::LeftButton ), buttonModifiers( Qt::NoModifier ), abortKey( Qt::Key_Escape ), abortKeyModifiers( Qt::NoModifier ), #ifndef QT_NO_CURSOR cursor( NULL ), restoreCursor( NULL ), hasCursor( false ), #endif isEnabled( false ) { orientations = Qt::Vertical | Qt::Horizontal; } ~PrivateData() { #ifndef QT_NO_CURSOR delete cursor; delete restoreCursor; #endif } Qt::MouseButton button; Qt::KeyboardModifiers buttonModifiers; int abortKey; Qt::KeyboardModifiers abortKeyModifiers; QPoint initialPos; QPoint pos; QPixmap pixmap; QBitmap contentsMask; #ifndef QT_NO_CURSOR QCursor *cursor; QCursor *restoreCursor; bool hasCursor; #endif bool isEnabled; Qt::Orientations orientations; }; /*! Creates an panner that is enabled for the left mouse button. \param parent Parent widget to be panned */ QwtPanner::QwtPanner( QWidget *parent ): QWidget( parent ) { d_data = new PrivateData(); setAttribute( Qt::WA_TransparentForMouseEvents ); setAttribute( Qt::WA_NoSystemBackground ); setFocusPolicy( Qt::NoFocus ); hide(); setEnabled( true ); } //! Destructor QwtPanner::~QwtPanner() { delete d_data; } /*! Change the mouse button and modifiers used for panning The defaults are Qt::LeftButton and Qt::NoModifier */ void QwtPanner::setMouseButton( Qt::MouseButton button, Qt::KeyboardModifiers modifiers ) { d_data->button = button; d_data->buttonModifiers = modifiers; } //! Get mouse button and modifiers used for panning void QwtPanner::getMouseButton( Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const { button = d_data->button; modifiers = d_data->buttonModifiers; } /*! Change the abort key The defaults are Qt::Key_Escape and Qt::NoModifiers \param key Key ( See Qt::Keycode ) \param modifiers Keyboard modifiers */ void QwtPanner::setAbortKey( int key, Qt::KeyboardModifiers modifiers ) { d_data->abortKey = key; d_data->abortKeyModifiers = modifiers; } //! Get the abort key and modifiers void QwtPanner::getAbortKey( int &key, Qt::KeyboardModifiers &modifiers ) const { key = d_data->abortKey; modifiers = d_data->abortKeyModifiers; } /*! Change the cursor, that is active while panning The default is the cursor of the parent widget. \param cursor New cursor \sa setCursor() */ #ifndef QT_NO_CURSOR void QwtPanner::setCursor( const QCursor &cursor ) { d_data->cursor = new QCursor( cursor ); } #endif /*! \return Cursor that is active while panning \sa setCursor() */ #ifndef QT_NO_CURSOR const QCursor QwtPanner::cursor() const { if ( d_data->cursor ) return *d_data->cursor; if ( parentWidget() ) return parentWidget()->cursor(); return QCursor(); } #endif /*! \brief En/disable the panner When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPanner::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = parentWidget(); if ( w ) { if ( d_data->isEnabled ) { w->installEventFilter( this ); } else { w->removeEventFilter( this ); hide(); } } } } /*! Set the orientations, where panning is enabled The default value is in both directions: Qt::Horizontal | Qt::Vertical /param o Orientation */ void QwtPanner::setOrientations( Qt::Orientations o ) { d_data->orientations = o; } //! Return the orientation, where paning is enabled Qt::Orientations QwtPanner::orientations() const { return d_data->orientations; } /*! \return True if an orientation is enabled \sa orientations(), setOrientations() */ bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const { return d_data->orientations & o; } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPanner::isEnabled() const { return d_data->isEnabled; } /*! \brief Paint event Repaint the grabbed pixmap on its current position and fill the empty spaces by the background of the parent widget. \param pe Paint event */ void QwtPanner::paintEvent( QPaintEvent *pe ) { int dx = d_data->pos.x() - d_data->initialPos.x(); int dy = d_data->pos.y() - d_data->initialPos.y(); QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() ); r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) ); QPixmap pm( size() ); QwtPainter::fillPixmap( parentWidget(), pm ); QPainter painter( &pm ); if ( !d_data->contentsMask.isNull() ) { QPixmap masked = d_data->pixmap; masked.setMask( d_data->contentsMask ); painter.drawPixmap( r, masked ); } else { painter.drawPixmap( r, d_data->pixmap ); } painter.end(); if ( !d_data->contentsMask.isNull() ) pm.setMask( d_data->contentsMask ); painter.begin( this ); painter.setClipRegion( pe->region() ); painter.drawPixmap( 0, 0, pm ); } /*! \brief Calculate a mask for the contents of the panned widget Sometimes only parts of the contents of a widget should be panned. F.e. for a widget with a styled background with rounded borders only the area inside of the border should be panned. \return An empty bitmap, indicating no mask */ QBitmap QwtPanner::contentsMask() const { return QBitmap(); } /*! Grab the widget into a pixmap. \return Grabbed pixmap */ QPixmap QwtPanner::grab() const { #if QT_VERSION >= 0x050000 return parentWidget()->grab( parentWidget()->rect() ); #else return QPixmap::grabWidget( parentWidget() ); #endif } /*! \brief Event filter When isEnabled() is true mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \return Always false, beside for paint events for the parent widget. \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ bool QwtPanner::eventFilter( QObject *object, QEvent *event ) { if ( object == NULL || object != parentWidget() ) return false; switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( static_cast( event ) ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( static_cast( event ) ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( static_cast( event ) ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( static_cast( event ) ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( static_cast( event ) ); break; } case QEvent::Paint: { if ( isVisible() ) return true; break; } default:; } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if ( ( mouseEvent->button() != d_data->button ) || ( mouseEvent->modifiers() != d_data->buttonModifiers ) ) { return; } QWidget *w = parentWidget(); if ( w == NULL ) return; #ifndef QT_NO_CURSOR showCursor( true ); #endif d_data->initialPos = d_data->pos = mouseEvent->pos(); setGeometry( parentWidget()->rect() ); // We don't want to grab the picker ! QVector pickers = qwtActivePickers( parentWidget() ); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( false ); d_data->pixmap = grab(); d_data->contentsMask = contentsMask(); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( true ); show(); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent() */ void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( !isVisible() ) return; QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); if ( pos != d_data->pos && rect().contains( pos ) ) { d_data->pos = pos; update(); Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { if ( isVisible() ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); d_data->pixmap = QPixmap(); d_data->contentsMask = QBitmap(); d_data->pos = pos; if ( d_data->pos != d_data->initialPos ) { Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } } /*! Handle a key press event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent ) { if ( ( keyEvent->key() == d_data->abortKey ) && ( keyEvent->modifiers() == d_data->abortKeyModifiers ) ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif d_data->pixmap = QPixmap(); } } /*! Handle a key release event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { Q_UNUSED( keyEvent ); } #ifndef QT_NO_CURSOR void QwtPanner::showCursor( bool on ) { if ( on == d_data->hasCursor ) return; QWidget *w = parentWidget(); if ( w == NULL || d_data->cursor == NULL ) return; d_data->hasCursor = on; if ( on ) { if ( w->testAttribute( Qt::WA_SetCursor ) ) { delete d_data->restoreCursor; d_data->restoreCursor = new QCursor( w->cursor() ); } w->setCursor( *d_data->cursor ); } else { if ( d_data->restoreCursor ) { w->setCursor( *d_data->restoreCursor ); delete d_data->restoreCursor; d_data->restoreCursor = NULL; } else w->unsetCursor(); } } #endif qsstv_8.2.12/qwt/qwt_abstract_scale.h000664 001750 001750 00000005533 12440612574 017632 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SCALE_H #define QWT_ABSTRACT_SCALE_H #include "qwt_global.h" #include class QwtScaleEngine; class QwtAbstractScaleDraw; class QwtScaleDiv; class QwtScaleMap; class QwtInterval; /*! \brief An abstract base class for widgets having a scale The scale of an QwtAbstractScale is determined by a QwtScaleDiv definition, that contains the boundaries and the ticks of the scale. The scale is painted using a QwtScaleDraw object. The scale division might be assigned explicitly - but usually it is calculated from the boundaries using a QwtScaleEngine. The scale engine also decides the type of transformation of the scale ( linear, logarithmic ... ). */ class QWT_EXPORT QwtAbstractScale: public QWidget { Q_OBJECT Q_PROPERTY( double lowerBound READ lowerBound WRITE setLowerBound ) Q_PROPERTY( double upperBound READ upperBound WRITE setUpperBound ) Q_PROPERTY( int scaleMaxMajor READ scaleMaxMajor WRITE setScaleMaxMajor ) Q_PROPERTY( int scaleMaxMinor READ scaleMaxMinor WRITE setScaleMaxMinor ) Q_PROPERTY( double scaleStepSize READ scaleStepSize WRITE setScaleStepSize ) public: QwtAbstractScale( QWidget *parent = NULL ); virtual ~QwtAbstractScale(); void setScale( double lowerBound, double upperBound ); void setScale( const QwtInterval & ); void setScale( const QwtScaleDiv & ); const QwtScaleDiv& scaleDiv() const; void setLowerBound( double value ); double lowerBound() const; void setUpperBound( double value ); double upperBound() const; void setScaleStepSize( double stepSize ); double scaleStepSize() const; void setScaleMaxMajor( int ticks ); int scaleMaxMinor() const; void setScaleMaxMinor( int ticks ); int scaleMaxMajor() const; void setScaleEngine( QwtScaleEngine * ); const QwtScaleEngine *scaleEngine() const; QwtScaleEngine *scaleEngine(); int transform( double ) const; double invTransform( int ) const; bool isInverted() const; double minimum() const; double maximum() const; const QwtScaleMap &scaleMap() const; protected: void rescale( double lowerBound, double upperBound, double stepSize ); void setAbstractScaleDraw( QwtAbstractScaleDraw * ); const QwtAbstractScaleDraw *abstractScaleDraw() const; QwtAbstractScaleDraw *abstractScaleDraw(); virtual void scaleChange(); private: void updateScaleDraw(); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_legend.h000664 001750 001750 00000006562 12440612574 016121 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_H #define QWT_LEGEND_H #include "qwt_global.h" #include "qwt_abstract_legend.h" #include class QScrollBar; /*! \brief The legend widget The QwtLegend widget is a tabular arrangement of legend items. Legend items might be any type of widget, but in general they will be a QwtLegendLabel. \sa QwtLegendLabel, QwtPlotItem, QwtPlot */ class QWT_EXPORT QwtLegend : public QwtAbstractLegend { Q_OBJECT public: explicit QwtLegend( QWidget *parent = NULL ); virtual ~QwtLegend(); void setMaxColumns( uint numColums ); uint maxColumns() const; void setDefaultItemMode( QwtLegendData::Mode ); QwtLegendData::Mode defaultItemMode() const; QWidget *contentsWidget(); const QWidget *contentsWidget() const; QWidget *legendWidget( const QVariant & ) const; QList legendWidgets( const QVariant & ) const; QVariant itemInfo( const QWidget * ) const; virtual bool eventFilter( QObject *, QEvent * ); virtual QSize sizeHint() const; virtual int heightForWidth( int w ) const; QScrollBar *horizontalScrollBar() const; QScrollBar *verticalScrollBar() const; virtual void renderLegend( QPainter *, const QRectF &, bool fillBackground ) const; virtual void renderItem( QPainter *, const QWidget *, const QRectF &, bool fillBackground ) const; virtual bool isEmpty() const; virtual int scrollExtent( Qt::Orientation ) const; Q_SIGNALS: /*! A signal which is emitted when the user has clicked on a legend label, which is in QwtLegendData::Clickable mode. \param itemInfo Info for the item item of the selected legend item \param index Index of the legend label in the list of widgets that are associated with the plot item \note clicks are disabled as default \sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo() */ void clicked( const QVariant &itemInfo, int index ); /*! A signal which is emitted when the user has clicked on a legend label, which is in QwtLegendData::Checkable mode \param itemInfo Info for the item of the selected legend label \param index Index of the legend label in the list of widgets that are associated with the plot item \param on True when the legend label is checked \note clicks are disabled as default \sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo() */ void checked( const QVariant &itemInfo, bool on, int index ); public Q_SLOTS: virtual void updateLegend( const QVariant &, const QList & ); protected Q_SLOTS: void itemClicked(); void itemChecked( bool ); protected: virtual QWidget *createWidget( const QwtLegendData & ) const; virtual void updateWidget( QWidget *widget, const QwtLegendData &data ); private: void updateTabOrder(); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_symbol.h000664 001750 001750 00000014107 12440612574 016162 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_SYMBOL_H #define QWT_SYMBOL_H #include "qwt_global.h" #include class QPainter; class QRect; class QSize; class QBrush; class QPen; class QColor; class QPointF; class QPolygonF; class QPainterPath; class QPixmap; class QByteArray; class QwtGraphic; //! A class for drawing symbols class QWT_EXPORT QwtSymbol { public: /*! Symbol Style \sa setStyle(), style() */ enum Style { //! No Style. The symbol cannot be drawn. NoSymbol = -1, //! Ellipse or circle Ellipse, //! Rectangle Rect, //! Diamond Diamond, //! Triangle pointing upwards Triangle, //! Triangle pointing downwards DTriangle, //! Triangle pointing upwards UTriangle, //! Triangle pointing left LTriangle, //! Triangle pointing right RTriangle, //! Cross (+) Cross, //! Diagonal cross (X) XCross, //! Horizontal line HLine, //! Vertical line VLine, //! X combined with + Star1, //! Six-pointed star Star2, //! Hexagon Hexagon, /*! The symbol is represented by a painter path, where the origin ( 0, 0 ) of the path coordinate system is mapped to the position of the symbol. \sa setPath(), path() */ Path, /*! The symbol is represented by a pixmap. The pixmap is centered or aligned to its pin point. \sa setPinPoint() */ Pixmap, /*! The symbol is represented by a graphic. The graphic is centered or aligned to its pin point. \sa setPinPoint() */ Graphic, /*! The symbol is represented by a SVG graphic. The graphic is centered or aligned to its pin point. \sa setPinPoint() */ SvgDocument, /*! Styles >= QwtSymbol::UserSymbol are reserved for derived classes of QwtSymbol that overload drawSymbols() with additional application specific symbol types. */ UserStyle = 1000 }; /*! Depending on the render engine and the complexity of the symbol shape it might be faster to render the symbol to a pixmap and to paint this pixmap. F.e. the raster paint engine is a pure software renderer where in cache mode a draw operation usually ends in raster operation with the the backing store, that are usually faster, than the algorithms for rendering polygons. But the opposite can be expected for graphic pipelines that can make use of hardware acceleration. The default setting is AutoCache \sa setCachePolicy(), cachePolicy() \note The policy has no effect, when the symbol is painted to a vector graphics format ( PDF, SVG ). \warning Since Qt 4.8 raster is the default backend on X11 */ enum CachePolicy { //! Don't use a pixmap cache NoCache, //! Always use a pixmap cache Cache, /*! Use a cache when one of the following conditions is true: - The symbol is rendered with the software renderer ( QPaintEngine::Raster ) */ AutoCache }; public: QwtSymbol( Style = NoSymbol ); QwtSymbol( Style, const QBrush &, const QPen &, const QSize & ); QwtSymbol( const QPainterPath &, const QBrush &, const QPen & ); virtual ~QwtSymbol(); void setCachePolicy( CachePolicy ); CachePolicy cachePolicy() const; void setSize( const QSize & ); void setSize( int width, int height = -1 ); const QSize& size() const; void setPinPoint( const QPointF &pos, bool enable = true ); QPointF pinPoint() const; void setPinPointEnabled( bool ); bool isPinPointEnabled() const; virtual void setColor( const QColor & ); void setBrush( const QBrush& b ); const QBrush& brush() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen& pen() const; void setStyle( Style ); Style style() const; void setPath( const QPainterPath & ); const QPainterPath &path() const; void setPixmap( const QPixmap & ); const QPixmap &pixmap() const; void setGraphic( const QwtGraphic & ); const QwtGraphic &graphic() const; #ifndef QWT_NO_SVG void setSvgDocument( const QByteArray & ); #endif void drawSymbol( QPainter *, const QRectF & ) const; void drawSymbol( QPainter *, const QPointF & ) const; void drawSymbols( QPainter *, const QPolygonF & ) const; void drawSymbols( QPainter *, const QPointF *, int numPoints ) const; virtual QRect boundingRect() const; void invalidateCache(); protected: virtual void renderSymbols( QPainter *, const QPointF *, int numPoints ) const; private: // Disabled copy constructor and operator= QwtSymbol( const QwtSymbol & ); QwtSymbol &operator=( const QwtSymbol & ); class PrivateData; PrivateData *d_data; }; /*! \brief Draw the symbol at a specified position \param painter Painter \param pos Position of the symbol in screen coordinates */ inline void QwtSymbol::drawSymbol( QPainter *painter, const QPointF &pos ) const { drawSymbols( painter, &pos, 1 ); } /*! \brief Draw symbols at the specified points \param painter Painter \param points Positions of the symbols in screen coordinates */ inline void QwtSymbol::drawSymbols( QPainter *painter, const QPolygonF &points ) const { drawSymbols( painter, points.data(), points.size() ); } #endif qsstv_8.2.12/qwt/qwt_abstract_scale_draw.cpp000664 001750 001750 00000023057 12440612574 021203 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_scale_draw.h" #include "qwt_math.h" #include "qwt_text.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include #include #include #include class QwtAbstractScaleDraw::PrivateData { public: PrivateData(): spacing( 4.0 ), penWidth( 0 ), minExtent( 0.0 ) { components = QwtAbstractScaleDraw::Backbone | QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels; tickLength[QwtScaleDiv::MinorTick] = 4.0; tickLength[QwtScaleDiv::MediumTick] = 6.0; tickLength[QwtScaleDiv::MajorTick] = 8.0; } ScaleComponents components; QwtScaleMap map; QwtScaleDiv scaleDiv; double spacing; double tickLength[QwtScaleDiv::NTickTypes]; int penWidth; double minExtent; QMap labelCache; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The spacing (distance between ticks and labels) is set to 4, the tick lengths are set to 4,6 and 8 pixels */ QwtAbstractScaleDraw::QwtAbstractScaleDraw() { d_data = new QwtAbstractScaleDraw::PrivateData; } //! Destructor QwtAbstractScaleDraw::~QwtAbstractScaleDraw() { delete d_data; } /*! En/Disable a component of the scale \param component Scale component \param enable On/Off \sa hasComponent() */ void QwtAbstractScaleDraw::enableComponent( ScaleComponent component, bool enable ) { if ( enable ) d_data->components |= component; else d_data->components &= ~component; } /*! Check if a component is enabled \param component Component type \return true, when component is enabled \sa enableComponent() */ bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const { return ( d_data->components & component ); } /*! Change the scale division \param scaleDiv New scale division */ void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &scaleDiv ) { d_data->scaleDiv = scaleDiv; d_data->map.setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() ); d_data->labelCache.clear(); } /*! Change the transformation of the scale \param transformation New scale transformation */ void QwtAbstractScaleDraw::setTransformation( QwtTransform *transformation ) { d_data->map.setTransformation( transformation ); } //! \return Map how to translate between scale and pixel values const QwtScaleMap &QwtAbstractScaleDraw::scaleMap() const { return d_data->map; } //! \return Map how to translate between scale and pixel values QwtScaleMap &QwtAbstractScaleDraw::scaleMap() { return d_data->map; } //! \return scale division const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const { return d_data->scaleDiv; } /*! \brief Specify the width of the scale pen \param width Pen width \sa penWidth() */ void QwtAbstractScaleDraw::setPenWidth( int width ) { if ( width < 0 ) width = 0; if ( width != d_data->penWidth ) d_data->penWidth = width; } /*! \return Scale pen width \sa setPenWidth() */ int QwtAbstractScaleDraw::penWidth() const { return d_data->penWidth; } /*! \brief Draw the scale \param painter The painter \param palette Palette, text color is used for the labels, foreground color for ticks and backbone */ void QwtAbstractScaleDraw::draw( QPainter *painter, const QPalette& palette ) const { painter->save(); QPen pen = painter->pen(); pen.setWidth( d_data->penWidth ); pen.setCosmetic( false ); painter->setPen( pen ); if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { painter->save(); painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style const QList &majorTicks = d_data->scaleDiv.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < majorTicks.count(); i++ ) { const double v = majorTicks[i]; if ( d_data->scaleDiv.contains( v ) ) drawLabel( painter, v ); } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const QList &ticks = d_data->scaleDiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( d_data->scaleDiv.contains( v ) ) drawTick( painter, v, d_data->tickLength[tickType] ); } } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); drawBackbone( painter ); painter->restore(); } painter->restore(); } /*! \brief Set the spacing between tick and labels The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \param spacing Spacing \sa spacing() */ void QwtAbstractScaleDraw::setSpacing( double spacing ) { if ( spacing < 0 ) spacing = 0; d_data->spacing = spacing; } /*! \brief Get the spacing The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \return Spacing \sa setSpacing() */ double QwtAbstractScaleDraw::spacing() const { return d_data->spacing; } /*! \brief Set a minimum for the extent The extent is calculated from the components of the scale draw. In situations, where the labels are changing and the layout depends on the extent (f.e scrolling a scale), setting an upper limit as minimum extent will avoid jumps of the layout. \param minExtent Minimum extent \sa extent(), minimumExtent() */ void QwtAbstractScaleDraw::setMinimumExtent( double minExtent ) { if ( minExtent < 0.0 ) minExtent = 0.0; d_data->minExtent = minExtent; } /*! Get the minimum extent \return Minimum extent \sa extent(), setMinimumExtent() */ double QwtAbstractScaleDraw::minimumExtent() const { return d_data->minExtent; } /*! Set the length of the ticks \param tickType Tick type \param length New length \warning the length is limited to [0..1000] */ void QwtAbstractScaleDraw::setTickLength( QwtScaleDiv::TickType tickType, double length ) { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return; } if ( length < 0.0 ) length = 0.0; const double maxTickLen = 1000.0; if ( length > maxTickLen ) length = maxTickLen; d_data->tickLength[tickType] = length; } /*! \return Length of the ticks \sa setTickLength(), maxTickLength() */ double QwtAbstractScaleDraw::tickLength( QwtScaleDiv::TickType tickType ) const { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return 0; } return d_data->tickLength[tickType]; } /*! \return Length of the longest tick Useful for layout calculations \sa tickLength(), setTickLength() */ double QwtAbstractScaleDraw::maxTickLength() const { double length = 0.0; for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) length = qMax( length, d_data->tickLength[i] ); return length; } /*! \brief Convert a value into its representing label The value is converted to a plain text using QLocale().toString(value). This method is often overloaded by applications to have individual labels. \param value Value \return Label string. */ QwtText QwtAbstractScaleDraw::label( double value ) const { if ( qFuzzyCompare( value + 1.0, 1.0 ) ) value = 0.0; return QLocale().toString( value ); } /*! \brief Convert a value into its representing label and cache it. The conversion between value and label is called very often in the layout and painting code. Unfortunately the calculation of the label sizes might be slow (really slow for rich text in Qt4), so it's necessary to cache the labels. \param font Font \param value Value \return Tick label */ const QwtText &QwtAbstractScaleDraw::tickLabel( const QFont &font, double value ) const { QMap::const_iterator it = d_data->labelCache.find( value ); if ( it == d_data->labelCache.end() ) { QwtText lbl = label( value ); lbl.setRenderFlags( 0 ); lbl.setLayoutAttribute( QwtText::MinimumLayout ); ( void )lbl.textSize( font ); // initialize the internal cache it = d_data->labelCache.insert( value, lbl ); } return ( *it ); } /*! Invalidate the cache used by tickLabel() The cache is invalidated, when a new QwtScaleDiv is set. If the labels need to be changed. while the same QwtScaleDiv is set, invalidateCache() needs to be called manually. */ void QwtAbstractScaleDraw::invalidateCache() { d_data->labelCache.clear(); } qsstv_8.2.12/qwt/qwt_legend.cpp000664 001750 001750 00000050734 12440612574 016454 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend.h" #include "qwt_legend_label.h" #include "qwt_dyngrid_layout.h" #include "qwt_math.h" #include "qwt_plot_item.h" #include "qwt_painter.h" #include #include #include #include #include #include class QwtLegendMap { public: inline bool isEmpty() const { return d_entries.isEmpty(); } void insert( const QVariant &, const QList & ); void remove( const QVariant & ); void removeWidget( const QWidget * ); QList legendWidgets( const QVariant & ) const; QVariant itemInfo( const QWidget * ) const; private: // we don't know anything about itemInfo and therefore don't have // any key that can be used for a map or hashtab. // But a simple linear list is o.k. here, as we will never have // more than a few entries. class Entry { public: QVariant itemInfo; QList widgets; }; QList< Entry > d_entries; }; void QwtLegendMap::insert( const QVariant &itemInfo, const QList &widgets ) { for ( int i = 0; i < d_entries.size(); i++ ) { Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) { entry.widgets = widgets; return; } } Entry newEntry; newEntry.itemInfo = itemInfo; newEntry.widgets = widgets; d_entries += newEntry; } void QwtLegendMap::remove( const QVariant &itemInfo ) { for ( int i = 0; i < d_entries.size(); i++ ) { Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) { d_entries.removeAt( i ); return; } } } void QwtLegendMap::removeWidget( const QWidget *widget ) { QWidget *w = const_cast( widget ); for ( int i = 0; i < d_entries.size(); i++ ) d_entries[ i ].widgets.removeAll( w ); } QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const { if ( widget != NULL ) { QWidget *w = const_cast( widget ); for ( int i = 0; i < d_entries.size(); i++ ) { const Entry &entry = d_entries[i]; if ( entry.widgets.indexOf( w ) >= 0 ) return entry.itemInfo; } } return QVariant(); } QList QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const { if ( itemInfo.isValid() ) { for ( int i = 0; i < d_entries.size(); i++ ) { const Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) return entry.widgets; } } return QList(); } class QwtLegend::PrivateData { public: PrivateData(): itemMode( QwtLegendData::ReadOnly ), view( NULL ) { } QwtLegendData::Mode itemMode; QwtLegendMap itemMap; class LegendView; LegendView *view; }; class QwtLegend::PrivateData::LegendView: public QScrollArea { public: LegendView( QWidget *parent ): QScrollArea( parent ) { contentsWidget = new QWidget( this ); contentsWidget->setObjectName( "QwtLegendViewContents" ); setWidget( contentsWidget ); setWidgetResizable( false ); viewport()->setObjectName( "QwtLegendViewport" ); // QScrollArea::setWidget internally sets autoFillBackground to true // But we don't want a background. contentsWidget->setAutoFillBackground( false ); viewport()->setAutoFillBackground( false ); } virtual bool event( QEvent *event ) { if ( event->type() == QEvent::PolishRequest ) { setFocusPolicy( Qt::NoFocus ); } if ( event->type() == QEvent::Resize ) { // adjust the size to en/disable the scrollbars // before QScrollArea adjusts the viewport size const QRect cr = contentsRect(); int w = cr.width(); int h = contentsWidget->heightForWidth( cr.width() ); if ( h > w ) { w -= verticalScrollBar()->sizeHint().width(); h = contentsWidget->heightForWidth( w ); } contentsWidget->resize( w, h ); } return QScrollArea::event( event ); } virtual bool viewportEvent( QEvent *event ) { bool ok = QScrollArea::viewportEvent( event ); if ( event->type() == QEvent::Resize ) { layoutContents(); } return ok; } QSize viewportSize( int w, int h ) const { const int sbHeight = horizontalScrollBar()->sizeHint().height(); const int sbWidth = verticalScrollBar()->sizeHint().width(); const int cw = contentsRect().width(); const int ch = contentsRect().height(); int vw = cw; int vh = ch; if ( w > vw ) vh -= sbHeight; if ( h > vh ) { vw -= sbWidth; if ( w > vw && vh == ch ) vh -= sbHeight; } return QSize( vw, vh ); } void layoutContents() { const QwtDynGridLayout *tl = qobject_cast( contentsWidget->layout() ); if ( tl == NULL ) return; const QSize visibleSize = viewport()->contentsRect().size(); const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin(); int w = qMax( visibleSize.width(), minW ); int h = qMax( tl->heightForWidth( w ), visibleSize.height() ); const int vpWidth = viewportSize( w, h ).width(); if ( w > vpWidth ) { w = qMax( vpWidth, minW ); h = qMax( tl->heightForWidth( w ), visibleSize.height() ); } contentsWidget->resize( w, h ); } QWidget *contentsWidget; }; /*! Constructor \param parent Parent widget */ QwtLegend::QwtLegend( QWidget *parent ): QwtAbstractLegend( parent ) { setFrameStyle( NoFrame ); d_data = new QwtLegend::PrivateData; d_data->view = new QwtLegend::PrivateData::LegendView( this ); d_data->view->setObjectName( "QwtLegendView" ); d_data->view->setFrameStyle( NoFrame ); QwtDynGridLayout *gridLayout = new QwtDynGridLayout( d_data->view->contentsWidget ); gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop ); d_data->view->contentsWidget->installEventFilter( this ); QVBoxLayout *layout = new QVBoxLayout( this ); layout->setContentsMargins( 0, 0, 0, 0 ); layout->addWidget( d_data->view ); } //! Destructor QwtLegend::~QwtLegend() { delete d_data; } /*! \brief Set the maximum number of entries in a row F.e when the maximum is set to 1 all items are aligned vertically. 0 means unlimited \param numColums Maximum number of entries in a row \sa maxColumns(), QwtDynGridLayout::setMaxColumns() */ void QwtLegend::setMaxColumns( uint numColums ) { QwtDynGridLayout *tl = qobject_cast( d_data->view->contentsWidget->layout() ); if ( tl ) tl->setMaxColumns( numColums ); } /*! \return Maximum number of entries in a row \sa setMaxColumns(), QwtDynGridLayout::maxColumns() */ uint QwtLegend::maxColumns() const { uint maxCols = 0; const QwtDynGridLayout *tl = qobject_cast( d_data->view->contentsWidget->layout() ); if ( tl ) maxCols = tl->maxColumns(); return maxCols; } /*! \brief Set the default mode for legend labels Legend labels will be constructed according to the attributes in a QwtLegendData object. When it doesn't contain a value for the QwtLegendData::ModeRole the label will be initialized with the default mode of the legend. \param mode Default item mode \sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData() \note Changing the mode doesn't have any effect on existing labels. */ void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode ) { d_data->itemMode = mode; } /*! \return Default item mode \sa setDefaultItemMode() */ QwtLegendData::Mode QwtLegend::defaultItemMode() const { return d_data->itemMode; } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ QWidget *QwtLegend::contentsWidget() { return d_data->view->contentsWidget; } /*! \return Horizontal scrollbar \sa verticalScrollBar() */ QScrollBar *QwtLegend::horizontalScrollBar() const { return d_data->view->horizontalScrollBar(); } /*! \return Vertical scrollbar \sa horizontalScrollBar() */ QScrollBar *QwtLegend::verticalScrollBar() const { return d_data->view->verticalScrollBar(); } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ const QWidget *QwtLegend::contentsWidget() const { return d_data->view->contentsWidget; } /*! \brief Update the entries for an item \param itemInfo Info for an item \param data List of legend entry attributes for the item */ void QwtLegend::updateLegend( const QVariant &itemInfo, const QList &data ) { QList widgetList = legendWidgets( itemInfo ); if ( widgetList.size() != data.size() ) { QLayout *contentsLayout = d_data->view->contentsWidget->layout(); while ( widgetList.size() > data.size() ) { QWidget *w = widgetList.takeLast(); contentsLayout->removeWidget( w ); // updates might be triggered by signals from the legend widget // itself. So we better don't delete it here. w->hide(); w->deleteLater(); } for ( int i = widgetList.size(); i < data.size(); i++ ) { QWidget *widget = createWidget( data[i] ); if ( contentsLayout ) contentsLayout->addWidget( widget ); widgetList += widget; } if ( widgetList.isEmpty() ) { d_data->itemMap.remove( itemInfo ); } else { d_data->itemMap.insert( itemInfo, widgetList ); } updateTabOrder(); } for ( int i = 0; i < data.size(); i++ ) updateWidget( widgetList[i], data[i] ); } /*! \brief Create a widget to be inserted into the legend The default implementation returns a QwtLegendLabel. \param data Attributes of the legend entry \return Widget representing data on the legend \note updateWidget() will called soon after createWidget() with the same attributes. */ QWidget *QwtLegend::createWidget( const QwtLegendData &data ) const { Q_UNUSED( data ); QwtLegendLabel *label = new QwtLegendLabel(); label->setItemMode( defaultItemMode() ); connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) ); connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) ); return label; } /*! \brief Update the widget \param widget Usually a QwtLegendLabel \param data Attributes to be displayed \sa createWidget() \note When widget is no QwtLegendLabel updateWidget() does nothing. */ void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &data ) { QwtLegendLabel *label = qobject_cast( widget ); if ( label ) { label->setData( data ); if ( !data.value( QwtLegendData::ModeRole ).isValid() ) { // use the default mode, when there is no specific // hint from the legend data label->setItemMode( defaultItemMode() ); } } } void QwtLegend::updateTabOrder() { QLayout *contentsLayout = d_data->view->contentsWidget->layout(); if ( contentsLayout ) { // set tab focus chain QWidget *w = NULL; for ( int i = 0; i < contentsLayout->count(); i++ ) { QLayoutItem *item = contentsLayout->itemAt( i ); if ( w && item->widget() ) QWidget::setTabOrder( w, item->widget() ); w = item->widget(); } } } //! Return a size hint. QSize QwtLegend::sizeHint() const { QSize hint = d_data->view->contentsWidget->sizeHint(); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! \return The preferred height, for a width. \param width Width */ int QwtLegend::heightForWidth( int width ) const { width -= 2 * frameWidth(); int h = d_data->view->contentsWidget->heightForWidth( width ); if ( h >= 0 ) h += 2 * frameWidth(); return h; } /*! Handle QEvent::ChildRemoved andQEvent::LayoutRequest events for the contentsWidget(). \param object Object to be filtered \param event Event \return Forwarded to QwtAbstractLegend::eventFilter() */ bool QwtLegend::eventFilter( QObject *object, QEvent *event ) { if ( object == d_data->view->contentsWidget ) { switch ( event->type() ) { case QEvent::ChildRemoved: { const QChildEvent *ce = static_cast(event); if ( ce->child()->isWidgetType() ) { QWidget *w = static_cast< QWidget * >( ce->child() ); d_data->itemMap.removeWidget( w ); } break; } case QEvent::LayoutRequest: { d_data->view->layoutContents(); if ( parentWidget() && parentWidget()->layout() == NULL ) { /* We want the parent widget ( usually QwtPlot ) to recalculate its layout, when the contentsWidget has changed. But because of the scroll view we have to forward the LayoutRequest event manually. We don't use updateGeometry() because it doesn't post LayoutRequest events when the legend is hidden. But we want the parent widget notified, so it can show/hide the legend depending on its items. */ QApplication::postEvent( parentWidget(), new QEvent( QEvent::LayoutRequest ) ); } break; } default: break; } } return QwtAbstractLegend::eventFilter( object, event ); } /*! Called internally when the legend has been clicked on. Emits a clicked() signal. */ void QwtLegend::itemClicked() { QWidget *w = qobject_cast( sender() ); if ( w ) { const QVariant itemInfo = d_data->itemMap.itemInfo( w ); if ( itemInfo.isValid() ) { const QList widgetList = d_data->itemMap.legendWidgets( itemInfo ); const int index = widgetList.indexOf( w ); if ( index >= 0 ) Q_EMIT clicked( itemInfo, index ); } } } /*! Called internally when the legend has been checked Emits a checked() signal. */ void QwtLegend::itemChecked( bool on ) { QWidget *w = qobject_cast( sender() ); if ( w ) { const QVariant itemInfo = d_data->itemMap.itemInfo( w ); if ( itemInfo.isValid() ) { const QList widgetList = d_data->itemMap.legendWidgets( itemInfo ); const int index = widgetList.indexOf( w ); if ( index >= 0 ) Q_EMIT checked( itemInfo, on, index ); } } } /*! Render the legend into a given rectangle. \param painter Painter \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself */ void QwtLegend::renderLegend( QPainter *painter, const QRectF &rect, bool fillBackground ) const { if ( d_data->itemMap.isEmpty() ) return; if ( fillBackground ) { if ( autoFillBackground() || testAttribute( Qt::WA_StyledBackground ) ) { QwtPainter::drawBackgound( painter, rect, this ); } } const QwtDynGridLayout *legendLayout = qobject_cast( contentsWidget()->layout() ); if ( legendLayout == NULL ) return; int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); QRect layoutRect; layoutRect.setLeft( qCeil( rect.left() ) + left ); layoutRect.setTop( qCeil( rect.top() ) + top ); layoutRect.setRight( qFloor( rect.right() ) - right ); layoutRect.setBottom( qFloor( rect.bottom() ) - bottom ); uint numCols = legendLayout->columnsForWidth( layoutRect.width() ); QList itemRects = legendLayout->layoutItems( layoutRect, numCols ); int index = 0; for ( int i = 0; i < legendLayout->count(); i++ ) { QLayoutItem *item = legendLayout->itemAt( i ); QWidget *w = item->widget(); if ( w ) { painter->save(); painter->setClipRect( itemRects[index] ); renderItem( painter, w, itemRects[index], fillBackground ); index++; painter->restore(); } } } /*! Render a legend entry into a given rectangle. \param painter Painter \param widget Widget representing a legend entry \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \note When widget is not derived from QwtLegendLabel renderItem does nothing beside the background */ void QwtLegend::renderItem( QPainter *painter, const QWidget *widget, const QRectF &rect, bool fillBackground ) const { if ( fillBackground ) { if ( widget->autoFillBackground() || widget->testAttribute( Qt::WA_StyledBackground ) ) { QwtPainter::drawBackgound( painter, rect, widget ); } } const QwtLegendLabel *label = qobject_cast( widget ); if ( label ) { // icon const QwtGraphic &icon = label->data().icon(); const QSizeF sz = icon.defaultSize(); const QRectF iconRect( rect.x() + label->margin(), rect.center().y() - 0.5 * sz.height(), sz.width(), sz.height() ); icon.render( painter, iconRect, Qt::KeepAspectRatio ); // title QRectF titleRect = rect; titleRect.setX( iconRect.right() + 2 * label->spacing() ); painter->setFont( label->font() ); painter->setPen( label->palette().color( QPalette::Text ) ); const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect ); } } /*! \return List of widgets associated to a item \param itemInfo Info about an item \sa legendWidget(), itemInfo(), QwtPlot::itemToInfo() */ QList QwtLegend::legendWidgets( const QVariant &itemInfo ) const { return d_data->itemMap.legendWidgets( itemInfo ); } /*! \return First widget in the list of widgets associated to an item \param itemInfo Info about an item \sa itemInfo(), QwtPlot::itemToInfo() \note Almost all types of items have only one widget */ QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const { const QList list = d_data->itemMap.legendWidgets( itemInfo ); if ( list.isEmpty() ) return NULL; return list[0]; } /*! Find the item that is associated to a widget \param widget Widget on the legend \return Associated item info \sa legendWidget() */ QVariant QwtLegend::itemInfo( const QWidget *widget ) const { return d_data->itemMap.itemInfo( widget ); } //! \return True, when no item is inserted bool QwtLegend::isEmpty() const { return d_data->itemMap.isEmpty(); } /*! Return the extent, that is needed for the scrollbars \param orientation Orientation ( \return The width of the vertical scrollbar for Qt::Horizontal and v.v. */ int QwtLegend::scrollExtent( Qt::Orientation orientation ) const { int extent = 0; if ( orientation == Qt::Horizontal ) extent = verticalScrollBar()->sizeHint().width(); else extent = horizontalScrollBar()->sizeHint().height(); return extent; } qsstv_8.2.12/qwt/qwt_abstract_scale_draw.h000664 001750 001750 00000007036 12440612574 020647 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SCALE_DRAW_H #define QWT_ABSTRACT_SCALE_DRAW_H #include "qwt_global.h" #include "qwt_scale_div.h" #include "qwt_text.h" class QPalette; class QPainter; class QFont; class QwtTransform; class QwtScaleMap; /*! \brief A abstract base class for drawing scales QwtAbstractScaleDraw can be used to draw linear or logarithmic scales. After a scale division has been specified as a QwtScaleDiv object using setScaleDiv(), the scale can be drawn with the draw() member. */ class QWT_EXPORT QwtAbstractScaleDraw { public: /*! Components of a scale \sa enableComponent(), hasComponent */ enum ScaleComponent { //! Backbone = the line where the ticks are located Backbone = 0x01, //! Ticks Ticks = 0x02, //! Labels Labels = 0x04 }; //! Scale components typedef QFlags ScaleComponents; QwtAbstractScaleDraw(); virtual ~QwtAbstractScaleDraw(); void setScaleDiv( const QwtScaleDiv &s ); const QwtScaleDiv& scaleDiv() const; void setTransformation( QwtTransform * ); const QwtScaleMap &scaleMap() const; QwtScaleMap &scaleMap(); void enableComponent( ScaleComponent, bool enable = true ); bool hasComponent( ScaleComponent ) const; void setTickLength( QwtScaleDiv::TickType, double length ); double tickLength( QwtScaleDiv::TickType ) const; double maxTickLength() const; void setSpacing( double margin ); double spacing() const; void setPenWidth( int width ); int penWidth() const; virtual void draw( QPainter *, const QPalette & ) const; virtual QwtText label( double ) const; /*! Calculate the extent The extent is the distance from the baseline to the outermost pixel of the scale draw in opposite to its orientation. It is at least minimumExtent() pixels. \param font Font used for drawing the tick labels \return Number of pixels \sa setMinimumExtent(), minimumExtent() */ virtual double extent( const QFont &font ) const = 0; void setMinimumExtent( double ); double minimumExtent() const; protected: /*! Draw a tick \param painter Painter \param value Value of the tick \param len Length of the tick \sa drawBackbone(), drawLabel() */ virtual void drawTick( QPainter *painter, double value, double len ) const = 0; /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ virtual void drawBackbone( QPainter *painter ) const = 0; /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone() */ virtual void drawLabel( QPainter *painter, double value ) const = 0; void invalidateCache(); const QwtText &tickLabel( const QFont &, double value ) const; private: QwtAbstractScaleDraw( const QwtAbstractScaleDraw & ); QwtAbstractScaleDraw &operator=( const QwtAbstractScaleDraw & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtAbstractScaleDraw::ScaleComponents ) #endif qsstv_8.2.12/qwt/qwt_legend_data.cpp000664 001750 001750 00000005252 12440612574 017440 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend_data.h" //! Constructor QwtLegendData::QwtLegendData() { } //! Destructor QwtLegendData::~QwtLegendData() { } /*! Set the legend attributes QwtLegendData actually is a QMap with some convenience interfaces \param map Values \sa values() */ void QwtLegendData::setValues( const QMap &map ) { d_map = map; } /*! \return Legend attributes \sa setValues() */ const QMap &QwtLegendData::values() const { return d_map; } /*! \param role Attribute role \return True, when the internal map has an entry for role */ bool QwtLegendData::hasRole( int role ) const { return d_map.contains( role ); } /*! Set an attribute value \param role Attribute role \param data Attribute value \sa value() */ void QwtLegendData::setValue( int role, const QVariant &data ) { d_map[role] = data; } /*! \param role Attribute role \return Attribute value for a specific role */ QVariant QwtLegendData::value( int role ) const { if ( !d_map.contains( role ) ) return QVariant(); return d_map[role]; } //! \return True, when the internal map is empty bool QwtLegendData::isValid() const { return !d_map.isEmpty(); } //! \return Value of the TitleRole attribute QwtText QwtLegendData::title() const { QwtText text; const QVariant titleValue = value( QwtLegendData::TitleRole ); if ( titleValue.canConvert() ) { text = qvariant_cast( titleValue ); } else if ( titleValue.canConvert() ) { text.setText( qvariant_cast( titleValue ) ); } return text; } //! \return Value of the IconRole attribute QwtGraphic QwtLegendData::icon() const { const QVariant iconValue = value( QwtLegendData::IconRole ); QwtGraphic graphic; if ( iconValue.canConvert() ) { graphic = qvariant_cast( iconValue ); } return graphic; } //! \return Value of the ModeRole attribute QwtLegendData::Mode QwtLegendData::mode() const { const QVariant modeValue = value( QwtLegendData::ModeRole ); if ( modeValue.canConvert() ) { const int mode = qvariant_cast( modeValue ); return static_cast( mode ); } return QwtLegendData::ReadOnly; } qsstv_8.2.12/qwt/qwt_abstract_slider.cpp000664 001750 001750 00000043742 12440612574 020364 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_slider.h" #include "qwt_abstract_scale_draw.h" #include "qwt_math.h" #include "qwt_scale_map.h" #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #endif static double qwtAlignToScaleDiv( const QwtAbstractSlider *slider, double value ) { const QwtScaleDiv &sd = slider->scaleDiv(); const int tValue = slider->transform( value ); if ( tValue == slider->transform( sd.lowerBound() ) ) return sd.lowerBound(); if ( tValue == slider->transform( sd.lowerBound() ) ) return sd.upperBound(); for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) { const QList ticks = sd.ticks( i ); for ( int j = 0; j < ticks.size(); j++ ) { if ( slider->transform( ticks[ j ] ) == tValue ) return ticks[ j ]; } } return value; } class QwtAbstractSlider::PrivateData { public: PrivateData(): isScrolling( false ), isTracking( true ), pendingValueChanged( false ), readOnly( false ), totalSteps( 100 ), singleSteps( 1 ), pageSteps( 10 ), stepAlignment( true ), isValid( false ), value( 0.0 ), wrapping( false ), invertedControls( false ) { } bool isScrolling; bool isTracking; bool pendingValueChanged; bool readOnly; uint totalSteps; uint singleSteps; uint pageSteps; bool stepAlignment; bool isValid; double value; bool wrapping; bool invertedControls; }; /*! \brief Constructor The scale is initialized to [0.0, 100.0], the number of steps is set to 100 with 1 and 10 and single an page step sizes. Step alignment is enabled. The initial value is invalid. \param parent Parent widget */ QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ): QwtAbstractScale( parent ) { d_data = new QwtAbstractSlider::PrivateData; setScale( 0.0, 100.0 ); setFocusPolicy( Qt::StrongFocus ); } //! Destructor QwtAbstractSlider::~QwtAbstractSlider() { delete d_data; } /*! Set the value to be valid/invalid \param on When true, the value is invalidated \sa setValue() */ void QwtAbstractSlider::setValid( bool on ) { if ( on != d_data->isValid ) { d_data->isValid = on; sliderChange(); Q_EMIT valueChanged( d_data->value ); } } //! \return True, when the value is invalid bool QwtAbstractSlider::isValid() const { return d_data->isValid; } /*! En/Disable read only mode In read only mode the slider can't be controlled by mouse or keyboard. \param on Enables in case of true \sa isReadOnly() \warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus */ void QwtAbstractSlider::setReadOnly( bool on ) { if ( d_data->readOnly != on ) { d_data->readOnly = on; setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus ); update(); } } /*! In read only mode the slider can't be controlled by mouse or keyboard. \return true if read only \sa setReadOnly() */ bool QwtAbstractSlider::isReadOnly() const { return d_data->readOnly; } /*! \brief Enables or disables tracking. If tracking is enabled, the slider emits the valueChanged() signal while the movable part of the slider is being dragged. If tracking is disabled, the slider emits the valueChanged() signal only when the user releases the slider. Tracking is enabled by default. \param on \c true (enable) or \c false (disable) tracking. \sa isTracking(), sliderMoved() */ void QwtAbstractSlider::setTracking( bool on ) { d_data->isTracking = on; } /*! \return True, when tracking has been enabled \sa setTracking() */ bool QwtAbstractSlider::isTracking() const { return d_data->isTracking; } /*! Mouse press event handler \param event Mouse event */ void QwtAbstractSlider::mousePressEvent( QMouseEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( !d_data->isValid || lowerBound() == upperBound() ) return; d_data->isScrolling = isScrollPosition( event->pos() ); if ( d_data->isScrolling ) { d_data->pendingValueChanged = false; Q_EMIT sliderPressed(); } } /*! Mouse Move Event handler \param event Mouse event */ void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( d_data->isValid && d_data->isScrolling ) { double value = scrolledTo( event->pos() ); if ( value != d_data->value ) { value = boundedValue( value ); if ( d_data->stepAlignment ) { value = alignedValue( value ); } else { value = qwtAlignToScaleDiv( this, value ); } if ( value != d_data->value ) { d_data->value = value; sliderChange(); Q_EMIT sliderMoved( d_data->value ); if ( d_data->isTracking ) Q_EMIT valueChanged( d_data->value ); else d_data->pendingValueChanged = true; } } } } /*! Mouse Release Event handler \param event Mouse event */ void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( d_data->isScrolling && d_data->isValid ) { d_data->isScrolling = false; if ( d_data->pendingValueChanged ) Q_EMIT valueChanged( d_data->value ); Q_EMIT sliderReleased(); } } /*! Wheel Event handler In/decreases the value by s number of steps. The direction depends on the invertedControls() property. When the control or shift modifier is pressed the wheel delta ( divided by 120 ) is mapped to an increment according to pageSteps(). Otherwise it is mapped to singleSteps(). \param event Wheel event */ void QwtAbstractSlider::wheelEvent( QWheelEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( !d_data->isValid || d_data->isScrolling ) return; int numSteps = 0; if ( ( event->modifiers() & Qt::ControlModifier) || ( event->modifiers() & Qt::ShiftModifier ) ) { // one page regardless of delta numSteps = d_data->pageSteps; if ( event->delta() < 0 ) numSteps = -numSteps; } else { const int numTurns = ( event->delta() / 120 ); numSteps = numTurns * d_data->singleSteps; } if ( d_data->invertedControls ) numSteps = -numSteps; const double value = incrementedValue( d_data->value, numSteps ); if ( value != d_data->value ) { d_data->value = value; sliderChange(); Q_EMIT sliderMoved( d_data->value ); Q_EMIT valueChanged( d_data->value ); } } /*! Handles key events QwtAbstractSlider handles the following keys: - Qt::Key_Left\n Add/Subtract singleSteps() in direction to lowerBound(); - Qt::Key_Right\n Add/Subtract singleSteps() in direction to upperBound(); - Qt::Key_Down\n Subtract singleSteps(), when invertedControls() is false - Qt::Key_Up\n Add singleSteps(), when invertedControls() is false - Qt::Key_PageDown\n Subtract pageSteps(), when invertedControls() is false - Qt::Key_PageUp\n Add pageSteps(), when invertedControls() is false - Qt::Key_Home\n Set the value to the minimum() - Qt::Key_End\n Set the value to the maximum() \param event Key event \sa isReadOnly() */ void QwtAbstractSlider::keyPressEvent( QKeyEvent *event ) { if ( isReadOnly() ) { event->ignore(); return; } if ( !d_data->isValid || d_data->isScrolling ) return; int numSteps = 0; double value = d_data->value; switch ( event->key() ) { case Qt::Key_Left: { numSteps = -static_cast( d_data->singleSteps ); if ( isInverted() ) numSteps = -numSteps; break; } case Qt::Key_Right: { numSteps = d_data->singleSteps; if ( isInverted() ) numSteps = -numSteps; break; } case Qt::Key_Down: { numSteps = -static_cast( d_data->singleSteps ); if ( d_data->invertedControls ) numSteps = -numSteps; break; } case Qt::Key_Up: { numSteps = d_data->singleSteps; if ( d_data->invertedControls ) numSteps = -numSteps; break; } case Qt::Key_PageUp: { numSteps = d_data->pageSteps; if ( d_data->invertedControls ) numSteps = -numSteps; break; } case Qt::Key_PageDown: { numSteps = -static_cast( d_data->pageSteps ); if ( d_data->invertedControls ) numSteps = -numSteps; break; } case Qt::Key_Home: { value = minimum(); break; } case Qt::Key_End: { value = maximum(); break; } default:; { event->ignore(); } } if ( numSteps != 0 ) { value = incrementedValue( d_data->value, numSteps ); } if ( value != d_data->value ) { d_data->value = value; sliderChange(); Q_EMIT sliderMoved( d_data->value ); Q_EMIT valueChanged( d_data->value ); } } /*! \brief Set the number of steps The range of the slider is divided into a number of steps from which the value increments according to user inputs depend. The default setting is 100. \param stepCount Number of steps \sa totalSteps(), setSingleSteps(), setPageSteps() */ void QwtAbstractSlider::setTotalSteps( uint stepCount ) { d_data->totalSteps = stepCount; } /*! \return Number of steps \sa setTotalSteps(), singleSteps(), pageSteps() */ uint QwtAbstractSlider::totalSteps() const { return d_data->totalSteps; } /*! \brief Set the number of steps for a single increment The range of the slider is divided into a number of steps from which the value increments according to user inputs depend. \param stepCount Number of steps \sa singleSteps(), setTotalSteps(), setPageSteps() */ void QwtAbstractSlider::setSingleSteps( uint stepCount ) { d_data->singleSteps = stepCount; } /*! \return Number of steps \sa setSingleSteps(), totalSteps(), pageSteps() */ uint QwtAbstractSlider::singleSteps() const { return d_data->singleSteps; } /*! \brief Set the number of steps for a page increment The range of the slider is divided into a number of steps from which the value increments according to user inputs depend. \param stepCount Number of steps \sa pageSteps(), setTotalSteps(), setSingleSteps() */ void QwtAbstractSlider::setPageSteps( uint stepCount ) { d_data->pageSteps = stepCount; } /*! \return Number of steps \sa setPageSteps(), totalSteps(), singleSteps() */ uint QwtAbstractSlider::pageSteps() const { return d_data->pageSteps; } /*! \brief Enable step alignment When step alignment is enabled values resulting from slider movements are aligned to the step size. \param on Enable step alignment when true \sa stepAlignment() */ void QwtAbstractSlider::setStepAlignment( bool on ) { if ( on != d_data->stepAlignment ) { d_data->stepAlignment = on; } } /*! \return True, when step alignment is enabled \sa setStepAlignment() */ bool QwtAbstractSlider::stepAlignment() const { return d_data->stepAlignment; } /*! Set the slider to the specified value \param value New value \sa setValid(), sliderChange(), valueChanged() */ void QwtAbstractSlider::setValue( double value ) { value = qBound( minimum(), value, maximum() ); const bool changed = ( d_data->value != value ) || !d_data->isValid; d_data->value = value; d_data->isValid = true; if ( changed ) { sliderChange(); Q_EMIT valueChanged( d_data->value ); } } //! Returns the current value. double QwtAbstractSlider::value() const { return d_data->value; } /*! If wrapping is true stepping up from upperBound() value will take you to the minimum() value and vice versa. \param on En/Disable wrapping \sa wrapping() */ void QwtAbstractSlider::setWrapping( bool on ) { d_data->wrapping = on; } /*! \return True, when wrapping is set \sa setWrapping() */ bool QwtAbstractSlider::wrapping() const { return d_data->wrapping; } /*! Invert wheel and key events Usually scrolling the mouse wheel "up" and using keys like page up will increase the slider's value towards its maximum. When invertedControls() is enabled the value is scrolled towards its minimum. Inverting the controls might be f.e. useful for a vertical slider with an inverted scale ( decreasing from top to bottom ). \param on Invert controls, when true \sa invertedControls(), keyEvent(), wheelEvent() */ void QwtAbstractSlider::setInvertedControls( bool on ) { d_data->invertedControls = on; } /*! \return True, when the controls are inverted \sa setInvertedControls() */ bool QwtAbstractSlider::invertedControls() const { return d_data->invertedControls; } /*! Increment the slider The step size depends on the number of totalSteps() \param stepCount Number of steps \sa setTotalSteps(), incrementedValue() */ void QwtAbstractSlider::incrementValue( int stepCount ) { const double value = incrementedValue( d_data->value, stepCount ); if ( value != d_data->value ) { d_data->value = value; sliderChange(); } } /*! Increment a value \param value Value \param stepCount Number of steps \return Incremented value */ double QwtAbstractSlider::incrementedValue( double value, int stepCount ) const { if ( d_data->totalSteps == 0 ) return value; const QwtTransform *transformation = scaleMap().transformation(); if ( transformation == NULL ) { const double range = maximum() - minimum(); value += stepCount * range / d_data->totalSteps; } else { QwtScaleMap map = scaleMap(); map.setPaintInterval( 0, d_data->totalSteps ); // we need equidant steps according to // paint device coordinates const double range = transformation->transform( maximum() ) - transformation->transform( minimum() ); const double stepSize = range / d_data->totalSteps; double v = transformation->transform( value ); v = qRound( v / stepSize ) * stepSize; v += stepCount * range / d_data->totalSteps; value = transformation->invTransform( v ); } value = boundedValue( value ); if ( d_data->stepAlignment ) value = alignedValue( value ); return value; } double QwtAbstractSlider::boundedValue( double value ) const { const double vmin = minimum(); const double vmax = maximum(); if ( d_data->wrapping && vmin != vmax ) { const int fullCircle = 360 * 16; const double pd = scaleMap().pDist(); if ( int( pd / fullCircle ) * fullCircle == pd ) { // full circle scales: min and max are the same const double range = vmax - vmin; if ( value < vmin ) { value += ::ceil( ( vmin - value ) / range ) * range; } else if ( value > vmax ) { value -= ::ceil( ( value - vmax ) / range ) * range; } } else { if ( value < vmin ) value = vmax; else if ( value > vmax ) value = vmin; } } else { value = qBound( vmin, value, vmax ); } return value; } double QwtAbstractSlider::alignedValue( double value ) const { if ( d_data->totalSteps == 0 ) return value; if ( scaleMap().transformation() == NULL ) { const double stepSize = ( maximum() - minimum() ) / d_data->totalSteps; if ( stepSize > 0.0 ) { value = lowerBound() + qRound( ( value - lowerBound() ) / stepSize ) * stepSize; } } else { const double stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps; if ( stepSize > 0.0 ) { double v = scaleMap().transform( value ); v = scaleMap().p1() + qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize; value = scaleMap().invTransform( v ); } } // correct rounding error if value = 0 if ( qFuzzyCompare( value + 1.0, 1.0 ) ) { value = 0.0; } else { // correct rounding error at the border if ( qFuzzyCompare( value, upperBound() ) ) value = upperBound(); else if ( qFuzzyCompare( value, lowerBound() ) ) value = lowerBound(); } return value; } /*! Update the slider according to modifications of the scale */ void QwtAbstractSlider::scaleChange() { const double value = qBound( minimum(), d_data->value, maximum() ); const bool changed = ( value != d_data->value ); if ( changed ) { d_data->value = value; } if ( d_data->isValid || changed ) Q_EMIT valueChanged( d_data->value ); updateGeometry(); update(); } //! Calling update() void QwtAbstractSlider::sliderChange() { update(); } qsstv_8.2.12/qwt/qwt_panner.h000664 001750 001750 00000005574 12440612574 016150 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PANNER_H #define QWT_PANNER_H 1 #include "qwt_global.h" #include #include class QCursor; /*! \brief QwtPanner provides panning of a widget QwtPanner grabs the contents of a widget, that can be dragged in all directions. The offset between the start and the end position is emitted by the panned signal. QwtPanner grabs the content of the widget into a pixmap and moves the pixmap around, without initiating any repaint events for the widget. Areas, that are not part of content are not painted while panning. This makes panning fast enough for widgets, where repaints are too slow for mouse movements. For widgets, where repaints are very fast it might be better to implement panning manually by mapping mouse events into paint events. */ class QWT_EXPORT QwtPanner: public QWidget { Q_OBJECT public: QwtPanner( QWidget* parent ); virtual ~QwtPanner(); void setEnabled( bool ); bool isEnabled() const; void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier ); void getMouseButton( Qt::MouseButton &button, Qt::KeyboardModifiers & ) const; void setAbortKey( int key, Qt::KeyboardModifiers = Qt::NoModifier ); void getAbortKey( int &key, Qt::KeyboardModifiers & ) const; void setCursor( const QCursor & ); const QCursor cursor() const; void setOrientations( Qt::Orientations ); Qt::Orientations orientations() const; bool isOrientationEnabled( Qt::Orientation ) const; virtual bool eventFilter( QObject *, QEvent * ); Q_SIGNALS: /*! Signal emitted, when panning is done \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void panned( int dx, int dy ); /*! Signal emitted, while the widget moved, but panning is not finished. \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void moved( int dx, int dy ); protected: virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void paintEvent( QPaintEvent * ); virtual QBitmap contentsMask() const; virtual QPixmap grab() const; private: #ifndef QT_NO_CURSOR void showCursor( bool ); #endif class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_abstract_slider.h000664 001750 001750 00000010463 12440612574 020023 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SLIDER_H #define QWT_ABSTRACT_SLIDER_H #include "qwt_global.h" #include "qwt_abstract_scale.h" /*! \brief An abstract base class for slider widgets with a scale A slider widget displays a value according to a scale. The class is designed as a common super class for widgets like QwtKnob, QwtDial and QwtSlider. When the slider is nor readOnly() its value can be modified by keyboard, mouse and wheel inputs. The range of the slider is divided into a number of steps from which the value increments according to user inputs depend. Only for linear scales the number of steps correspond with a fixed step size. */ class QWT_EXPORT QwtAbstractSlider: public QwtAbstractScale { Q_OBJECT Q_PROPERTY( double value READ value WRITE setValue ) Q_PROPERTY( uint totalSteps READ totalSteps WRITE setTotalSteps ) Q_PROPERTY( uint singleSteps READ singleSteps WRITE setSingleSteps ) Q_PROPERTY( uint pageSteps READ pageSteps WRITE setPageSteps ) Q_PROPERTY( bool stepAlignment READ stepAlignment WRITE setStepAlignment ) Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly ) Q_PROPERTY( bool tracking READ isTracking WRITE setTracking ) Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping ) Q_PROPERTY( bool invertedControls READ invertedControls WRITE setInvertedControls ) public: explicit QwtAbstractSlider( QWidget *parent = NULL ); virtual ~QwtAbstractSlider(); void setValid( bool ); bool isValid() const; double value() const; void setWrapping( bool ); bool wrapping() const; void setTotalSteps( uint ); uint totalSteps() const; void setSingleSteps( uint ); uint singleSteps() const; void setPageSteps( uint ); uint pageSteps() const; void setStepAlignment( bool ); bool stepAlignment() const; void setTracking( bool ); bool isTracking() const; void setReadOnly( bool ); bool isReadOnly() const; void setInvertedControls( bool ); bool invertedControls() const; public Q_SLOTS: void setValue( double val ); Q_SIGNALS: /*! \brief Notify a change of value. When tracking is enabled (default setting), this signal will be emitted every time the value changes. \param value New value \sa setTracking(), sliderMoved() */ void valueChanged( double value ); /*! This signal is emitted when the user presses the movable part of the slider. */ void sliderPressed(); /*! This signal is emitted when the user releases the movable part of the slider. */ void sliderReleased(); /*! This signal is emitted when the user moves the slider with the mouse. \param value New value \sa valueChanged() */ void sliderMoved( double value ); protected: virtual void mousePressEvent( QMouseEvent * ); virtual void mouseReleaseEvent( QMouseEvent * ); virtual void mouseMoveEvent( QMouseEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void wheelEvent( QWheelEvent * ); /*! \brief Determine what to do when the user presses a mouse button. \param pos Mouse position \retval True, when pos is a valid scroll position \sa scrolledTo() */ virtual bool isScrollPosition( const QPoint &pos ) const = 0; /*! \brief Determine the value for a new position of the movable part of the slider \param pos Mouse position \return Value for the mouse position \sa isScrollPosition() */ virtual double scrolledTo( const QPoint &pos ) const = 0; void incrementValue( int numSteps ); virtual void scaleChange(); protected: virtual void sliderChange(); double incrementedValue( double value, int stepCount ) const; private: double alignedValue( double ) const; double boundedValue( double ) const; class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_picker.cpp000664 001750 001750 00000114521 12440612574 016466 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker.h" #include "qwt_picker_machine.h" #include "qwt_painter.h" #include "qwt_math.h" #include "qwt_widget_overlay.h" #include #include #include #include #include #include #include #include #include static inline QRegion qwtMaskRegion( const QRect &r, int penWidth ) { const int pw = qMax( penWidth, 1 ); const int pw2 = penWidth / 2; int x1 = r.left() - pw2; int x2 = r.right() + 1 + pw2 + ( pw % 2 ); int y1 = r.top() - pw2; int y2 = r.bottom() + 1 + pw2 + ( pw % 2 ); QRegion region; region += QRect( x1, y1, x2 - x1, pw ); region += QRect( x1, y1, pw, y2 - y1 ); region += QRect( x1, y2 - pw, x2 - x1, pw ); region += QRect( x2 - pw, y1, pw, y2 - y1 ); return region; } static inline QRegion qwtMaskRegion( const QLine &l, int penWidth ) { const int pw = qMax( penWidth, 1 ); const int pw2 = penWidth / 2; QRegion region; if ( l.x1() == l.x2() ) { region += QRect( l.x1() - pw2, l.y1(), pw, l.y2() ).normalized(); } else if ( l.y1() == l.y2() ) { region += QRect( l.x1(), l.y1() - pw2, l.x2(), pw ).normalized(); } return region; } class QwtPickerRubberband: public QwtWidgetOverlay { public: QwtPickerRubberband( QwtPicker *, QWidget * ); protected: virtual void drawOverlay( QPainter * ) const; virtual QRegion maskHint() const; QwtPicker *d_picker; }; class QwtPickerTracker: public QwtWidgetOverlay { public: QwtPickerTracker( QwtPicker *, QWidget * ); protected: virtual void drawOverlay( QPainter * ) const; virtual QRegion maskHint() const; QwtPicker *d_picker; }; class QwtPicker::PrivateData { public: PrivateData(): enabled( false ), stateMachine( NULL ), resizeMode( QwtPicker::Stretch ), rubberBand( QwtPicker::NoRubberBand ), trackerMode( QwtPicker::AlwaysOff ), isActive( false ), trackerPosition( -1, -1 ), mouseTracking( false ), openGL( false ) { } bool enabled; QwtPickerMachine *stateMachine; QwtPicker::ResizeMode resizeMode; QwtPicker::RubberBand rubberBand; QPen rubberBandPen; QwtPicker::DisplayMode trackerMode; QPen trackerPen; QFont trackerFont; QPolygon pickedPoints; bool isActive; QPoint trackerPosition; bool mouseTracking; // used to save previous value QPointer< QwtPickerRubberband > rubberBandOverlay; QPointer< QwtPickerTracker> trackerOverlay; bool openGL; }; QwtPickerRubberband::QwtPickerRubberband( QwtPicker *picker, QWidget *parent ): QwtWidgetOverlay( parent ), d_picker( picker ) { setMaskMode( QwtWidgetOverlay::MaskHint ); } QRegion QwtPickerRubberband::maskHint() const { return d_picker->rubberBandMask(); } void QwtPickerRubberband::drawOverlay( QPainter *painter ) const { painter->setPen( d_picker->rubberBandPen() ); d_picker->drawRubberBand( painter ); } QwtPickerTracker::QwtPickerTracker( QwtPicker *picker, QWidget *parent ): QwtWidgetOverlay( parent ), d_picker( picker ) { setMaskMode( QwtWidgetOverlay::MaskHint ); } QRegion QwtPickerTracker::maskHint() const { return d_picker->trackerRect( font() ); } void QwtPickerTracker::drawOverlay( QPainter *painter ) const { painter->setPen( d_picker->trackerPen() ); d_picker->drawTracker( painter ); } /*! Constructor Creates an picker that is enabled, but without a state machine. rubber band and tracker are disabled. \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( QWidget *parent ): QObject( parent ) { init( parent, NoRubberBand, AlwaysOff ); } /*! Constructor \param rubberBand Rubber band style \param trackerMode Tracker mode \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget *parent ): QObject( parent ) { init( parent, rubberBand, trackerMode ); } //! Destructor QwtPicker::~QwtPicker() { setMouseTracking( false ); delete d_data->stateMachine; delete d_data->rubberBandOverlay; delete d_data->trackerOverlay; delete d_data; } //! Initialize the picker - used by the constructors void QwtPicker::init( QWidget *parent, RubberBand rubberBand, DisplayMode trackerMode ) { d_data = new PrivateData; d_data->rubberBand = rubberBand; if ( parent ) { if ( parent->focusPolicy() == Qt::NoFocus ) parent->setFocusPolicy( Qt::WheelFocus ); d_data->openGL = parent->inherits( "QGLWidget" ); d_data->trackerFont = parent->font(); d_data->mouseTracking = parent->hasMouseTracking(); setEnabled( true ); } setTrackerMode( trackerMode ); } /*! Set a state machine and delete the previous one \param stateMachine State machine \sa stateMachine() */ void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine ) { if ( d_data->stateMachine != stateMachine ) { reset(); delete d_data->stateMachine; d_data->stateMachine = stateMachine; if ( d_data->stateMachine ) d_data->stateMachine->reset(); } } /*! \return Assigned state machine \sa setStateMachine() */ QwtPickerMachine *QwtPicker::stateMachine() { return d_data->stateMachine; } /*! \return Assigned state machine \sa setStateMachine() */ const QwtPickerMachine *QwtPicker::stateMachine() const { return d_data->stateMachine; } //! Return the parent widget, where the selection happens QWidget *QwtPicker::parentWidget() { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast( obj ); return NULL; } //! Return the parent widget, where the selection happens const QWidget *QwtPicker::parentWidget() const { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast< const QWidget *>( obj ); return NULL; } /*! Set the rubber band style \param rubberBand Rubber band style The default value is NoRubberBand. \sa rubberBand(), RubberBand, setRubberBandPen() */ void QwtPicker::setRubberBand( RubberBand rubberBand ) { d_data->rubberBand = rubberBand; } /*! \return Rubber band style \sa setRubberBand(), RubberBand, rubberBandPen() */ QwtPicker::RubberBand QwtPicker::rubberBand() const { return d_data->rubberBand; } /*! \brief Set the display mode of the tracker. A tracker displays information about current position of the cursor as a string. The display mode controls if the tracker has to be displayed whenever the observed widget has focus and cursor (AlwaysOn), never (AlwaysOff), or only when the selection is active (ActiveOnly). \param mode Tracker display mode \warning In case of AlwaysOn, mouseTracking will be enabled for the observed widget. \sa trackerMode(), DisplayMode */ void QwtPicker::setTrackerMode( DisplayMode mode ) { if ( d_data->trackerMode != mode ) { d_data->trackerMode = mode; setMouseTracking( d_data->trackerMode == AlwaysOn ); } } /*! \return Tracker display mode \sa setTrackerMode(), DisplayMode */ QwtPicker::DisplayMode QwtPicker::trackerMode() const { return d_data->trackerMode; } /*! \brief Set the resize mode. The resize mode controls what to do with the selected points of an active selection when the observed widget is resized. Stretch means the points are scaled according to the new size, KeepSize means the points remain unchanged. The default mode is Stretch. \param mode Resize mode \sa resizeMode(), ResizeMode */ void QwtPicker::setResizeMode( ResizeMode mode ) { d_data->resizeMode = mode; } /*! \return Resize mode \sa setResizeMode(), ResizeMode */ QwtPicker::ResizeMode QwtPicker::resizeMode() const { return d_data->resizeMode; } /*! \brief En/disable the picker When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param enabled true or false \sa isEnabled(), eventFilter() */ void QwtPicker::setEnabled( bool enabled ) { if ( d_data->enabled != enabled ) { d_data->enabled = enabled; QWidget *w = parentWidget(); if ( w ) { if ( enabled ) w->installEventFilter( this ); else w->removeEventFilter( this ); } updateDisplay(); } } /*! \return true when enabled, false otherwise \sa setEnabled(), eventFilter() */ bool QwtPicker::isEnabled() const { return d_data->enabled; } /*! Set the font for the tracker \param font Tracker font \sa trackerFont(), setTrackerMode(), setTrackerPen() */ void QwtPicker::setTrackerFont( const QFont &font ) { if ( font != d_data->trackerFont ) { d_data->trackerFont = font; updateDisplay(); } } /*! \return Tracker font \sa setTrackerFont(), trackerMode(), trackerPen() */ QFont QwtPicker::trackerFont() const { return d_data->trackerFont; } /*! Set the pen for the tracker \param pen Tracker pen \sa trackerPen(), setTrackerMode(), setTrackerFont() */ void QwtPicker::setTrackerPen( const QPen &pen ) { if ( pen != d_data->trackerPen ) { d_data->trackerPen = pen; updateDisplay(); } } /*! \return Tracker pen \sa setTrackerPen(), trackerMode(), trackerFont() */ QPen QwtPicker::trackerPen() const { return d_data->trackerPen; } /*! Set the pen for the rubberband \param pen Rubber band pen \sa rubberBandPen(), setRubberBand() */ void QwtPicker::setRubberBandPen( const QPen &pen ) { if ( pen != d_data->rubberBandPen ) { d_data->rubberBandPen = pen; updateDisplay(); } } /*! \return Rubber band pen \sa setRubberBandPen(), rubberBand() */ QPen QwtPicker::rubberBandPen() const { return d_data->rubberBandPen; } /*! \brief Return the label for a position In case of HLineRubberBand the label is the value of the y position, in case of VLineRubberBand the value of the x position. Otherwise the label contains x and y position separated by a ',' . The format for the string conversion is "%d". \param pos Position \return Converted position as string */ QwtText QwtPicker::trackerText( const QPoint &pos ) const { QString label; switch ( rubberBand() ) { case HLineRubberBand: label.sprintf( "%d", pos.y() ); break; case VLineRubberBand: label.sprintf( "%d", pos.x() ); break; default: label.sprintf( "%d, %d", pos.x(), pos.y() ); } return label; } /*! Calculate the mask for the rubber band overlay \return Region for the mask \sa QWidget::setMask() */ QRegion QwtPicker::rubberBandMask() const { QRegion mask; if ( !isActive() || rubberBand() == NoRubberBand || rubberBandPen().style() == Qt::NoPen ) { return mask; } const QPolygon pa = adjustedPoints( d_data->pickedPoints ); QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( d_data->stateMachine ) selectionType = d_data->stateMachine->selectionType(); switch ( selectionType ) { case QwtPickerMachine::NoSelection: case QwtPickerMachine::PointSelection: { if ( pa.count() < 1 ) return mask; const QPoint pos = pa[0]; const int pw = rubberBandPen().width(); const QRect pRect = pickArea().boundingRect().toRect(); switch ( rubberBand() ) { case VLineRubberBand: { mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), pos.x(), pRect.bottom() ), pw ); break; } case HLineRubberBand: { mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), pRect.right(), pos.y() ), pw ); break; } case CrossRubberBand: { mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), pos.x(), pRect.bottom() ), pw ); mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), pRect.right(), pos.y() ), pw ); break; } default: break; } break; } case QwtPickerMachine::RectSelection: { if ( pa.count() < 2 ) return mask; const int pw = rubberBandPen().width(); switch ( rubberBand() ) { case RectRubberBand: { const QRect r = QRect( pa.first(), pa.last() ); mask = qwtMaskRegion( r.normalized(), pw ); break; } case EllipseRubberBand: { const QRect r = QRect( pa.first(), pa.last() ); mask += r.adjusted( -pw, -pw, pw, pw ); break; } default: break; } break; } case QwtPickerMachine::PolygonSelection: { const int pw = rubberBandPen().width(); if ( pw <= 1 ) { // because of the join style we better // return a mask for a pen width <= 1 only const int off = 2 * pw; const QRect r = pa.boundingRect(); mask += r.adjusted( -off, -off, off, off ); } break; } default: break; } return mask; } /*! Draw a rubber band, depending on rubberBand() \param painter Painter, initialized with a clip region \sa rubberBand(), RubberBand */ void QwtPicker::drawRubberBand( QPainter *painter ) const { if ( !isActive() || rubberBand() == NoRubberBand || rubberBandPen().style() == Qt::NoPen ) { return; } const QPolygon pa = adjustedPoints( d_data->pickedPoints ); QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( d_data->stateMachine ) selectionType = d_data->stateMachine->selectionType(); switch ( selectionType ) { case QwtPickerMachine::NoSelection: case QwtPickerMachine::PointSelection: { if ( pa.count() < 1 ) return; const QPoint pos = pa[0]; const QRect pRect = pickArea().boundingRect().toRect(); switch ( rubberBand() ) { case VLineRubberBand: { QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); break; } case HLineRubberBand: { QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; } case CrossRubberBand: { QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; } default: break; } break; } case QwtPickerMachine::RectSelection: { if ( pa.count() < 2 ) return; const QRect rect = QRect( pa.first(), pa.last() ).normalized(); switch ( rubberBand() ) { case EllipseRubberBand: { QwtPainter::drawEllipse( painter, rect ); break; } case RectRubberBand: { QwtPainter::drawRect( painter, rect ); break; } default: break; } break; } case QwtPickerMachine::PolygonSelection: { if ( rubberBand() == PolygonRubberBand ) painter->drawPolyline( pa ); break; } default: break; } } /*! Draw the tracker \param painter Painter \sa trackerRect(), trackerText() */ void QwtPicker::drawTracker( QPainter *painter ) const { const QRect textRect = trackerRect( painter->font() ); if ( !textRect.isEmpty() ) { const QwtText label = trackerText( d_data->trackerPosition ); if ( !label.isEmpty() ) label.draw( painter, textRect ); } } /*! \brief Map the pickedPoints() into a selection() adjustedPoints() maps the points, that have been collected on the parentWidget() into a selection(). The default implementation simply returns the points unmodified. The reason, why a selection() differs from the picked points depends on the application requirements. F.e. : - A rectangular selection might need to have a specific aspect ratio only.\n - A selection could accept non intersecting polygons only.\n - ...\n The example below is for a rectangular selection, where the first point is the center of the selected rectangle. \par Example \verbatim QPolygon MyPicker::adjustedPoints(const QPolygon &points) const { QPolygon adjusted; if ( points.size() == 2 ) { const int width = qAbs(points[1].x() - points[0].x()); const int height = qAbs(points[1].y() - points[0].y()); QRect rect(0, 0, 2 * width, 2 * height); rect.moveCenter(points[0]); adjusted += rect.topLeft(); adjusted += rect.bottomRight(); } return adjusted; }\endverbatim\n \param points Selected points \return Selected points unmodified */ QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const { return points; } /*! \return Selected points \sa pickedPoints(), adjustedPoints() */ QPolygon QwtPicker::selection() const { return adjustedPoints( d_data->pickedPoints ); } //! \return Current position of the tracker QPoint QwtPicker::trackerPosition() const { return d_data->trackerPosition; } /*! Calculate the bounding rectangle for the tracker text from the current position of the tracker \param font Font of the tracker text \return Bounding rectangle of the tracker text \sa trackerPosition() */ QRect QwtPicker::trackerRect( const QFont &font ) const { if ( trackerMode() == AlwaysOff || ( trackerMode() == ActiveOnly && !isActive() ) ) { return QRect(); } if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) return QRect(); QwtText text = trackerText( d_data->trackerPosition ); if ( text.isEmpty() ) return QRect(); const QSizeF textSize = text.textSize( font ); QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) ); const QPoint &pos = d_data->trackerPosition; int alignment = 0; if ( isActive() && d_data->pickedPoints.count() > 1 && rubberBand() != NoRubberBand ) { const QPoint last = d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2]; alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft; alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop; } else alignment = Qt::AlignTop | Qt::AlignRight; const int margin = 5; int x = pos.x(); if ( alignment & Qt::AlignLeft ) x -= textRect.width() + margin; else if ( alignment & Qt::AlignRight ) x += margin; int y = pos.y(); if ( alignment & Qt::AlignBottom ) y += margin; else if ( alignment & Qt::AlignTop ) y -= textRect.height() + margin; textRect.moveTopLeft( QPoint( x, y ) ); const QRect pickRect = pickArea().boundingRect().toRect(); int right = qMin( textRect.right(), pickRect.right() - margin ); int bottom = qMin( textRect.bottom(), pickRect.bottom() - margin ); textRect.moveBottomRight( QPoint( right, bottom ) ); int left = qMax( textRect.left(), pickRect.left() + margin ); int top = qMax( textRect.top(), pickRect.top() + margin ); textRect.moveTopLeft( QPoint( left, top ) ); return textRect; } /*! \brief Event filter When isEnabled() is true all events of the observed widget are filtered. Mouse and keyboard events are translated into widgetMouse- and widgetKey- and widgetWheel-events. Paint and Resize events are handled to keep rubber band and tracker up to date. \param object Object to be filtered \param event Event \return Always false. \sa widgetEnterEvent(), widgetLeaveEvent(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent(), QObject::installEventFilter(), QObject::event() */ bool QwtPicker::eventFilter( QObject *object, QEvent *event ) { if ( object && object == parentWidget() ) { switch ( event->type() ) { case QEvent::Resize: { const QResizeEvent *re = static_cast( event ); if ( d_data->resizeMode == Stretch ) stretchSelection( re->oldSize(), re->size() ); break; } case QEvent::Enter: { widgetEnterEvent( event ); break; } case QEvent::Leave: { widgetLeaveEvent( event ); break; } case QEvent::MouseButtonPress: { widgetMousePressEvent( static_cast( event ) ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( static_cast( event ) ); break; } case QEvent::MouseButtonDblClick: { widgetMouseDoubleClickEvent( static_cast( event ) ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( static_cast( event ) ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( static_cast( event ) ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( static_cast( event ) ); break; } case QEvent::Wheel: { widgetWheelEvent( static_cast( event ) ); break; } default: break; } } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( pickArea().contains( mouseEvent->pos() ) ) d_data->trackerPosition = mouseEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); transition( mouseEvent ); } /*! Handle a enter event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetEnterEvent( QEvent *event ) { transition( event ); } /*! Handle a leave event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetLeaveEvent( QEvent *event ) { transition( event ); d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle mouse double click event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a wheel event for the observed widget. Move the last point of the selection in case of isActive() == true \param wheelEvent Wheel event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent ) { if ( pickArea().contains( wheelEvent->pos() ) ) d_data->trackerPosition = wheelEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); updateDisplay(); transition( wheelEvent ); } /*! Handle a key press event for the observed widget. Selections can be completely done by the keyboard. The arrow keys move the cursor, the abort key aborts a selection. All other keys are handled by the current state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyReleaseEvent(), stateMachine(), QwtEventPattern::KeyPatternCode */ void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent ) { int dx = 0; int dy = 0; int offset = 1; if ( keyEvent->isAutoRepeat() ) offset = 5; if ( keyMatch( KeyLeft, keyEvent ) ) dx = -offset; else if ( keyMatch( KeyRight, keyEvent ) ) dx = offset; else if ( keyMatch( KeyUp, keyEvent ) ) dy = -offset; else if ( keyMatch( KeyDown, keyEvent ) ) dy = offset; else if ( keyMatch( KeyAbort, keyEvent ) ) { reset(); } else transition( keyEvent ); if ( dx != 0 || dy != 0 ) { const QRect rect = pickArea().boundingRect().toRect(); const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() ); int x = pos.x() + dx; x = qMax( rect.left(), x ); x = qMin( rect.right(), x ); int y = pos.y() + dy; y = qMax( rect.top(), y ); y = qMin( rect.bottom(), y ); QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) ); } } /*! Handle a key release event for the observed widget. Passes the event to the state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), stateMachine() */ void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { transition( keyEvent ); } /*! Passes an event to the state machine and executes the resulting commands. Append and Move commands use the current position of the cursor ( QCursor::pos() ). \param event Event */ void QwtPicker::transition( const QEvent *event ) { if ( !d_data->stateMachine ) return; const QList commandList = d_data->stateMachine->transition( *this, event ); QPoint pos; switch ( event->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { const QMouseEvent *me = static_cast< const QMouseEvent * >( event ); pos = me->pos(); break; } default: pos = parentWidget()->mapFromGlobal( QCursor::pos() ); } for ( int i = 0; i < commandList.count(); i++ ) { switch ( commandList[i] ) { case QwtPickerMachine::Begin: { begin(); break; } case QwtPickerMachine::Append: { append( pos ); break; } case QwtPickerMachine::Move: { move( pos ); break; } case QwtPickerMachine::Remove: { remove(); break; } case QwtPickerMachine::End: { end(); break; } } } } /*! Open a selection setting the state to active \sa isActive(), end(), append(), move() */ void QwtPicker::begin() { if ( d_data->isActive ) return; d_data->pickedPoints.resize( 0 ); d_data->isActive = true; Q_EMIT activated( true ); if ( trackerMode() != AlwaysOff ) { if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) { QWidget *w = parentWidget(); if ( w ) d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() ); } } updateDisplay(); setMouseTracking( true ); } /*! \brief Close a selection setting the state to inactive. The selection is validated and maybe fixed by accept(). \param ok If true, complete the selection and emit a selected signal otherwise discard the selection. \return true if the selection is accepted, false otherwise \sa isActive(), begin(), append(), move(), selected(), accept() */ bool QwtPicker::end( bool ok ) { if ( d_data->isActive ) { setMouseTracking( false ); d_data->isActive = false; Q_EMIT activated( false ); if ( trackerMode() == ActiveOnly ) d_data->trackerPosition = QPoint( -1, -1 ); if ( ok ) ok = accept( d_data->pickedPoints ); if ( ok ) Q_EMIT selected( d_data->pickedPoints ); else d_data->pickedPoints.resize( 0 ); updateDisplay(); } else ok = false; return ok; } /*! Reset the state machine and terminate ( end(false) ) the selection */ void QwtPicker::reset() { if ( d_data->stateMachine ) d_data->stateMachine->reset(); if ( isActive() ) end( false ); } /*! Append a point to the selection and update rubber band and tracker. The appended() signal is emitted. \param pos Additional point \sa isActive(), begin(), end(), move(), appended() */ void QwtPicker::append( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count(); d_data->pickedPoints.resize( idx + 1 ); d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT appended( pos ); } } /*! Move the last point of the selection The moved() signal is emitted. \param pos New position \sa isActive(), begin(), end(), append() */ void QwtPicker::move( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx >= 0 ) { if ( d_data->pickedPoints[idx] != pos ) { d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT moved( pos ); } } } } /*! Remove the last point of the selection The removed() signal is emitted. \sa isActive(), begin(), end(), append(), move() */ void QwtPicker::remove() { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx > 0 ) { const int idx = d_data->pickedPoints.count(); const QPoint pos = d_data->pickedPoints[idx - 1]; d_data->pickedPoints.resize( idx - 1 ); updateDisplay(); Q_EMIT removed( pos ); } } } /*! \brief Validate and fix up the selection Accepts all selections unmodified \param selection Selection to validate and fix up \return true, when accepted, false otherwise */ bool QwtPicker::accept( QPolygon &selection ) const { Q_UNUSED( selection ); return true; } /*! A picker is active between begin() and end(). \return true if the selection is active. */ bool QwtPicker::isActive() const { return d_data->isActive; } /*! Return the points, that have been collected so far. The selection() is calculated from the pickedPoints() in adjustedPoints(). \return Picked points */ const QPolygon &QwtPicker::pickedPoints() const { return d_data->pickedPoints; } /*! Scale the selection by the ratios of oldSize and newSize The changed() signal is emitted. \param oldSize Previous size \param newSize Current size \sa ResizeMode, setResizeMode(), resizeMode() */ void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize ) { if ( oldSize.isEmpty() ) { // avoid division by zero. But scaling for small sizes also // doesn't make much sense, because of rounding losses. TODO ... return; } const double xRatio = double( newSize.width() ) / double( oldSize.width() ); const double yRatio = double( newSize.height() ) / double( oldSize.height() ); for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ ) { QPoint &p = d_data->pickedPoints[i]; p.setX( qRound( p.x() * xRatio ) ); p.setY( qRound( p.y() * yRatio ) ); Q_EMIT changed( d_data->pickedPoints ); } } /*! Set mouse tracking for the observed widget. In case of enable is true, the previous value is saved, that is restored when enable is false. \warning Even when enable is false, mouse tracking might be restored to true. When mouseTracking for the observed widget has been changed directly by QWidget::setMouseTracking while mouse tracking has been set to true, this value can't be restored. */ void QwtPicker::setMouseTracking( bool enable ) { QWidget *widget = parentWidget(); if ( !widget ) return; if ( enable ) { d_data->mouseTracking = widget->hasMouseTracking(); widget->setMouseTracking( true ); } else { widget->setMouseTracking( d_data->mouseTracking ); } } /*! Find the area of the observed widget, where selection might happen. \return parentWidget()->contentsRect() */ QPainterPath QwtPicker::pickArea() const { QPainterPath path; const QWidget *widget = parentWidget(); if ( widget ) path.addRect( widget->contentsRect() ); return path; } //! Update the state of rubber band and tracker label void QwtPicker::updateDisplay() { QWidget *w = parentWidget(); bool showRubberband = false; bool showTracker = false; if ( w && w->isVisible() && d_data->enabled ) { if ( rubberBand() != NoRubberBand && isActive() && rubberBandPen().style() != Qt::NoPen ) { showRubberband = true; } if ( trackerMode() == AlwaysOn || ( trackerMode() == ActiveOnly && isActive() ) ) { if ( trackerPen() != Qt::NoPen && !trackerRect( QFont() ).isEmpty() ) { showTracker = true; } } } QPointer< QwtPickerRubberband > &rw = d_data->rubberBandOverlay; if ( showRubberband ) { if ( rw.isNull() ) { rw = new QwtPickerRubberband( this, w ); rw->setObjectName( "PickerRubberBand" ); rw->resize( w->size() ); } if ( d_data->rubberBand <= RectRubberBand ) rw->setMaskMode( QwtWidgetOverlay::MaskHint ); else rw->setMaskMode( QwtWidgetOverlay::AlphaMask ); rw->updateOverlay(); } else { if ( d_data->openGL ) { // Qt 4.8 crashes for a delete if ( !rw.isNull() ) { rw->hide(); rw->deleteLater(); rw = NULL; } } else { delete rw; } } QPointer< QwtPickerTracker > &tw = d_data->trackerOverlay; if ( showTracker ) { if ( tw.isNull() ) { tw = new QwtPickerTracker( this, w ); tw->setObjectName( "PickerTracker" ); tw->resize( w->size() ); } tw->setFont( d_data->trackerFont ); tw->updateOverlay(); } else { if ( d_data->openGL ) { // Qt 4.8 crashes for a delete if ( !tw.isNull() ) { tw->hide(); tw->deleteLater(); tw = NULL; } } else { delete tw; } } } //! \return Overlay displaying the rubber band const QwtWidgetOverlay *QwtPicker::rubberBandOverlay() const { return d_data->rubberBandOverlay; } //! \return Overlay displaying the tracker text const QwtWidgetOverlay *QwtPicker::trackerOverlay() const { return d_data->trackerOverlay; } qsstv_8.2.12/qwt/qwt_analog_clock.cpp000664 001750 001750 00000013322 12440612574 017622 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_analog_clock.h" #include "qwt_round_scale_draw.h" #include #include class QwtAnalogClockScaleDraw: public QwtRoundScaleDraw { public: QwtAnalogClockScaleDraw() { setSpacing( 8 ); enableComponent( QwtAbstractScaleDraw::Backbone, false ); setTickLength( QwtScaleDiv::MinorTick, 2 ); setTickLength( QwtScaleDiv::MediumTick, 4 ); setTickLength( QwtScaleDiv::MajorTick, 8 ); setPenWidth( 1 ); } virtual QwtText label( double value ) const { if ( qFuzzyCompare( value + 1.0, 1.0 ) ) value = 60.0 * 60.0 * 12.0; return QLocale().toString( qRound( value / ( 60.0 * 60.0 ) ) ); } }; /*! Constructor \param parent Parent widget */ QwtAnalogClock::QwtAnalogClock( QWidget *parent ): QwtDial( parent ) { setWrapping( true ); setReadOnly( true ); setOrigin( 270.0 ); setScaleDraw( new QwtAnalogClockScaleDraw() ); setTotalSteps( 60 ); const int secondsPerHour = 60.0 * 60.0; QList majorTicks; QList minorTicks; for ( int i = 0; i < 12; i++ ) { majorTicks += i * secondsPerHour; for ( int j = 1; j < 5; j++ ) minorTicks += i * secondsPerHour + j * secondsPerHour / 5.0; } QwtScaleDiv scaleDiv; scaleDiv.setInterval( 0.0, 12.0 * secondsPerHour ); scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks ); scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks ); setScale( scaleDiv ); QColor knobColor = palette().color( QPalette::Active, QPalette::Text ); knobColor = knobColor.dark( 120 ); QColor handColor; int width; for ( int i = 0; i < NHands; i++ ) { if ( i == SecondHand ) { width = 2; handColor = knobColor.dark( 120 ); } else { width = 8; handColor = knobColor; } QwtDialSimpleNeedle *hand = new QwtDialSimpleNeedle( QwtDialSimpleNeedle::Arrow, true, handColor, knobColor ); hand->setWidth( width ); d_hand[i] = NULL; setHand( static_cast( i ), hand ); } } //! Destructor QwtAnalogClock::~QwtAnalogClock() { for ( int i = 0; i < NHands; i++ ) delete d_hand[i]; } /*! Nop method, use setHand() instead \sa setHand() */ void QwtAnalogClock::setNeedle( QwtDialNeedle * ) { // no op return; } /*! Set a clock hand \param hand Specifies the type of hand \param needle Hand \sa hand() */ void QwtAnalogClock::setHand( Hand hand, QwtDialNeedle *needle ) { if ( hand >= 0 && hand < NHands ) { delete d_hand[hand]; d_hand[hand] = needle; } } /*! \return Clock hand \param hd Specifies the type of hand \sa setHand() */ QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) { if ( hd < 0 || hd >= NHands ) return NULL; return d_hand[hd]; } /*! \return Clock hand \param hd Specifies the type of hand \sa setHand() */ const QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) const { return const_cast( this )->hand( hd ); } /*! \brief Set the current time */ void QwtAnalogClock::setCurrentTime() { setTime( QTime::currentTime() ); } /*! Set a time \param time Time to display */ void QwtAnalogClock::setTime( const QTime &time ) { if ( time.isValid() ) { setValue( ( time.hour() % 12 ) * 60.0 * 60.0 + time.minute() * 60.0 + time.second() ); } else setValid( false ); } /*! \brief Draw the needle A clock has no single needle but three hands instead. drawNeedle() translates value() into directions for the hands and calls drawHand(). \param painter Painter \param center Center of the clock \param radius Maximum length for the hands \param dir Dummy, not used. \param colorGroup ColorGroup \sa drawHand() */ void QwtAnalogClock::drawNeedle( QPainter *painter, const QPointF ¢er, double radius, double dir, QPalette::ColorGroup colorGroup ) const { Q_UNUSED( dir ); if ( isValid() ) { const double hours = value() / ( 60.0 * 60.0 ); const double minutes = ( value() - qFloor(hours) * 60.0 * 60.0 ) / 60.0; const double seconds = value() - qFloor(hours) * 60.0 * 60.0 - qFloor(minutes) * 60.0; double angle[NHands]; angle[HourHand] = 360.0 * hours / 12.0; angle[MinuteHand] = 360.0 * minutes / 60.0; angle[SecondHand] = 360.0 * seconds / 60.0; for ( int hand = 0; hand < NHands; hand++ ) { const double d = 360.0 - angle[hand] - origin(); drawHand( painter, static_cast( hand ), center, radius, d, colorGroup ); } } } /*! Draw a clock hand \param painter Painter \param hd Specify the type of hand \param center Center of the clock \param radius Maximum length for the hands \param direction Direction of the hand in degrees, counter clockwise \param cg ColorGroup */ void QwtAnalogClock::drawHand( QPainter *painter, Hand hd, const QPointF ¢er, double radius, double direction, QPalette::ColorGroup cg ) const { const QwtDialNeedle *needle = hand( hd ); if ( needle ) { if ( hd == HourHand ) radius = qRound( 0.8 * radius ); needle->draw( painter, center, radius, direction, cg ); } } qsstv_8.2.12/qwt/qwt_picker.h000664 001750 001750 00000022476 12440612574 016142 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER #define QWT_PICKER 1 #include "qwt_global.h" #include "qwt_text.h" #include "qwt_event_pattern.h" #include #include #include #include #include class QWidget; class QMouseEvent; class QWheelEvent; class QKeyEvent; class QwtPickerMachine; class QwtWidgetOverlay; /*! \brief QwtPicker provides selections on a widget QwtPicker filters all enter, leave, mouse and keyboard events of a widget and translates them into an array of selected points. The way how the points are collected depends on type of state machine that is connected to the picker. Qwt offers a couple of predefined state machines for selecting: - Nothing\n QwtPickerTrackerMachine - Single points\n QwtPickerClickPointMachine, QwtPickerDragPointMachine - Rectangles\n QwtPickerClickRectMachine, QwtPickerDragRectMachine - Polygons\n QwtPickerPolygonMachine While these state machines cover the most common ways to collect points it is also possible to implement individual machines as well. QwtPicker translates the picked points into a selection using the adjustedPoints() method. adjustedPoints() is intended to be reimplemented to fix up the selection according to application specific requirements. (F.e. when an application accepts rectangles of a fixed aspect ratio only.) Optionally QwtPicker support the process of collecting points by a rubber band and tracker displaying a text for the current mouse position. \par Example \verbatim #include #include QwtPicker *picker = new QwtPicker(widget); picker->setStateMachine(new QwtPickerDragRectMachine); picker->setTrackerMode(QwtPicker::ActiveOnly); picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n The state machine triggers the following commands: - begin()\n Activate/Initialize the selection. - append()\n Add a new point - move() \n Change the position of the last point. - remove()\n Remove the last point. - end()\n Terminate the selection and call accept to validate the picked points. The picker is active (isActive()), between begin() and end(). In active state the rubber band is displayed, and the tracker is visible in case of trackerMode is ActiveOnly or AlwaysOn. The cursor can be moved using the arrow keys. All selections can be aborted using the abort key. (QwtEventPattern::KeyPatternCode) \warning In case of QWidget::NoFocus the focus policy of the observed widget is set to QWidget::WheelFocus and mouse tracking will be manipulated while the picker is active, or if trackerMode() is AlwayOn. */ class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern { Q_OBJECT Q_ENUMS( RubberBand DisplayMode ResizeMode ) Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled ) Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode ) Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode ) Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen ) Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont ) Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand ) Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen ) public: /*! Rubber band style The default value is QwtPicker::NoRubberBand. \sa setRubberBand(), rubberBand() */ enum RubberBand { //! No rubberband. NoRubberBand = 0, //! A horizontal line ( only for QwtPickerMachine::PointSelection ) HLineRubberBand, //! A vertical line ( only for QwtPickerMachine::PointSelection ) VLineRubberBand, //! A crosshair ( only for QwtPickerMachine::PointSelection ) CrossRubberBand, //! A rectangle ( only for QwtPickerMachine::RectSelection ) RectRubberBand, //! An ellipse ( only for QwtPickerMachine::RectSelection ) EllipseRubberBand, //! A polygon ( only for QwtPickerMachine::PolygonSelection ) PolygonRubberBand, /*! Values >= UserRubberBand can be used to define additional rubber bands. */ UserRubberBand = 100 }; /*! \brief Display mode \sa setTrackerMode(), trackerMode(), isActive() */ enum DisplayMode { //! Display never AlwaysOff, //! Display always AlwaysOn, //! Display only when the selection is active ActiveOnly }; /*! Controls what to do with the selected points of an active selection when the observed widget is resized. The default value is QwtPicker::Stretch. \sa setResizeMode() */ enum ResizeMode { //! All points are scaled according to the new size, Stretch, //! All points remain unchanged. KeepSize }; explicit QwtPicker( QWidget *parent ); explicit QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget * ); virtual ~QwtPicker(); void setStateMachine( QwtPickerMachine * ); const QwtPickerMachine *stateMachine() const; QwtPickerMachine *stateMachine(); void setRubberBand( RubberBand ); RubberBand rubberBand() const; void setTrackerMode( DisplayMode ); DisplayMode trackerMode() const; void setResizeMode( ResizeMode ); ResizeMode resizeMode() const; void setRubberBandPen( const QPen & ); QPen rubberBandPen() const; void setTrackerPen( const QPen & ); QPen trackerPen() const; void setTrackerFont( const QFont & ); QFont trackerFont() const; bool isEnabled() const; bool isActive() const; virtual bool eventFilter( QObject *, QEvent * ); QWidget *parentWidget(); const QWidget *parentWidget() const; virtual QPainterPath pickArea() const; virtual void drawRubberBand( QPainter * ) const; virtual void drawTracker( QPainter * ) const; virtual QRegion rubberBandMask() const; virtual QwtText trackerText( const QPoint &pos ) const; QPoint trackerPosition() const; virtual QRect trackerRect( const QFont & ) const; QPolygon selection() const; public Q_SLOTS: void setEnabled( bool ); Q_SIGNALS: /*! A signal indicating, when the picker has been activated. Together with setEnabled() it can be used to implement selections with more than one picker. \param on True, when the picker has been activated */ void activated( bool on ); /*! A signal emitting the selected points, at the end of a selection. \param polygon Selected points */ void selected( const QPolygon &polygon ); /*! A signal emitted when a point has been appended to the selection \param pos Position of the appended point. \sa append(). moved() */ void appended( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been moved. \param pos Position of the moved last point of the selection. \sa move(), appended() */ void moved( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been removed. \param pos Position of the point, that has been removed \sa remove(), appended() */ void removed( const QPoint &pos ); /*! A signal emitted when the active selection has been changed. This might happen when the observed widget is resized. \param selection Changed selection \sa stretchSelection() */ void changed( const QPolygon &selection ); protected: virtual QPolygon adjustedPoints( const QPolygon & ) const; virtual void transition( const QEvent * ); virtual void begin(); virtual void append( const QPoint & ); virtual void move( const QPoint & ); virtual void remove(); virtual bool end( bool ok = true ); virtual bool accept( QPolygon & ) const; virtual void reset(); virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseDoubleClickEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetWheelEvent( QWheelEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void widgetEnterEvent( QEvent * ); virtual void widgetLeaveEvent( QEvent * ); virtual void stretchSelection( const QSize &oldSize, const QSize &newSize ); virtual void updateDisplay(); const QwtWidgetOverlay *rubberBandOverlay() const; const QwtWidgetOverlay *trackerOverlay() const; const QPolygon &pickedPoints() const; private: void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode ); void setMouseTracking( bool ); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_analog_clock.h000664 001750 001750 00000004171 12440612574 017271 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ANALOG_CLOCK_H #define QWT_ANALOG_CLOCK_H #include "qwt_global.h" #include "qwt_dial.h" #include "qwt_dial_needle.h" #include /*! \brief An analog clock \image html analogclock.png \par Example \code #include QwtAnalogClock *clock = new QwtAnalogClock(...); clock->scaleDraw()->setPenWidth(3); clock->setLineWidth(6); clock->setFrameShadow(QwtDial::Sunken); clock->setTime(); // update the clock every second QTimer *timer = new QTimer(clock); timer->connect(timer, SIGNAL(timeout()), clock, SLOT(setCurrentTime())); timer->start(1000); \endcode \note The examples/dials example shows how to use QwtAnalogClock. */ class QWT_EXPORT QwtAnalogClock: public QwtDial { Q_OBJECT public: /*! Hand type \sa setHand(), hand() */ enum Hand { //! Needle displaying the seconds SecondHand, //! Needle displaying the minutes MinuteHand, //! Needle displaying the hours HourHand, //! Number of needles NHands }; explicit QwtAnalogClock( QWidget* parent = NULL ); virtual ~QwtAnalogClock(); void setHand( Hand, QwtDialNeedle * ); const QwtDialNeedle *hand( Hand ) const; QwtDialNeedle *hand( Hand ); public Q_SLOTS: void setCurrentTime(); void setTime( const QTime & ); protected: virtual void drawNeedle( QPainter *, const QPointF &, double radius, double direction, QPalette::ColorGroup ) const; virtual void drawHand( QPainter *, Hand, const QPointF &, double radius, double direction, QPalette::ColorGroup ) const; private: // use setHand instead void setNeedle( QwtDialNeedle * ); QwtDialNeedle *d_hand[NHands]; }; #endif qsstv_8.2.12/qwt/qwt_picker_machine.cpp000664 001750 001750 00000032001 12440612574 020142 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker_machine.h" #include "qwt_event_pattern.h" #include //! Constructor QwtPickerMachine::QwtPickerMachine( SelectionType type ): d_selectionType( type ), d_state( 0 ) { } //! Destructor QwtPickerMachine::~QwtPickerMachine() { } //! Return the selection type QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const { return d_selectionType; } //! Return the current state int QwtPickerMachine::state() const { return d_state; } //! Change the current state void QwtPickerMachine::setState( int state ) { d_state = state; } //! Set the current state to 0. void QwtPickerMachine::reset() { setState( 0 ); } //! Constructor QwtPickerTrackerMachine::QwtPickerTrackerMachine(): QwtPickerMachine( NoSelection ) { } //! Transition QList QwtPickerTrackerMachine::transition( const QwtEventPattern &, const QEvent *e ) { QList cmdList; switch ( e->type() ) { case QEvent::Enter: case QEvent::MouseMove: { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += Move; } break; } case QEvent::Leave: { cmdList += Remove; cmdList += End; setState( 0 ); } default: break; } return cmdList; } //! Constructor QwtPickerClickPointMachine::QwtPickerClickPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerClickPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { cmdList += Begin; cmdList += Append; cmdList += End; } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { cmdList += Begin; cmdList += Append; cmdList += End; } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragPointMachine::QwtPickerDragPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerDragPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() != 0 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerClickRectMachine::QwtPickerClickRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerClickRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { switch ( state() ) { case 0: { cmdList += Begin; cmdList += Append; setState( 1 ); break; } case 1: { // Uh, strange we missed the MouseButtonRelease break; } default: { cmdList += End; setState( 0 ); } } } } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } else if ( state() == 2 ) { cmdList += End; setState( 0 ); } } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragRectMachine::QwtPickerDragRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerDragRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() == 2 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } else { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerPolygonMachine::QwtPickerPolygonMachine(): QwtPickerMachine( PolygonSelection ) { } //! Transition QList QwtPickerPolygonMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect2, static_cast( event ) ) ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } else if ( eventPattern.keyMatch( QwtEventPattern::KeySelect2, static_cast ( event ) ) ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragLineMachine::QwtPickerDragLineMachine(): QwtPickerMachine( PolygonSelection ) { } //! Transition QList QwtPickerDragLineMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += End; setState( 0 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() != 0 ) { cmdList += End; setState( 0 ); } } default: break; } return cmdList; } qsstv_8.2.12/qwt/qwt_arrow_button.cpp000664 001750 001750 00000020202 12440612574 017726 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_arrow_button.h" #include "qwt_math.h" #include #include #include #include #include static const int MaxNum = 3; static const int Margin = 2; static const int Spacing = 1; class QwtArrowButton::PrivateData { public: int num; Qt::ArrowType arrowType; }; static QStyleOptionButton styleOpt( const QwtArrowButton* btn ) { QStyleOptionButton option; option.init( btn ); option.features = QStyleOptionButton::None; if ( btn->isFlat() ) option.features |= QStyleOptionButton::Flat; if ( btn->menu() ) option.features |= QStyleOptionButton::HasMenu; if ( btn->autoDefault() || btn->isDefault() ) option.features |= QStyleOptionButton::AutoDefaultButton; if ( btn->isDefault() ) option.features |= QStyleOptionButton::DefaultButton; if ( btn->isDown() ) option.state |= QStyle::State_Sunken; if ( !btn->isFlat() && !btn->isDown() ) option.state |= QStyle::State_Raised; return option; } /*! \param num Number of arrows \param arrowType see Qt::ArrowType in the Qt docs. \param parent Parent widget */ QwtArrowButton::QwtArrowButton( int num, Qt::ArrowType arrowType, QWidget *parent ): QPushButton( parent ) { d_data = new PrivateData; d_data->num = qBound( 1, num, MaxNum ); d_data->arrowType = arrowType; setAutoRepeat( true ); setAutoDefault( false ); switch ( d_data->arrowType ) { case Qt::LeftArrow: case Qt::RightArrow: setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); break; default: setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); } } //! Destructor QwtArrowButton::~QwtArrowButton() { delete d_data; d_data = NULL; } /*! \brief The direction of the arrows */ Qt::ArrowType QwtArrowButton::arrowType() const { return d_data->arrowType; } /*! \brief The number of arrows */ int QwtArrowButton::num() const { return d_data->num; } /*! \return the bounding rectangle for the label */ QRect QwtArrowButton::labelRect() const { const int m = Margin; QRect r = rect(); r.setRect( r.x() + m, r.y() + m, r.width() - 2 * m, r.height() - 2 * m ); if ( isDown() ) { QStyleOptionButton option = styleOpt( this ); const int ph = style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &option, this ); const int pv = style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &option, this ); r.translate( ph, pv ); } return r; } /*! Paint event handler \param event Paint event */ void QwtArrowButton::paintEvent( QPaintEvent *event ) { QPushButton::paintEvent( event ); QPainter painter( this ); drawButtonLabel( &painter ); } /*! \brief Draw the button label \param painter Painter \sa The Qt Manual for QPushButton */ void QwtArrowButton::drawButtonLabel( QPainter *painter ) { const bool isVertical = d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow; const QRect r = labelRect(); QSize boundingSize = labelRect().size(); if ( isVertical ) boundingSize.transpose(); const int w = ( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum; QSize arrow = arrowSize( Qt::RightArrow, QSize( w, boundingSize.height() ) ); if ( isVertical ) arrow.transpose(); QRect contentsSize; // aligned rect where to paint all arrows if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow ) { contentsSize.setWidth( d_data->num * arrow.width() + ( d_data->num - 1 ) * Spacing ); contentsSize.setHeight( arrow.height() ); } else { contentsSize.setWidth( arrow.width() ); contentsSize.setHeight( d_data->num * arrow.height() + ( d_data->num - 1 ) * Spacing ); } QRect arrowRect( contentsSize ); arrowRect.moveCenter( r.center() ); arrowRect.setSize( arrow ); painter->save(); for ( int i = 0; i < d_data->num; i++ ) { drawArrow( painter, arrowRect, d_data->arrowType ); int dx = 0; int dy = 0; if ( isVertical ) dy = arrow.height() + Spacing; else dx = arrow.width() + Spacing; arrowRect.translate( dx, dy ); } painter->restore(); if ( hasFocus() ) { QStyleOptionFocusRect option; option.init( this ); option.backgroundColor = palette().color( QPalette::Window ); style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, painter, this ); } } /*! Draw an arrow int a bounding rectangle \param painter Painter \param r Rectangle where to paint the arrow \param arrowType Arrow type */ void QwtArrowButton::drawArrow( QPainter *painter, const QRect &r, Qt::ArrowType arrowType ) const { QPolygon pa( 3 ); switch ( arrowType ) { case Qt::UpArrow: pa.setPoint( 0, r.bottomLeft() ); pa.setPoint( 1, r.bottomRight() ); pa.setPoint( 2, r.center().x(), r.top() ); break; case Qt::DownArrow: pa.setPoint( 0, r.topLeft() ); pa.setPoint( 1, r.topRight() ); pa.setPoint( 2, r.center().x(), r.bottom() ); break; case Qt::RightArrow: pa.setPoint( 0, r.topLeft() ); pa.setPoint( 1, r.bottomLeft() ); pa.setPoint( 2, r.right(), r.center().y() ); break; case Qt::LeftArrow: pa.setPoint( 0, r.topRight() ); pa.setPoint( 1, r.bottomRight() ); pa.setPoint( 2, r.left(), r.center().y() ); break; default: break; } painter->save(); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( QPalette::ButtonText ) ); painter->drawPolygon( pa ); painter->restore(); } /*! \return a size hint */ QSize QwtArrowButton::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint */ QSize QwtArrowButton::minimumSizeHint() const { const QSize asz = arrowSize( Qt::RightArrow, QSize() ); QSize sz( 2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(), 2 * Margin + asz.height() ); if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow ) sz.transpose(); QStyleOption styleOption; styleOption.init( this ); sz = style()->sizeFromContents( QStyle::CT_PushButton, &styleOption, sz, this ); return sz; } /*! Calculate the size for a arrow that fits into a rectangle of a given size \param arrowType Arrow type \param boundingSize Bounding size \return Size of the arrow */ QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType, const QSize &boundingSize ) const { QSize bs = boundingSize; if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) bs.transpose(); const int MinLen = 2; const QSize sz = bs.expandedTo( QSize( MinLen, 2 * MinLen - 1 ) ); // minimum int w = sz.width(); int h = 2 * w - 1; if ( h > sz.height() ) { h = sz.height(); w = ( h + 1 ) / 2; } QSize arrSize( w, h ); if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) arrSize.transpose(); return arrSize; } /*! \brief autoRepeat for the space keys */ void QwtArrowButton::keyPressEvent( QKeyEvent *event ) { if ( event->isAutoRepeat() && event->key() == Qt::Key_Space ) Q_EMIT clicked(); QPushButton::keyPressEvent( event ); } qsstv_8.2.12/qwt/qwt_picker_machine.h000664 001750 001750 00000013136 12440612574 017617 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER_MACHINE #define QWT_PICKER_MACHINE 1 #include "qwt_global.h" #include class QEvent; class QwtEventPattern; /*! \brief A state machine for QwtPicker selections QwtPickerMachine accepts key and mouse events and translates them into selection commands. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerMachine { public: /*! Type of a selection. \sa selectionType() */ enum SelectionType { //! The state machine not usable for any type of selection. NoSelection = -1, //! The state machine is for selecting a single point. PointSelection, //! The state machine is for selecting a rectangle (2 points). RectSelection, //! The state machine is for selecting a polygon (many points). PolygonSelection }; //! Commands - the output of a state machine enum Command { Begin, Append, Move, Remove, End }; QwtPickerMachine( SelectionType ); virtual ~QwtPickerMachine(); //! Transition virtual QList transition( const QwtEventPattern &, const QEvent * ) = 0; void reset(); int state() const; void setState( int ); SelectionType selectionType() const; private: const SelectionType d_selectionType; int d_state; }; /*! \brief A state machine for indicating mouse movements QwtPickerTrackerMachine supports displaying information corresponding to mouse movements, but is not intended for selecting anything. Begin/End are related to Enter/Leave events. */ class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine { public: QwtPickerTrackerMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 selects a point. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine { public: QwtPickerClickPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection, releasing QwtEventPattern::MouseSelect1 or a second press of QwtEventPattern::KeySelect1 terminates it. */ class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine { public: QwtPickerDragPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 starts the selection, releasing it selects the first point. Pressing it again selects the second point and terminates the selection. Pressing QwtEventPattern::KeySelect1 also starts the selection, a second press selects the first point. A third one selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine { public: QwtPickerClickRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 selects the first point, releasing it the second point. Pressing QwtEventPattern::KeySelect1 also selects the first point, a second press selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine { public: QwtPickerDragRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for line selections Pressing QwtEventPattern::MouseSelect1 selects the first point, releasing it the second point. Pressing QwtEventPattern::KeySelect1 also selects the first point, a second press selects the second point and terminates the selection. A common use case of QwtPickerDragLineMachine are pickers for distance measurements. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerDragLineMachine: public QwtPickerMachine { public: QwtPickerDragLineMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for polygon selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection and selects the first point, or appends a point. Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2 appends the last point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine { public: QwtPickerPolygonMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; #endif qsstv_8.2.12/qwt/qwt_arrow_button.h000664 001750 001750 00000002621 12440612574 017400 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ARROW_BUTTON_H #define QWT_ARROW_BUTTON_H #include "qwt_global.h" #include /*! \brief Arrow Button A push button with one or more filled triangles on its front. An Arrow button can have 1 to 3 arrows in a row, pointing up, down, left or right. */ class QWT_EXPORT QwtArrowButton : public QPushButton { public: explicit QwtArrowButton ( int num, Qt::ArrowType, QWidget *parent = NULL ); virtual ~QwtArrowButton(); Qt::ArrowType arrowType() const; int num() const; virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; protected: virtual void paintEvent( QPaintEvent *event ); virtual void drawButtonLabel( QPainter *p ); virtual void drawArrow( QPainter *, const QRect &, Qt::ArrowType ) const; virtual QRect labelRect() const; virtual QSize arrowSize( Qt::ArrowType, const QSize &boundingSize ) const; virtual void keyPressEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_pixel_matrix.cpp000664 001750 001750 00000002133 12440612574 017711 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_pixel_matrix.h" /*! \brief Constructor \param rect Bounding rectangle for the matrix */ QwtPixelMatrix::QwtPixelMatrix( const QRect& rect ): QBitArray( qMax( rect.width() * rect.height(), 0 ) ), d_rect( rect ) { } //! Destructor QwtPixelMatrix::~QwtPixelMatrix() { } /*! Set the bounding rectangle of the matrix \param rect Bounding rectangle \note All bits are cleared */ void QwtPixelMatrix::setRect( const QRect& rect ) { if ( rect != d_rect ) { d_rect = rect; const int sz = qMax( rect.width() * rect.height(), 0 ); resize( sz ); } fill( false ); } //! \return Bounding rectangle QRect QwtPixelMatrix::rect() const { return d_rect; } qsstv_8.2.12/qwt/qwt_clipper.cpp000664 001750 001750 00000031010 12440612574 016636 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_clipper.h" #include "qwt_point_polar.h" #include #include #include #if QT_VERSION < 0x040601 #define qAtan(x) ::atan(x) #endif namespace QwtClip { // some templates used for inlining template class LeftEdge; template class RightEdge; template class TopEdge; template class BottomEdge; template class PointBuffer; } template class QwtClip::LeftEdge { public: inline LeftEdge( Value x1, Value, Value, Value ): d_x1( x1 ) { } inline bool isInside( const Point &p ) const { return p.x() >= d_x1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x1, static_cast< Value >( p2.y() + ( d_x1 - p2.x() ) * dy ) ); } private: const Value d_x1; }; template class QwtClip::RightEdge { public: inline RightEdge( Value, Value x2, Value, Value ): d_x2( x2 ) { } inline bool isInside( const Point &p ) const { return p.x() <= d_x2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x2, static_cast( p2.y() + ( d_x2 - p2.x() ) * dy ) ); } private: const Value d_x2; }; template class QwtClip::TopEdge { public: inline TopEdge( Value, Value, Value y1, Value ): d_y1( y1 ) { } inline bool isInside( const Point &p ) const { return p.y() >= d_y1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( static_cast( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 ); } private: const Value d_y1; }; template class QwtClip::BottomEdge { public: inline BottomEdge( Value, Value, Value, Value y2 ): d_y2( y2 ) { } inline bool isInside( const Point &p ) const { return p.y() <= d_y2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( static_cast( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 ); } private: const Value d_y2; }; template class QwtClip::PointBuffer { public: PointBuffer( int capacity = 0 ): m_capacity( 0 ), m_size( 0 ), m_buffer( NULL ) { if ( capacity > 0 ) reserve( capacity ); } ~PointBuffer() { if ( m_buffer ) ::free( m_buffer ); } inline void setPoints( int numPoints, const Point *points ) { reserve( numPoints ); m_size = numPoints; ::memcpy( m_buffer, points, m_size * sizeof( Point ) ); } inline void reset() { m_size = 0; } inline int size() const { return m_size; } inline Point *data() const { return m_buffer; } inline Point &operator[]( int i ) { return m_buffer[i]; } inline const Point &operator[]( int i ) const { return m_buffer[i]; } inline void add( const Point &point ) { if ( m_capacity <= m_size ) reserve( m_size + 1 ); m_buffer[m_size++] = point; } private: inline void reserve( int size ) { if ( m_capacity == 0 ) m_capacity = 1; while ( m_capacity < size ) m_capacity *= 2; m_buffer = static_cast( ::realloc( m_buffer, m_capacity * sizeof( Point ) ) ); } int m_capacity; int m_size; Point *m_buffer; }; using namespace QwtClip; template class QwtPolygonClipper { public: QwtPolygonClipper( const Rect &clipRect ): d_clipRect( clipRect ) { } Polygon clipPolygon( const Polygon &polygon, bool closePolygon ) const { #if 0 if ( d_clipRect.contains( polygon.boundingRect() ) ) return polygon; #endif PointBuffer points1; PointBuffer points2( qMin( 256, polygon.size() ) ); points1.setPoints( polygon.size(), polygon.data() ); clipEdge< LeftEdge >( closePolygon, points1, points2 ); clipEdge< RightEdge >( closePolygon, points2, points1 ); clipEdge< TopEdge >( closePolygon, points1, points2 ); clipEdge< BottomEdge >( closePolygon, points2, points1 ); Polygon p; p.resize( points1.size() ); ::memcpy( p.data(), points1.data(), points1.size() * sizeof( Point ) ); return p; } private: template inline void clipEdge( bool closePolygon, PointBuffer &points, PointBuffer &clippedPoints ) const { clippedPoints.reset(); if ( points.size() < 2 ) { if ( points.size() == 1 ) clippedPoints.add( points[0] ); return; } const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(), d_clipRect.y(), d_clipRect.y() + d_clipRect.height() ); int lastPos, start; if ( closePolygon ) { start = 0; lastPos = points.size() - 1; } else { start = 1; lastPos = 0; if ( edge.isInside( points[0] ) ) clippedPoints.add( points[0] ); } const uint nPoints = points.size(); for ( uint i = start; i < nPoints; i++ ) { const Point &p1 = points[i]; const Point &p2 = points[lastPos]; if ( edge.isInside( p1 ) ) { if ( edge.isInside( p2 ) ) { clippedPoints.add( p1 ); } else { clippedPoints.add( edge.intersection( p1, p2 ) ); clippedPoints.add( p1 ); } } else { if ( edge.isInside( p2 ) ) { clippedPoints.add( edge.intersection( p1, p2 ) ); } } lastPos = i; } } const Rect d_clipRect; }; class QwtCircleClipper { public: QwtCircleClipper( const QRectF &r ); QVector clipCircle( const QPointF &, double radius ) const; private: enum Edge { Left, Top, Right, Bottom, NEdges }; QList cuttingPoints( Edge, const QPointF &pos, double radius ) const; double toAngle( const QPointF &, const QPointF & ) const; const QRectF d_rect; }; QwtCircleClipper::QwtCircleClipper( const QRectF &r ): d_rect( r ) { } QVector QwtCircleClipper::clipCircle( const QPointF &pos, double radius ) const { QList points; for ( int edge = 0; edge < NEdges; edge++ ) points += cuttingPoints( static_cast(edge), pos, radius ); QVector intv; if ( points.size() <= 0 ) { QRectF cRect( 0, 0, 2 * radius, 2 * radius ); cRect.moveCenter( pos ); if ( d_rect.contains( cRect ) ) intv += QwtInterval( 0.0, 2 * M_PI ); } else { QList angles; for ( int i = 0; i < points.size(); i++ ) angles += toAngle( pos, points[i] ); qSort( angles ); const int in = d_rect.contains( qwtPolar2Pos( pos, radius, angles[0] + ( angles[1] - angles[0] ) / 2 ) ); if ( in ) { for ( int i = 0; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); } else { for ( int i = 1; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); intv += QwtInterval( angles.last(), angles.first() ); } } return intv; } double QwtCircleClipper::toAngle( const QPointF &from, const QPointF &to ) const { if ( from.x() == to.x() ) return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0; const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) ); double angle = qAtan( m ); if ( to.x() > from.x() ) { if ( to.y() > from.y() ) angle = 2 * M_PI - angle; } else { if ( to.y() > from.y() ) angle = M_PI + angle; else angle = M_PI - angle; } return angle; } QList QwtCircleClipper::cuttingPoints( Edge edge, const QPointF &pos, double radius ) const { QList points; if ( edge == Left || edge == Right ) { const double x = ( edge == Left ) ? d_rect.left() : d_rect.right(); if ( qAbs( pos.x() - x ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) ); const double m_y1 = pos.y() + off; if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() ) points += QPointF( x, m_y1 ); const double m_y2 = pos.y() - off; if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() ) points += QPointF( x, m_y2 ); } } else { const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom(); if ( qAbs( pos.y() - y ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) ); const double x1 = pos.x() + off; if ( x1 >= d_rect.left() && x1 <= d_rect.right() ) points += QPointF( x1, y ); const double m_x2 = pos.x() - off; if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() ) points += QPointF( m_x2, y ); } } return points; } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygon QwtClipper::clipPolygon( const QRectF &clipRect, const QPolygon &polygon, bool closePolygon ) { const int minX = qCeil( clipRect.left() ); const int maxX = qFloor( clipRect.right() ); const int minY = qCeil( clipRect.top() ); const int maxY = qFloor( clipRect.bottom() ); const QRect r( minX, minY, maxX - minX, maxY - minY ); QwtPolygonClipper clipper( r ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygon QwtClipper::clipPolygon( const QRect &clipRect, const QPolygon &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygonF QwtClipper::clipPolygonF( const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Circle clipping clipCircle() divides a circle into intervals of angles representing arcs of the circle. When the circle is completely inside the clip rectangle an interval [0.0, 2 * M_PI] is returned. \param clipRect Clip rectangle \param center Center of the circle \param radius Radius of the circle \return Arcs of the circle */ QVector QwtClipper::clipCircle( const QRectF &clipRect, const QPointF ¢er, double radius ) { QwtCircleClipper clipper( clipRect ); return clipper.clipCircle( center, radius ); } qsstv_8.2.12/qwt/qwt_plot_item.h000664 001750 001750 00000020233 12440612574 016646 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ITEM_H #define QWT_PLOT_ITEM_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_legend_data.h" #include "qwt_graphic.h" #include #include #include class QPainter; class QwtScaleMap; class QwtScaleDiv; class QwtPlot; /*! \brief Base class for items on the plot canvas A plot item is "something", that can be painted on the plot canvas, or only affects the scales of the plot widget. They can be categorized as: - Representator\n A "Representator" is an item that represents some sort of data on the plot canvas. The different representator classes are organized according to the characteristics of the data: - QwtPlotMarker Represents a point or a horizontal/vertical coordinate - QwtPlotCurve Represents a series of points - QwtPlotSpectrogram ( QwtPlotRasterItem ) Represents raster data - ... - Decorators\n A "Decorator" is an item, that displays additional information, that is not related to any data: - QwtPlotGrid - QwtPlotScaleItem - QwtPlotSvgItem - ... Depending on the QwtPlotItem::ItemAttribute flags, an item is included into autoscaling or has an entry on the legend. Before misusing the existing item classes it might be better to implement a new type of plot item ( don't implement a watermark as spectrogram ). Deriving a new type of QwtPlotItem primarily means to implement the YourPlotItem::draw() method. \sa The cpuplot example shows the implementation of additional plot items. */ class QWT_EXPORT QwtPlotItem { public: /*! \brief Runtime type information RttiValues is used to cast plot items, without having to enable runtime type information of the compiler. */ enum RttiValues { //! Unspecific value, that can be used, when it doesn't matter Rtti_PlotItem = 0, //! For QwtPlotGrid Rtti_PlotGrid, //! For QwtPlotScaleItem Rtti_PlotScale, //! For QwtPlotLegendItem Rtti_PlotLegend, //! For QwtPlotMarker Rtti_PlotMarker, //! For QwtPlotCurve Rtti_PlotCurve, //! For QwtPlotSpectroCurve Rtti_PlotSpectroCurve, //! For QwtPlotIntervalCurve Rtti_PlotIntervalCurve, //! For QwtPlotHistogram Rtti_PlotHistogram, //! For QwtPlotSpectrogram Rtti_PlotSpectrogram, //! For QwtPlotSvgItem Rtti_PlotSVG, //! For QwtPlotTradingCurve Rtti_PlotTradingCurve, //! For QwtPlotBarChart Rtti_PlotBarChart, //! For QwtPlotMultiBarChart Rtti_PlotMultiBarChart, //! For QwtPlotShapeItem Rtti_PlotShape, //! For QwtPlotTextLabel Rtti_PlotTextLabel, //! For QwtPlotZoneItem Rtti_PlotZone, /*! Values >= Rtti_PlotUserItem are reserved for plot items not implemented in the Qwt library. */ Rtti_PlotUserItem = 1000 }; /*! \brief Plot Item Attributes Various aspects of a plot widget depend on the attributes of the attached plot items. If and how a single plot item participates in these updates depends on its attributes. \sa setItemAttribute(), testItemAttribute(), ItemInterest */ enum ItemAttribute { //! The item is represented on the legend. Legend = 0x01, /*! The boundingRect() of the item is included in the autoscaling calculation as long as its width or height is >= 0.0. */ AutoScale = 0x02, /*! The item needs extra space to display something outside its bounding rectangle. \sa getCanvasMarginHint() */ Margins = 0x04 }; //! Plot Item Attributes typedef QFlags ItemAttributes; /*! \brief Plot Item Interests Plot items might depend on the situation of the corresponding plot widget. By enabling an interest the plot item will be notified, when the corresponding attribute of the plot widgets has changed. \sa setItemAttribute(), testItemAttribute(), ItemInterest */ enum ItemInterest { /*! The item is interested in updates of the scales \sa updateScaleDiv() */ ScaleInterest = 0x01, /*! The item is interested in updates of the legend ( of other items ) This flag is intended for items, that want to implement a legend for displaying entries of other plot item. \note If the plot item wants to be represented on a legend enable QwtPlotItem::Legend instead. \sa updateLegend() */ LegendInterest = 0x02 }; //! Plot Item Interests typedef QFlags ItemInterests; //! Render hints enum RenderHint { //! Enable antialiasing RenderAntialiased = 0x1 }; //! Render hints typedef QFlags RenderHints; explicit QwtPlotItem( const QwtText &title = QwtText() ); virtual ~QwtPlotItem(); void attach( QwtPlot *plot ); void detach(); QwtPlot *plot() const; void setTitle( const QString &title ); void setTitle( const QwtText &title ); const QwtText &title() const; virtual int rtti() const; void setItemAttribute( ItemAttribute, bool on = true ); bool testItemAttribute( ItemAttribute ) const; void setItemInterest( ItemInterest, bool on = true ); bool testItemInterest( ItemInterest ) const; void setRenderHint( RenderHint, bool on = true ); bool testRenderHint( RenderHint ) const; void setRenderThreadCount( uint numThreads ); uint renderThreadCount() const; void setLegendIconSize( const QSize & ); QSize legendIconSize() const; double z() const; void setZ( double z ); void show(); void hide(); virtual void setVisible( bool ); bool isVisible () const; void setAxes( int xAxis, int yAxis ); void setXAxis( int axis ); int xAxis() const; void setYAxis( int axis ); int yAxis() const; virtual void itemChanged(); virtual void legendChanged(); /*! \brief Draw the item \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas in painter coordinates */ virtual void draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const = 0; virtual QRectF boundingRect() const; virtual void getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasSize, double &left, double &top, double &right, double &bottom) const; virtual void updateScaleDiv( const QwtScaleDiv&, const QwtScaleDiv& ); virtual void updateLegend( const QwtPlotItem *, const QList & ); QRectF scaleRect( const QwtScaleMap &, const QwtScaleMap & ) const; QRectF paintRect( const QwtScaleMap &, const QwtScaleMap & ) const; virtual QList legendData() const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: QwtGraphic defaultIcon( const QBrush &, const QSizeF & ) const; private: // Disabled copy constructor and operator= QwtPlotItem( const QwtPlotItem & ); QwtPlotItem &operator=( const QwtPlotItem & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemInterests ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::RenderHints ) Q_DECLARE_METATYPE( QwtPlotItem * ) #endif qsstv_8.2.12/qwt/qwt_clipper.h000664 001750 001750 00000002051 12440612574 016306 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_CLIPPER_H #define QWT_CLIPPER_H #include "qwt_global.h" #include "qwt_interval.h" #include #include class QRect; class QRectF; /*! \brief Some clipping algorithms */ class QWT_EXPORT QwtClipper { public: static QPolygon clipPolygon( const QRect &, const QPolygon &, bool closePolygon = false ); static QPolygon clipPolygon( const QRectF &, const QPolygon &, bool closePolygon = false ); static QPolygonF clipPolygonF( const QRectF &, const QPolygonF &, bool closePolygon = false ); static QVector clipCircle( const QRectF &, const QPointF &, double radius ); }; #endif qsstv_8.2.12/qwt/qwt_pixel_matrix.h000664 001750 001750 00000004431 12440612574 017361 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2003 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PIXEL_MATRIX_H #define QWT_PIXEL_MATRIX_H #include "qwt_global.h" #include #include /*! \brief A bit field corresponding to the pixels of a rectangle QwtPixelMatrix is intended to filter out duplicates in an unsorted array of points. */ class QWT_EXPORT QwtPixelMatrix: public QBitArray { public: QwtPixelMatrix( const QRect& rect ); ~QwtPixelMatrix(); void setRect( const QRect& rect ); QRect rect() const; bool testPixel( int x, int y ) const; bool testAndSetPixel( int x, int y, bool on ); int index( int x, int y ) const; private: QRect d_rect; }; /*! \brief Test if a pixel has been set \param x X-coordinate \param y Y-coordinate \return true, when pos is outside of rect(), or when the pixel has already been set. */ inline bool QwtPixelMatrix::testPixel( int x, int y ) const { const int idx = index( x, y ); return ( idx >= 0 ) ? testBit( idx ) : true; } /*! \brief Set a pixel and test if a pixel has been set before \param x X-coordinate \param y Y-coordinate \param on Set/Clear the pixel \return true, when pos is outside of rect(), or when the pixel was set before. */ inline bool QwtPixelMatrix::testAndSetPixel( int x, int y, bool on ) { const int idx = index( x, y ); if ( idx < 0 ) return true; const bool onBefore = testBit( idx ); setBit( idx, on ); return onBefore; } /*! \brief Calculate the index in the bit field corresponding to a position \param x X-coordinate \param y Y-coordinate \return Index, when rect() contains pos - otherwise -1. */ inline int QwtPixelMatrix::index( int x, int y ) const { const int dx = x - d_rect.x(); if ( dx < 0 || dx >= d_rect.width() ) return -1; const int dy = y - d_rect.y(); if ( dy < 0 || dy >= d_rect.height() ) return -1; return dy * d_rect.width() + dx; } #endif qsstv_8.2.12/qwt/qwt_color_map.cpp000664 001750 001750 00000023662 12440612574 017171 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_color_map.h" #include "qwt_math.h" #include "qwt_interval.h" #include class QwtLinearColorMap::ColorStops { public: ColorStops() { _stops.reserve( 256 ); } void insert( double pos, const QColor &color ); QRgb rgb( QwtLinearColorMap::Mode, double pos ) const; QVector stops() const; private: class ColorStop { public: ColorStop(): pos( 0.0 ), rgb( 0 ) { }; ColorStop( double p, const QColor &c ): pos( p ), rgb( c.rgb() ) { r = qRed( rgb ); g = qGreen( rgb ); b = qBlue( rgb ); } double pos; QRgb rgb; int r, g, b; }; inline int findUpper( double pos ) const; QVector _stops; }; void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color ) { // Lookups need to be very fast, insertions are not so important. // Anyway, a balanced tree is what we need here. TODO ... if ( pos < 0.0 || pos > 1.0 ) return; int index; if ( _stops.size() == 0 ) { index = 0; _stops.resize( 1 ); } else { index = findUpper( pos ); if ( index == _stops.size() || qAbs( _stops[index].pos - pos ) >= 0.001 ) { _stops.resize( _stops.size() + 1 ); for ( int i = _stops.size() - 1; i > index; i-- ) _stops[i] = _stops[i-1]; } } _stops[index] = ColorStop( pos, color ); } inline QVector QwtLinearColorMap::ColorStops::stops() const { QVector positions( _stops.size() ); for ( int i = 0; i < _stops.size(); i++ ) positions[i] = _stops[i].pos; return positions; } inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const { int index = 0; int n = _stops.size(); const ColorStop *stops = _stops.data(); while ( n > 0 ) { const int half = n >> 1; const int middle = index + half; if ( stops[middle].pos <= pos ) { index = middle + 1; n -= half + 1; } else n = half; } return index; } inline QRgb QwtLinearColorMap::ColorStops::rgb( QwtLinearColorMap::Mode mode, double pos ) const { if ( pos <= 0.0 ) return _stops[0].rgb; if ( pos >= 1.0 ) return _stops[ _stops.size() - 1 ].rgb; const int index = findUpper( pos ); if ( mode == FixedColors ) { return _stops[index-1].rgb; } else { const ColorStop &s1 = _stops[index-1]; const ColorStop &s2 = _stops[index]; const double ratio = ( pos - s1.pos ) / ( s2.pos - s1.pos ); const int r = s1.r + qRound( ratio * ( s2.r - s1.r ) ); const int g = s1.g + qRound( ratio * ( s2.g - s1.g ) ); const int b = s1.b + qRound( ratio * ( s2.b - s1.b ) ); return qRgb( r, g, b ); } } //! Constructor QwtColorMap::QwtColorMap( Format format ): d_format( format ) { } //! Destructor QwtColorMap::~QwtColorMap() { } /*! Build and return a color map of 256 colors The color table is needed for rendering indexed images in combination with using colorIndex(). \param interval Range for the values \return A color table, that can be used for a QImage */ QVector QwtColorMap::colorTable( const QwtInterval &interval ) const { QVector table( 256 ); if ( interval.isValid() ) { const double step = interval.width() / ( table.size() - 1 ); for ( int i = 0; i < table.size(); i++ ) table[i] = rgb( interval, interval.minValue() + step * i ); } return table; } class QwtLinearColorMap::PrivateData { public: ColorStops colorStops; QwtLinearColorMap::Mode mode; }; /*! Build a color map with two stops at 0.0 and 1.0. The color at 0.0 is Qt::blue, at 1.0 it is Qt::yellow. \param format Preferred format of the color map */ QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( Qt::blue, Qt::yellow ); } /*! Build a color map with two stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \param format Preferred format for the color map */ QwtLinearColorMap::QwtLinearColorMap( const QColor &color1, const QColor &color2, QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( color1, color2 ); } //! Destructor QwtLinearColorMap::~QwtLinearColorMap() { delete d_data; } /*! \brief Set the mode of the color map FixedColors means the color is calculated from the next lower color stop. ScaledColors means the color is calculated by interpolating the colors of the adjacent stops. \sa mode() */ void QwtLinearColorMap::setMode( Mode mode ) { d_data->mode = mode; } /*! \return Mode of the color map \sa setMode() */ QwtLinearColorMap::Mode QwtLinearColorMap::mode() const { return d_data->mode; } /*! Set the color range Add stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \sa color1(), color2() */ void QwtLinearColorMap::setColorInterval( const QColor &color1, const QColor &color2 ) { d_data->colorStops = ColorStops(); d_data->colorStops.insert( 0.0, color1 ); d_data->colorStops.insert( 1.0, color2 ); } /*! Add a color stop The value has to be in the range [0.0, 1.0]. F.e. a stop at position 17.0 for a range [10.0,20.0] must be passed as: (17.0 - 10.0) / (20.0 - 10.0) \param value Value between [0.0, 1.0] \param color Color stop */ void QwtLinearColorMap::addColorStop( double value, const QColor& color ) { if ( value >= 0.0 && value <= 1.0 ) d_data->colorStops.insert( value, color ); } /*! \return Positions of color stops in increasing order */ QVector QwtLinearColorMap::colorStops() const { return d_data->colorStops.stops(); } /*! \return the first color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color1() const { return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) ); } /*! \return the second color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color2() const { return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) ); } /*! Map a value of a given interval into a RGB value \param interval Range for all values \param value Value to map into a RGB value \return RGB value for value */ QRgb QwtLinearColorMap::rgb( const QwtInterval &interval, double value ) const { if ( qIsNaN(value) ) return qRgba(0, 0, 0, 0); const double width = interval.width(); double ratio = 0.0; if ( width > 0.0 ) ratio = ( value - interval.minValue() ) / width; return d_data->colorStops.rgb( d_data->mode, ratio ); } /*! \brief Map a value of a given interval into a color index \param interval Range for all values \param value Value to map into a color index \return Index, between 0 and 255 */ unsigned char QwtLinearColorMap::colorIndex( const QwtInterval &interval, double value ) const { const double width = interval.width(); if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() ) return 0; if ( value >= interval.maxValue() ) return 255; const double ratio = ( value - interval.minValue() ) / width; unsigned char index; if ( d_data->mode == FixedColors ) index = static_cast( ratio * 255 ); // always floor else index = static_cast( qRound( ratio * 255 ) ); return index; } class QwtAlphaColorMap::PrivateData { public: QColor color; QRgb rgb; }; /*! Constructor \param color Color of the map */ QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ): QwtColorMap( QwtColorMap::RGB ) { d_data = new PrivateData; d_data->color = color; d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 ); } //! Destructor QwtAlphaColorMap::~QwtAlphaColorMap() { delete d_data; } /*! Set the color \param color Color \sa color() */ void QwtAlphaColorMap::setColor( const QColor &color ) { d_data->color = color; d_data->rgb = color.rgb(); } /*! \return the color \sa setColor() */ QColor QwtAlphaColorMap::color() const { return d_data->color; } /*! \brief Map a value of a given interval into a alpha value alpha := (value - interval.minValue()) / interval.width(); \param interval Range for all values \param value Value to map into a RGB value \return RGB value, with an alpha value */ QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const { const double width = interval.width(); if ( !qIsNaN(value) && width >= 0.0 ) { const double ratio = ( value - interval.minValue() ) / width; int alpha = qRound( 255 * ratio ); if ( alpha < 0 ) alpha = 0; if ( alpha > 255 ) alpha = 255; return d_data->rgb | ( alpha << 24 ); } return d_data->rgb; } /*! Dummy function, needed to be implemented as it is pure virtual in QwtColorMap. Color indices make no sense in combination with an alpha channel. \return Always 0 */ unsigned char QwtAlphaColorMap::colorIndex( const QwtInterval &, double ) const { return 0; } qsstv_8.2.12/qwt/qwt_plot.cpp000664 001750 001750 00000073756 12440612574 016205 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_plot_dict.h" #include "qwt_plot_layout.h" #include "qwt_scale_widget.h" #include "qwt_scale_engine.h" #include "qwt_text_label.h" #include "qwt_legend.h" #include "qwt_legend_data.h" #include "qwt_plot_canvas.h" #include #include #include #include #include #include static inline void qwtEnableLegendItems( QwtPlot *plot, bool on ) { if ( on ) { QObject::connect( plot, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), plot, SLOT( updateLegendItems( const QVariant &, const QList & ) ) ); } else { QObject::disconnect( plot, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), plot, SLOT( updateLegendItems( const QVariant &, const QList & ) ) ); } } static void qwtSetTabOrder( QWidget *first, QWidget *second, bool withChildren ) { QList tabChain; tabChain += first; tabChain += second; if ( withChildren ) { QList children = second->findChildren(); QWidget *w = second->nextInFocusChain(); while ( children.contains( w ) ) { children.removeAll( w ); tabChain += w; w = w->nextInFocusChain(); } } for ( int i = 0; i < tabChain.size() - 1; i++ ) { QWidget *from = tabChain[i]; QWidget *to = tabChain[i+1]; const Qt::FocusPolicy policy1 = from->focusPolicy(); const Qt::FocusPolicy policy2 = to->focusPolicy(); QWidget *proxy1 = from->focusProxy(); QWidget *proxy2 = to->focusProxy(); from->setFocusPolicy( Qt::TabFocus ); from->setFocusProxy( NULL); to->setFocusPolicy( Qt::TabFocus ); to->setFocusProxy( NULL); QWidget::setTabOrder( from, to ); from->setFocusPolicy( policy1 ); from->setFocusProxy( proxy1); to->setFocusPolicy( policy2 ); to->setFocusProxy( proxy2 ); } } class QwtPlot::PrivateData { public: QPointer titleLabel; QPointer footerLabel; QPointer canvas; QPointer legend; QwtPlotLayout *layout; bool autoReplot; }; /*! \brief Constructor \param parent Parent widget */ QwtPlot::QwtPlot( QWidget *parent ): QFrame( parent ) { initPlot( QwtText() ); } /*! \brief Constructor \param title Title text \param parent Parent widget */ QwtPlot::QwtPlot( const QwtText &title, QWidget *parent ): QFrame( parent ) { initPlot( title ); } //! Destructor QwtPlot::~QwtPlot() { detachItems( QwtPlotItem::Rtti_PlotItem, autoDelete() ); delete d_data->layout; deleteAxesData(); delete d_data; } /*! \brief Initializes a QwtPlot instance \param title Title text */ void QwtPlot::initPlot( const QwtText &title ) { d_data = new PrivateData; d_data->layout = new QwtPlotLayout; d_data->autoReplot = false; // title d_data->titleLabel = new QwtTextLabel( this ); d_data->titleLabel->setObjectName( "QwtPlotTitle" ); d_data->titleLabel->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) ); QwtText text( title ); text.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap ); d_data->titleLabel->setText( text ); // footer d_data->footerLabel = new QwtTextLabel( this ); d_data->footerLabel->setObjectName( "QwtPlotFooter" ); QwtText footer; footer.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap ); d_data->footerLabel->setText( footer ); // legend d_data->legend = NULL; // axis initAxesData(); // canvas d_data->canvas = new QwtPlotCanvas( this ); d_data->canvas->setObjectName( "QwtPlotCanvas" ); d_data->canvas->installEventFilter( this ); setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); resize( 200, 200 ); QList focusChain; focusChain << this << d_data->titleLabel << axisWidget( xTop ) << axisWidget( yLeft ) << d_data->canvas << axisWidget( yRight ) << axisWidget( xBottom ) << d_data->footerLabel; for ( int i = 0; i < focusChain.size() - 1; i++ ) qwtSetTabOrder( focusChain[i], focusChain[i+1], false ); qwtEnableLegendItems( this, true ); } /*! \brief Set the drawing canvas of the plot widget QwtPlot invokes methods of the canvas as meta methods ( see QMetaObject ). In opposite to using conventional C++ techniques like virtual methods they allow to use canvas implementations that are derived from QWidget or QGLWidget. The following meta methods could be implemented: - replot() When the canvas doesn't offer a replot method, QwtPlot calls update() instead. - borderPath() The border path is necessary to clip the content of the canvas When the canvas doesn't have any special border ( f.e rounded corners ) it is o.k. not to implement this method. The default canvas is a QwtPlotCanvas \param canvas Canvas Widget \sa canvas() */ void QwtPlot::setCanvas( QWidget *canvas ) { if ( canvas == d_data->canvas ) return; delete d_data->canvas; d_data->canvas = canvas; if ( canvas ) { canvas->setParent( this ); canvas->installEventFilter( this ); if ( isVisible() ) canvas->show(); } } /*! \brief Adds handling of layout requests \param event Event \return See QFrame::event() */ bool QwtPlot::event( QEvent *event ) { bool ok = QFrame::event( event ); switch ( event->type() ) { case QEvent::LayoutRequest: updateLayout(); break; case QEvent::PolishRequest: replot(); break; default:; } return ok; } /*! \brief Event filter The plot handles the following events for the canvas: - QEvent::Resize The canvas margins might depend on its size - QEvent::ContentsRectChange The layout needs to be recalculated \param object Object to be filtered \param event Event \return See QFrame::eventFilter() \sa updateCanvasMargins(), updateLayout() */ bool QwtPlot::eventFilter( QObject *object, QEvent *event ) { if ( object == d_data->canvas ) { if ( event->type() == QEvent::Resize ) { updateCanvasMargins(); } else if ( event->type() == QEvent::ContentsRectChange ) { updateLayout(); } } return QFrame::eventFilter( object, event ); } //! Replots the plot if autoReplot() is \c true. void QwtPlot::autoRefresh() { if ( d_data->autoReplot ) replot(); } /*! \brief Set or reset the autoReplot option If the autoReplot option is set, the plot will be updated implicitly by manipulating member functions. Since this may be time-consuming, it is recommended to leave this option switched off and call replot() explicitly if necessary. The autoReplot option is set to false by default, which means that the user has to call replot() in order to make changes visible. \param tf \c true or \c false. Defaults to \c true. \sa replot() */ void QwtPlot::setAutoReplot( bool tf ) { d_data->autoReplot = tf; } /*! \return true if the autoReplot option is set. \sa setAutoReplot() */ bool QwtPlot::autoReplot() const { return d_data->autoReplot; } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QString &title ) { if ( title != d_data->titleLabel->text().text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QwtText &title ) { if ( title != d_data->titleLabel->text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } //! \return Title of the plot QwtText QwtPlot::title() const { return d_data->titleLabel->text(); } //! \return Title label widget. QwtTextLabel *QwtPlot::titleLabel() { return d_data->titleLabel; } //! \return Title label widget. const QwtTextLabel *QwtPlot::titleLabel() const { return d_data->titleLabel; } /*! Change the text the footer \param text New text of the footer */ void QwtPlot::setFooter( const QString &text ) { if ( text != d_data->footerLabel->text().text() ) { d_data->footerLabel->setText( text ); updateLayout(); } } /*! Change the text the footer \param text New text of the footer */ void QwtPlot::setFooter( const QwtText &text ) { if ( text != d_data->footerLabel->text() ) { d_data->footerLabel->setText( text ); updateLayout(); } } //! \return Text of the footer QwtText QwtPlot::footer() const { return d_data->footerLabel->text(); } //! \return Footer label widget. QwtTextLabel *QwtPlot::footerLabel() { return d_data->footerLabel; } //! \return Footer label widget. const QwtTextLabel *QwtPlot::footerLabel() const { return d_data->footerLabel; } /*! \brief Assign a new plot layout \param layout Layout() \sa plotLayout() */ void QwtPlot::setPlotLayout( QwtPlotLayout *layout ) { if ( layout != d_data->layout ) { delete d_data->layout; layout = d_data->layout; updateLayout(); } } //! \return the plot's layout QwtPlotLayout *QwtPlot::plotLayout() { return d_data->layout; } //! \return the plot's layout const QwtPlotLayout *QwtPlot::plotLayout() const { return d_data->layout; } /*! \return the plot's legend \sa insertLegend() */ QwtAbstractLegend *QwtPlot::legend() { return d_data->legend; } /*! \return the plot's legend \sa insertLegend() */ const QwtAbstractLegend *QwtPlot::legend() const { return d_data->legend; } /*! \return the plot's canvas */ QWidget *QwtPlot::canvas() { return d_data->canvas; } /*! \return the plot's canvas */ const QWidget *QwtPlot::canvas() const { return d_data->canvas; } /*! \return Size hint for the plot widget \sa minimumSizeHint() */ QSize QwtPlot::sizeHint() const { int dw = 0; int dh = 0; for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { const int niceDist = 40; const QwtScaleWidget *scaleWidget = axisWidget( axisId ); const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv(); const int majCnt = scaleDiv.ticks( QwtScaleDiv::MajorTick ).count(); if ( axisId == yLeft || axisId == yRight ) { int hDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().height(); if ( hDiff > dh ) dh = hDiff; } else { int wDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().width(); if ( wDiff > dw ) dw = wDiff; } } } return minimumSizeHint() + QSize( dw, dh ); } /*! \brief Return a minimum size hint */ QSize QwtPlot::minimumSizeHint() const { QSize hint = d_data->layout->minimumSizeHint( this ); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! Resize and update internal layout \param e Resize event */ void QwtPlot::resizeEvent( QResizeEvent *e ) { QFrame::resizeEvent( e ); updateLayout(); } /*! \brief Redraw the plot If the autoReplot option is not set (which is the default) or if any curves are attached to raw data, the plot has to be refreshed explicitly in order to make changes visible. \sa updateAxes(), setAutoReplot() */ void QwtPlot::replot() { bool doAutoReplot = autoReplot(); setAutoReplot( false ); updateAxes(); /* Maybe the layout needs to be updated, because of changed axes labels. We need to process them here before painting to avoid that scales and canvas get out of sync. */ QApplication::sendPostedEvents( this, QEvent::LayoutRequest ); if ( d_data->canvas ) { const bool ok = QMetaObject::invokeMethod( d_data->canvas, "replot", Qt::DirectConnection ); if ( !ok ) { // fallback, when canvas has no a replot method d_data->canvas->update( d_data->canvas->contentsRect() ); } } setAutoReplot( doAutoReplot ); } /*! \brief Adjust plot content to its current size. \sa resizeEvent() */ void QwtPlot::updateLayout() { d_data->layout->activate( this, contentsRect() ); QRect titleRect = d_data->layout->titleRect().toRect(); QRect footerRect = d_data->layout->footerRect().toRect(); QRect scaleRect[QwtPlot::axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) scaleRect[axisId] = d_data->layout->scaleRect( axisId ).toRect(); QRect legendRect = d_data->layout->legendRect().toRect(); QRect canvasRect = d_data->layout->canvasRect().toRect(); // resize and show the visible widgets if ( !d_data->titleLabel->text().isEmpty() ) { d_data->titleLabel->setGeometry( titleRect ); if ( !d_data->titleLabel->isVisibleTo( this ) ) d_data->titleLabel->show(); } else d_data->titleLabel->hide(); if ( !d_data->footerLabel->text().isEmpty() ) { d_data->footerLabel->setGeometry( footerRect ); if ( !d_data->footerLabel->isVisibleTo( this ) ) d_data->footerLabel->show(); } else d_data->footerLabel->hide(); for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { axisWidget( axisId )->setGeometry( scaleRect[axisId] ); #if 1 if ( axisId == xBottom || axisId == xTop ) { // do we need this code any longer ??? QRegion r( scaleRect[axisId] ); if ( axisEnabled( yLeft ) ) r = r.subtracted( QRegion( scaleRect[yLeft] ) ); if ( axisEnabled( yRight ) ) r = r.subtracted( QRegion( scaleRect[yRight] ) ); r.translate( -scaleRect[ axisId ].x(), -scaleRect[axisId].y() ); axisWidget( axisId )->setMask( r ); } #endif if ( !axisWidget( axisId )->isVisibleTo( this ) ) axisWidget( axisId )->show(); } else axisWidget( axisId )->hide(); } if ( d_data->legend ) { if ( d_data->legend->isEmpty() ) { d_data->legend->hide(); } else { d_data->legend->setGeometry( legendRect ); d_data->legend->show(); } } d_data->canvas->setGeometry( canvasRect ); } /*! \brief Calculate the canvas margins \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates \param canvasRect Bounding rectangle where to paint \param left Return parameter for the left margin \param top Return parameter for the top margin \param right Return parameter for the right margin \param bottom Return parameter for the bottom margin Plot items might indicate, that they need some extra space at the borders of the canvas by the QwtPlotItem::Margins flag. updateCanvasMargins(), QwtPlotItem::getCanvasMarginHint() */ void QwtPlot::getCanvasMarginsHint( const QwtScaleMap maps[], const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const { left = top = right = bottom = -1.0; const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { const QwtPlotItem *item = *it; if ( item->testItemAttribute( QwtPlotItem::Margins ) ) { double m[ QwtPlot::axisCnt ]; item->getCanvasMarginHint( maps[ item->xAxis() ], maps[ item->yAxis() ], canvasRect, m[yLeft], m[xTop], m[yRight], m[xBottom] ); left = qMax( left, m[yLeft] ); top = qMax( top, m[xTop] ); right = qMax( right, m[yRight] ); bottom = qMax( bottom, m[xBottom] ); } } } /*! \brief Update the canvas margins Plot items might indicate, that they need some extra space at the borders of the canvas by the QwtPlotItem::Margins flag. getCanvasMarginsHint(), QwtPlotItem::getCanvasMarginHint() */ void QwtPlot::updateCanvasMargins() { QwtScaleMap maps[axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) maps[axisId] = canvasMap( axisId ); double margins[axisCnt]; getCanvasMarginsHint( maps, canvas()->contentsRect(), margins[yLeft], margins[xTop], margins[yRight], margins[xBottom] ); bool doUpdate = false; for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( margins[axisId] >= 0.0 ) { const int m = qCeil( margins[axisId] ); plotLayout()->setCanvasMargin( m, axisId); doUpdate = true; } } if ( doUpdate ) updateLayout(); } /*! Redraw the canvas. \param painter Painter used for drawing \warning drawCanvas calls drawItems what is also used for printing. Applications that like to add individual plot items better overload drawItems() \sa drawItems() */ void QwtPlot::drawCanvas( QPainter *painter ) { QwtScaleMap maps[axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) maps[axisId] = canvasMap( axisId ); drawItems( painter, d_data->canvas->contentsRect(), maps ); } /*! Redraw the canvas items. \param painter Painter used for drawing \param canvasRect Bounding rectangle where to paint \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates \note Usually canvasRect is contentsRect() of the plot canvas. Due to a bug in Qt this rectangle might be wrong for certain frame styles ( f.e QFrame::Box ) and it might be necessary to fix the margins manually using QWidget::setContentsMargins() */ void QwtPlot::drawItems( QPainter *painter, const QRectF &canvasRect, const QwtScaleMap maps[axisCnt] ) const { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item && item->isVisible() ) { painter->save(); painter->setRenderHint( QPainter::Antialiasing, item->testRenderHint( QwtPlotItem::RenderAntialiased ) ); painter->setRenderHint( QPainter::HighQualityAntialiasing, item->testRenderHint( QwtPlotItem::RenderAntialiased ) ); item->draw( painter, maps[item->xAxis()], maps[item->yAxis()], canvasRect ); painter->restore(); } } } /*! \param axisId Axis \return Map for the axis on the canvas. With this map pixel coordinates can translated to plot coordinates and vice versa. \sa QwtScaleMap, transform(), invTransform() */ QwtScaleMap QwtPlot::canvasMap( int axisId ) const { QwtScaleMap map; if ( !d_data->canvas ) return map; map.setTransformation( axisScaleEngine( axisId )->transformation() ); const QwtScaleDiv &sd = axisScaleDiv( axisId ); map.setScaleInterval( sd.lowerBound(), sd.upperBound() ); if ( axisEnabled( axisId ) ) { const QwtScaleWidget *s = axisWidget( axisId ); if ( axisId == yLeft || axisId == yRight ) { double y = s->y() + s->startBorderDist() - d_data->canvas->y(); double h = s->height() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( y + h, y ); } else { double x = s->x() + s->startBorderDist() - d_data->canvas->x(); double w = s->width() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( x, x + w ); } } else { int margin = 0; if ( !plotLayout()->alignCanvasToScale( axisId ) ) margin = plotLayout()->canvasMargin( axisId ); const QRect &canvasRect = d_data->canvas->contentsRect(); if ( axisId == yLeft || axisId == yRight ) { map.setPaintInterval( canvasRect.bottom() - margin, canvasRect.top() + margin ); } else { map.setPaintInterval( canvasRect.left() + margin, canvasRect.right() - margin ); } } return map; } /*! \brief Change the background of the plotting area Sets brush to QPalette::Window of all color groups of the palette of the canvas. Using canvas()->setPalette() is a more powerful way to set these colors. \param brush New background brush \sa canvasBackground() */ void QwtPlot::setCanvasBackground( const QBrush &brush ) { QPalette pal = d_data->canvas->palette(); pal.setBrush( QPalette::Window, brush ); canvas()->setPalette( pal ); } /*! Nothing else than: canvas()->palette().brush( QPalette::Normal, QPalette::Window); \return Background brush of the plotting area. \sa setCanvasBackground() */ QBrush QwtPlot::canvasBackground() const { return canvas()->palette().brush( QPalette::Normal, QPalette::Window ); } /*! \return \c true if the specified axis exists, otherwise \c false \param axisId axis index */ bool QwtPlot::axisValid( int axisId ) { return ( ( axisId >= QwtPlot::yLeft ) && ( axisId < QwtPlot::axisCnt ) ); } /*! \brief Insert a legend If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend the legend will be organized in one column from top to down. Otherwise the legend items will be placed in a table with a best fit number of columns from left to right. insertLegend() will set the plot widget as parent for the legend. The legend will be deleted in the destructor of the plot or when another legend is inserted. Legends, that are not inserted into the layout of the plot widget need to connect to the legendDataChanged() signal. Calling updateLegend() initiates this signal for an initial update. When the application code wants to implement its own layout this also needs to be done for rendering plots to a document ( see QwtPlotRenderer ). \param legend Legend \param pos The legend's position. For top/left position the number of columns will be limited to 1, otherwise it will be set to unlimited. \param ratio Ratio between legend and the bounding rectangle of title, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa legend(), QwtPlotLayout::legendPosition(), QwtPlotLayout::setLegendPosition() */ void QwtPlot::insertLegend( QwtAbstractLegend *legend, QwtPlot::LegendPosition pos, double ratio ) { d_data->layout->setLegendPosition( pos, ratio ); if ( legend != d_data->legend ) { if ( d_data->legend && d_data->legend->parent() == this ) delete d_data->legend; d_data->legend = legend; if ( d_data->legend ) { connect( this, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), d_data->legend, SLOT( updateLegend( const QVariant &, const QList & ) ) ); if ( d_data->legend->parent() != this ) d_data->legend->setParent( this ); qwtEnableLegendItems( this, false ); updateLegend(); qwtEnableLegendItems( this, true ); QwtLegend *lgd = qobject_cast( legend ); if ( lgd ) { switch ( d_data->layout->legendPosition() ) { case LeftLegend: case RightLegend: { if ( lgd->maxColumns() == 0 ) lgd->setMaxColumns( 1 ); // 1 column: align vertical break; } case TopLegend: case BottomLegend: { lgd->setMaxColumns( 0 ); // unlimited break; } default: break; } } QWidget *previousInChain = NULL; switch ( d_data->layout->legendPosition() ) { case LeftLegend: { previousInChain = axisWidget( QwtPlot::xTop ); break; } case TopLegend: { previousInChain = this; break; } case RightLegend: { previousInChain = axisWidget( QwtPlot::yRight ); break; } case BottomLegend: { previousInChain = footerLabel(); break; } } if ( previousInChain ) qwtSetTabOrder( previousInChain, legend, true ); } } updateLayout(); } /*! Emit legendDataChanged() for all plot item \sa QwtPlotItem::legendData(), legendDataChanged() */ void QwtPlot::updateLegend() { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { updateLegend( *it ); } } /*! Emit legendDataChanged() for a plot item \param plotItem Plot item \sa QwtPlotItem::legendData(), legendDataChanged() */ void QwtPlot::updateLegend( const QwtPlotItem *plotItem ) { if ( plotItem == NULL ) return; QList legendData; if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) ) legendData = plotItem->legendData(); const QVariant itemInfo = itemToInfo( const_cast< QwtPlotItem *>( plotItem) ); Q_EMIT legendDataChanged( itemInfo, legendData ); } /*! \brief Update all plot items interested in legend attributes Call QwtPlotItem::updateLegend(), when the QwtPlotItem::LegendInterest flag is set. \param itemInfo Info about the plot item \param legendData Entries to be displayed for the plot item ( usually 1 ) \sa QwtPlotItem::LegendInterest, QwtPlotLegendItem, QwtPlotItem::updateLegend() */ void QwtPlot::updateLegendItems( const QVariant &itemInfo, const QList &legendData ) { QwtPlotItem *plotItem = infoToItem( itemInfo ); if ( plotItem ) { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item->testItemInterest( QwtPlotItem::LegendInterest ) ) item->updateLegend( plotItem, legendData ); } } } /*! \brief Attach/Detach a plot item \param plotItem Plot item \param on When true attach the item, otherwise detach it */ void QwtPlot::attachItem( QwtPlotItem *plotItem, bool on ) { if ( plotItem->testItemInterest( QwtPlotItem::LegendInterest ) ) { // plotItem is some sort of legend const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; QList legendData; if ( on && item->testItemAttribute( QwtPlotItem::Legend ) ) { legendData = item->legendData(); plotItem->updateLegend( item, legendData ); } } } if ( on ) insertItem( plotItem ); else removeItem( plotItem ); Q_EMIT itemAttached( plotItem, on ); if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) ) { // the item wants to be represented on the legend if ( on ) { updateLegend( plotItem ); } else { const QVariant itemInfo = itemToInfo( plotItem ); Q_EMIT legendDataChanged( itemInfo, QList() ); } } if ( autoReplot() ) update(); } /*! \brief Build an information, that can be used to identify a plot item on the legend. The default implementation simply wraps the plot item into a QVariant object. When overloading itemToInfo() usually infoToItem() needs to reimplemeted too. \code QVariant itemInfo; qVariantSetValue( itemInfo, plotItem ); \endcode \param plotItem Plot item \return Plot item embedded in a QVariant \sa infoToItem() */ QVariant QwtPlot::itemToInfo( QwtPlotItem *plotItem ) const { QVariant itemInfo; qVariantSetValue( itemInfo, plotItem ); return itemInfo; } /*! \brief Identify the plot item according to an item info object, that has bee generated from itemToInfo(). The default implementation simply tries to unwrap a QwtPlotItem pointer: \code if ( itemInfo.canConvert() ) return qvariant_cast( itemInfo ); \endcode \param itemInfo Plot item \return A plot item, when successful, otherwise a NULL pointer. \sa itemToInfo() */ QwtPlotItem *QwtPlot::infoToItem( const QVariant &itemInfo ) const { if ( itemInfo.canConvert() ) return qvariant_cast( itemInfo ); return NULL; } qsstv_8.2.12/qwt/qwt_color_map.h000664 001750 001750 00000011663 12440612574 016634 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLOR_MAP_H #define QWT_COLOR_MAP_H #include "qwt_global.h" #include "qwt_interval.h" #include #include /*! \brief QwtColorMap is used to map values into colors. For displaying 3D data on a 2D plane the 3rd dimension is often displayed using colors, like f.e in a spectrogram. Each color map is optimized to return colors for only one of the following image formats: - QImage::Format_Indexed8\n - QImage::Format_ARGB32\n \sa QwtPlotSpectrogram, QwtScaleWidget */ class QWT_EXPORT QwtColorMap { public: /*! Format for color mapping \sa rgb(), colorIndex(), colorTable() */ enum Format { //! The map is intended to map into RGB values. RGB, /*! The map is intended to map into 8 bit values, that are indices into the color table. */ Indexed }; QwtColorMap( Format = QwtColorMap::RGB ); virtual ~QwtColorMap(); Format format() const; /*! Map a value of a given interval into a RGB value. \param interval Range for the values \param value Value \return RGB value, corresponding to value */ virtual QRgb rgb( const QwtInterval &interval, double value ) const = 0; /*! Map a value of a given interval into a color index \param interval Range for the values \param value Value \return color index, corresponding to value */ virtual unsigned char colorIndex( const QwtInterval &interval, double value ) const = 0; QColor color( const QwtInterval &, double value ) const; virtual QVector colorTable( const QwtInterval & ) const; private: Format d_format; }; /*! \brief QwtLinearColorMap builds a color map from color stops. A color stop is a color at a specific position. The valid range for the positions is [0.0, 1.0]. When mapping a value into a color it is translated into this interval according to mode(). */ class QWT_EXPORT QwtLinearColorMap: public QwtColorMap { public: /*! Mode of color map \sa setMode(), mode() */ enum Mode { //! Return the color from the next lower color stop FixedColors, //! Interpolating the colors of the adjacent stops. ScaledColors }; QwtLinearColorMap( QwtColorMap::Format = QwtColorMap::RGB ); QwtLinearColorMap( const QColor &from, const QColor &to, QwtColorMap::Format = QwtColorMap::RGB ); virtual ~QwtLinearColorMap(); void setMode( Mode ); Mode mode() const; void setColorInterval( const QColor &color1, const QColor &color2 ); void addColorStop( double value, const QColor& ); QVector colorStops() const; QColor color1() const; QColor color2() const; virtual QRgb rgb( const QwtInterval &, double value ) const; virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class ColorStops; private: // Disabled copy constructor and operator= QwtLinearColorMap( const QwtLinearColorMap & ); QwtLinearColorMap &operator=( const QwtLinearColorMap & ); class PrivateData; PrivateData *d_data; }; /*! \brief QwtAlphaColorMap varies the alpha value of a color */ class QWT_EXPORT QwtAlphaColorMap: public QwtColorMap { public: QwtAlphaColorMap( const QColor & = QColor( Qt::gray ) ); virtual ~QwtAlphaColorMap(); void setColor( const QColor & ); QColor color() const; virtual QRgb rgb( const QwtInterval &, double value ) const; private: QwtAlphaColorMap( const QwtAlphaColorMap & ); QwtAlphaColorMap &operator=( const QwtAlphaColorMap & ); virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class PrivateData; PrivateData *d_data; }; /*! Map a value into a color \param interval Valid interval for values \param value Value \return Color corresponding to value \warning This method is slow for Indexed color maps. If it is necessary to map many values, its better to get the color table once and find the color using colorIndex(). */ inline QColor QwtColorMap::color( const QwtInterval &interval, double value ) const { if ( d_format == RGB ) { return QColor( rgb( interval, value ) ); } else { const unsigned int index = colorIndex( interval, value ); return colorTable( interval )[index]; // slow } } /*! \return Intended format of the color map \sa Format */ inline QwtColorMap::Format QwtColorMap::format() const { return d_format; } #endif qsstv_8.2.12/qwt/qwt_plot.h000664 001750 001750 00000020252 12440612574 015631 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_H #define QWT_PLOT_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_plot_dict.h" #include "qwt_scale_map.h" #include "qwt_interval.h" #include #include #include class QwtPlotLayout; class QwtAbstractLegend; class QwtScaleWidget; class QwtScaleEngine; class QwtScaleDiv; class QwtScaleDraw; class QwtTextLabel; /*! \brief A 2-D plotting widget QwtPlot is a widget for plotting two-dimensional graphs. An unlimited number of plot items can be displayed on its canvas. Plot items might be curves (QwtPlotCurve), markers (QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived from QwtPlotItem. A plot can have up to four axes, with each plot item attached to an x- and a y axis. The scales at the axes can be explicitly set (QwtScaleDiv), or are calculated from the plot items, using algorithms (QwtScaleEngine) which can be configured separately for each axis. The simpleplot example is a good starting point to see how to set up a plot widget. \image html plot.png \par Example The following example shows (schematically) the most simple way to use QwtPlot. By default, only the left and bottom axes are visible and their scales are computed automatically. \verbatim #include #include QwtPlot *myPlot = new QwtPlot("Two Curves", parent); // add curves QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1"); QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2"); // connect or copy the data to the curves curve1->setData(...); curve2->setData(...); curve1->attach(myPlot); curve2->attach(myPlot); // finally, refresh the plot myPlot->replot(); \endverbatim */ class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict { Q_OBJECT Q_PROPERTY( QBrush canvasBackground READ canvasBackground WRITE setCanvasBackground ) Q_PROPERTY( bool autoReplot READ autoReplot WRITE setAutoReplot ) #if 0 // This property is intended to configure the plot // widget from a special dialog in the deigner plugin. // Disabled until such a dialog has been implemented. Q_PROPERTY( QString propertiesDocument READ grabProperties WRITE applyProperties ) #endif public: //! \brief Axis index enum Axis { //! Y axis left of the canvas yLeft, //! Y axis right of the canvas yRight, //! X axis below the canvas xBottom, //! X axis above the canvas xTop, //! Number of axes axisCnt }; /*! Position of the legend, relative to the canvas. \sa insertLegend() */ enum LegendPosition { //! The legend will be left from the QwtPlot::yLeft axis. LeftLegend, //! The legend will be right from the QwtPlot::yRight axis. RightLegend, //! The legend will be below the footer BottomLegend, //! The legend will be above the title TopLegend }; explicit QwtPlot( QWidget * = NULL ); explicit QwtPlot( const QwtText &title, QWidget * = NULL ); virtual ~QwtPlot(); void applyProperties( const QString & ); QString grabProperties() const; void setAutoReplot( bool = true ); bool autoReplot() const; // Layout void setPlotLayout( QwtPlotLayout * ); QwtPlotLayout *plotLayout(); const QwtPlotLayout *plotLayout() const; // Title void setTitle( const QString & ); void setTitle( const QwtText &t ); QwtText title() const; QwtTextLabel *titleLabel(); const QwtTextLabel *titleLabel() const; // Footer void setFooter( const QString & ); void setFooter( const QwtText &t ); QwtText footer() const; QwtTextLabel *footerLabel(); const QwtTextLabel *footerLabel() const; // Canvas void setCanvas( QWidget * ); QWidget *canvas(); const QWidget *canvas() const; void setCanvasBackground( const QBrush & ); QBrush canvasBackground() const; virtual QwtScaleMap canvasMap( int axisId ) const; double invTransform( int axisId, int pos ) const; double transform( int axisId, double value ) const; // Axes QwtScaleEngine *axisScaleEngine( int axisId ); const QwtScaleEngine *axisScaleEngine( int axisId ) const; void setAxisScaleEngine( int axisId, QwtScaleEngine * ); void setAxisAutoScale( int axisId, bool on = true ); bool axisAutoScale( int axisId ) const; void enableAxis( int axisId, bool tf = true ); bool axisEnabled( int axisId ) const; void setAxisFont( int axisId, const QFont &f ); QFont axisFont( int axisId ) const; void setAxisScale( int axisId, double min, double max, double step = 0 ); void setAxisScaleDiv( int axisId, const QwtScaleDiv & ); void setAxisScaleDraw( int axisId, QwtScaleDraw * ); double axisStepSize( int axisId ) const; QwtInterval axisInterval( int axisId ) const; const QwtScaleDiv &axisScaleDiv( int axisId ) const; const QwtScaleDraw *axisScaleDraw( int axisId ) const; QwtScaleDraw *axisScaleDraw( int axisId ); const QwtScaleWidget *axisWidget( int axisId ) const; QwtScaleWidget *axisWidget( int axisId ); void setAxisLabelAlignment( int axisId, Qt::Alignment ); void setAxisLabelRotation( int axisId, double rotation ); void setAxisTitle( int axisId, const QString & ); void setAxisTitle( int axisId, const QwtText & ); QwtText axisTitle( int axisId ) const; void setAxisMaxMinor( int axisId, int maxMinor ); int axisMaxMinor( int axisId ) const; void setAxisMaxMajor( int axisId, int maxMajor ); int axisMaxMajor( int axisId ) const; // Legend void insertLegend( QwtAbstractLegend *, LegendPosition = QwtPlot::RightLegend, double ratio = -1.0 ); QwtAbstractLegend *legend(); const QwtAbstractLegend *legend() const; void updateLegend(); void updateLegend( const QwtPlotItem * ); // Misc virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void updateLayout(); virtual void drawCanvas( QPainter * ); void updateAxes(); void updateCanvasMargins(); virtual void getCanvasMarginsHint( const QwtScaleMap maps[], const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const; virtual bool event( QEvent * ); virtual bool eventFilter( QObject *, QEvent * ); virtual void drawItems( QPainter *, const QRectF &, const QwtScaleMap maps[axisCnt] ) const; virtual QVariant itemToInfo( QwtPlotItem * ) const; virtual QwtPlotItem *infoToItem( const QVariant & ) const; Q_SIGNALS: /*! A signal indicating, that an item has been attached/detached \param plotItem Plot item \param on Attached/Detached */ void itemAttached( QwtPlotItem *plotItem, bool on ); /*! A signal with the attributes how to update the legend entries for a plot item. \param itemInfo Info about a plot item, build from itemToInfo() \param data Attributes of the entries ( usually <= 1 ) for the plot item. \sa itemToInfo(), infoToItem(), QwtAbstractLegend::updateLegend() */ void legendDataChanged( const QVariant &itemInfo, const QList &data ); public Q_SLOTS: virtual void replot(); void autoRefresh(); protected: static bool axisValid( int axisId ); virtual void resizeEvent( QResizeEvent *e ); private Q_SLOTS: void updateLegendItems( const QVariant &itemInfo, const QList &data ); private: friend class QwtPlotItem; void attachItem( QwtPlotItem *, bool ); void initAxesData(); void deleteAxesData(); void updateScaleDiv(); void initPlot( const QwtText &title ); class AxisData; AxisData *d_axisData[axisCnt]; class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_column_symbol.cpp000664 001750 001750 00000015276 12440612574 020102 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_column_symbol.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include static void qwtDrawBox( QPainter *p, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); QPolygonF polygon( outerRect ); if ( outerRect.width() > 2 * lw && outerRect.height() > 2 * lw ) { const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); polygon = polygon.subtracted( innerRect ); } p->setPen( Qt::NoPen ); p->setBrush( pal.dark() ); p->drawPolygon( polygon ); } const QRectF windowRect = rect.adjusted( lw, lw, -lw + 1, -lw + 1 ); if ( windowRect.isValid() ) p->fillRect( windowRect, pal.window() ); } static void qwtDrawPanel( QPainter *painter, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); QPolygonF lines[2]; lines[0] += outerRect.bottomLeft(); lines[0] += outerRect.topLeft(); lines[0] += outerRect.topRight(); lines[0] += innerRect.topRight(); lines[0] += innerRect.topLeft(); lines[0] += innerRect.bottomLeft(); lines[1] += outerRect.topRight(); lines[1] += outerRect.bottomRight(); lines[1] += outerRect.bottomLeft(); lines[1] += innerRect.bottomLeft(); lines[1] += innerRect.bottomRight(); lines[1] += innerRect.topRight(); painter->setPen( Qt::NoPen ); painter->setBrush( pal.light() ); painter->drawPolygon( lines[0] ); painter->setBrush( pal.dark() ); painter->drawPolygon( lines[1] ); } painter->fillRect( rect.adjusted( lw, lw, -lw + 1, -lw + 1 ), pal.window() ); } class QwtColumnSymbol::PrivateData { public: PrivateData(): style( QwtColumnSymbol::Box ), frameStyle( QwtColumnSymbol::Raised ), lineWidth( 2 ) { palette = QPalette( Qt::gray ); } QwtColumnSymbol::Style style; QwtColumnSymbol::FrameStyle frameStyle; QPalette palette; int lineWidth; }; /*! Constructor \param style Style of the symbol \sa setStyle(), style(), Style */ QwtColumnSymbol::QwtColumnSymbol( Style style ) { d_data = new PrivateData(); d_data->style = style; } //! Destructor QwtColumnSymbol::~QwtColumnSymbol() { delete d_data; } /*! Specify the symbol style \param style Style \sa style(), setPalette() */ void QwtColumnSymbol::setStyle( Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtColumnSymbol::Style QwtColumnSymbol::style() const { return d_data->style; } /*! Assign a palette for the symbol \param palette Palette \sa palette(), setStyle() */ void QwtColumnSymbol::setPalette( const QPalette &palette ) { d_data->palette = palette; } /*! \return Current palette \sa setPalette() */ const QPalette& QwtColumnSymbol::palette() const { return d_data->palette; } /*! Set the frame, that is used for the Box style. \param frameStyle Frame style \sa frameStyle(), setLineWidth(), setStyle() */ void QwtColumnSymbol::setFrameStyle( FrameStyle frameStyle ) { d_data->frameStyle = frameStyle; } /*! \return Current frame style, that is used for the Box style. \sa setFrameStyle(), lineWidth(), setStyle() */ QwtColumnSymbol::FrameStyle QwtColumnSymbol::frameStyle() const { return d_data->frameStyle; } /*! Set the line width of the frame, that is used for the Box style. \param width Width \sa lineWidth(), setFrameStyle() */ void QwtColumnSymbol::setLineWidth( int width ) { if ( width < 0 ) width = 0; d_data->lineWidth = width; } /*! \return Line width of the frame, that is used for the Box style. \sa setLineWidth(), frameStyle(), setStyle() */ int QwtColumnSymbol::lineWidth() const { return d_data->lineWidth; } /*! Draw the symbol depending on its style. \param painter Painter \param rect Directed rectangle \sa drawBox() */ void QwtColumnSymbol::draw( QPainter *painter, const QwtColumnRect &rect ) const { painter->save(); switch ( d_data->style ) { case QwtColumnSymbol::Box: { drawBox( painter, rect ); break; } default:; } painter->restore(); } /*! Draw the symbol when it is in Box style. \param painter Painter \param rect Directed rectangle \sa draw() */ void QwtColumnSymbol::drawBox( QPainter *painter, const QwtColumnRect &rect ) const { QRectF r = rect.toRect(); if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } switch ( d_data->frameStyle ) { case QwtColumnSymbol::Raised: { qwtDrawPanel( painter, r, d_data->palette, d_data->lineWidth ); break; } case QwtColumnSymbol::Plain: { qwtDrawBox( painter, r, d_data->palette, d_data->lineWidth ); break; } default: { painter->fillRect( r, d_data->palette.window() ); } } } qsstv_8.2.12/qwt/qwt_plot_abstract_barchart.h000664 001750 001750 00000005042 12440612574 021362 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ABSTRACT_BAR_CHART_H #define QWT_PLOT_ABSTRACT_BAR_CHART_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" /*! \brief Abstract base class for bar chart items In opposite to almost all other plot items bar charts can't be displayed inside of their bounding rectangle and need a special API how to calculate the width of the bars and how they affect the layout of the attached plot. */ class QWT_EXPORT QwtPlotAbstractBarChart: public QwtPlotSeriesItem { public: /*! \brief Mode how to calculate the bar width setLayoutPolicy(), setLayoutHint(), barWidthHint() */ enum LayoutPolicy { /*! The sample width is calculated by dividing the bounding rectangle by the number of samples. \sa boundingRectangle() \note The layoutHint() is ignored */ AutoAdjustSamples, /*! layoutHint() defines an interval in axis coordinates */ ScaleSamplesToAxes, /*! The bar width is calculated by multiplying layoutHint() with the height or width of the canvas. \sa boundingRectangle() */ ScaleSampleToCanvas, /*! layoutHint() defines a fixed width in paint device coordinates. */ FixedSampleSize }; explicit QwtPlotAbstractBarChart( const QwtText &title ); virtual ~QwtPlotAbstractBarChart(); void setLayoutPolicy( LayoutPolicy ); LayoutPolicy layoutPolicy() const; void setLayoutHint( double ); double layoutHint() const; void setSpacing( int ); int spacing() const; void setMargin( int ); int margin() const; void setBaseline( double ); double baseline() const; virtual void getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const; protected: double sampleWidth( const QwtScaleMap &map, double canvasSize, double dataSize, double value ) const; private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_column_symbol.h000664 001750 001750 00000007360 12440612574 017542 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLUMN_SYMBOL_H #define QWT_COLUMN_SYMBOL_H #include "qwt_global.h" #include "qwt_interval.h" #include #include #include class QPainter; class QPalette; class QRect; class QwtText; /*! \brief Directed rectangle representing bounding rectangle and orientation of a column. */ class QWT_EXPORT QwtColumnRect { public: //! Direction of the column enum Direction { //! From left to right LeftToRight, //! From right to left RightToLeft, //! From bottom to top BottomToTop, //! From top to bottom TopToBottom }; //! Build an rectangle with invalid intervals directed BottomToTop. QwtColumnRect(): direction( BottomToTop ) { } //! \return A normalized QRect built from the intervals QRectF toRect() const { QRectF r( hInterval.minValue(), vInterval.minValue(), hInterval.maxValue() - hInterval.minValue(), vInterval.maxValue() - vInterval.minValue() ); r = r.normalized(); if ( hInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 1, 0, 0, 0 ); if ( hInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, -1, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 0, 1, 0, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, 0, -1 ); return r; } //! \return Orientation Qt::Orientation orientation() const { if ( direction == LeftToRight || direction == RightToLeft ) return Qt::Horizontal; return Qt::Vertical; } //! Interval for the horizontal coordinates QwtInterval hInterval; //! Interval for the vertical coordinates QwtInterval vInterval; //! Direction Direction direction; }; //! A drawing primitive for columns class QWT_EXPORT QwtColumnSymbol { public: /*! Style \sa setStyle(), style() */ enum Style { //! No Style, the symbol draws nothing NoStyle = -1, /*! The column is painted with a frame depending on the frameStyle() and lineWidth() using the palette(). */ Box, /*! Styles >= QwtColumnSymbol::UserStyle are reserved for derived classes of QwtColumnSymbol that overload draw() with additional application specific symbol types. */ UserStyle = 1000 }; /*! Frame Style used in Box style(). \sa Style, setFrameStyle(), frameStyle(), setStyle(), setPalette() */ enum FrameStyle { //! No frame NoFrame, //! A plain frame style Plain, //! A raised frame style Raised }; public: QwtColumnSymbol( Style = NoStyle ); virtual ~QwtColumnSymbol(); void setFrameStyle( FrameStyle style ); FrameStyle frameStyle() const; void setLineWidth( int width ); int lineWidth() const; void setPalette( const QPalette & ); const QPalette &palette() const; void setStyle( Style ); Style style() const; virtual void draw( QPainter *, const QwtColumnRect & ) const; protected: void drawBox( QPainter *, const QwtColumnRect & ) const; private: class PrivateData; PrivateData* d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_barchart.cpp000664 001750 001750 00000026351 12440612574 020040 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_barchart.h" #include "qwt_scale_map.h" #include "qwt_column_symbol.h" #include "qwt_painter.h" #include class QwtPlotBarChart::PrivateData { public: PrivateData(): symbol( NULL ), legendMode( QwtPlotBarChart::LegendChartTitle ) { } ~PrivateData() { delete symbol; } QwtColumnSymbol *symbol; QwtPlotBarChart::LegendMode legendMode; }; /*! Constructor \param title Title of the curve */ QwtPlotBarChart::QwtPlotBarChart( const QwtText &title ): QwtPlotAbstractBarChart( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotBarChart::QwtPlotBarChart( const QString &title ): QwtPlotAbstractBarChart( QwtText( title ) ) { init(); } //! Destructor QwtPlotBarChart::~QwtPlotBarChart() { delete d_data; } void QwtPlotBarChart::init() { d_data = new PrivateData; setData( new QwtPointSeriesData() ); } //! \return QwtPlotItem::Rtti_PlotBarChart int QwtPlotBarChart::rtti() const { return QwtPlotItem::Rtti_PlotBarChart; } /*! Initialize data with an array of points \param samples Vector of points \note QVector is implicitly shared \note QPolygonF is derived from QVector */ void QwtPlotBarChart::setSamples( const QVector &samples ) { setData( new QwtPointSeriesData( samples ) ); } /*! Initialize data with an array of doubles The indices in the array are taken as x coordinate, while the doubles are interpreted as y values. \param samples Vector of y coordinates \note QVector is implicitly shared */ void QwtPlotBarChart::setSamples( const QVector &samples ) { QVector points; for ( int i = 0; i < samples.size(); i++ ) points += QPointF( i, samples[ i ] ); setData( new QwtPointSeriesData( points ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotBarChart::setSamples( QwtSeriesData *data ) { setData( data ); } /*! \brief Assign a symbol The bar chart will take the ownership of the symbol, hence the previously set symbol will be delete by setting a new one. If \p symbol is \c NULL no symbol will be drawn. \param symbol Symbol \sa symbol() */ void QwtPlotBarChart::setSymbol( QwtColumnSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; legendChanged(); itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtColumnSymbol *QwtPlotBarChart::symbol() const { return d_data->symbol; } /*! Set the mode that decides what to display on the legend In case of LegendBarTitles barTitle() needs to be overloaded to return individual titles for each bar. \param mode New mode \sa legendMode(), legendData(), barTitle(), QwtPlotItem::ItemAttribute */ void QwtPlotBarChart::setLegendMode( LegendMode mode ) { if ( mode != d_data->legendMode ) { d_data->legendMode = mode; legendChanged(); } } /*! \return Legend mode \sa setLegendMode() */ QwtPlotBarChart::LegendMode QwtPlotBarChart::legendMode() const { return d_data->legendMode; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotBarChart::boundingRect() const { const size_t numSamples = dataSize(); if ( numSamples == 0 ) return QwtPlotSeriesItem::boundingRect(); const double baseLine = baseline(); QRectF rect = QwtPlotSeriesItem::boundingRect(); if ( rect.bottom() < baseLine ) rect.setBottom( baseLine ); if ( rect.top() > baseLine ) rect.setTop( baseLine ); if ( rect.isValid() && ( orientation() == Qt::Horizontal ) ) rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() ); return rect; } /*! Draw an interval of the bar chart \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. \sa drawSymbols() */ void QwtPlotBarChart::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; const QRectF br = data()->boundingRect(); const QwtInterval interval( br.left(), br.right() ); painter->save(); for ( int i = from; i <= to; i++ ) { drawSample( painter, xMap, yMap, canvasRect, interval, i, sample( i ) ); } painter->restore(); } /*! Draw a sample \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param boundingInterval Bounding interval of sample values \param index Index of the sample \param sample Value of the sample \sa drawSeries() */ void QwtPlotBarChart::drawSample( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QPointF &sample ) const { QwtColumnRect barRect; if ( orientation() == Qt::Horizontal ) { const double barHeight = sampleWidth( yMap, canvasRect.height(), boundingInterval.width(), sample.y() ); const double x1 = xMap.transform( baseline() ); const double x2 = xMap.transform( sample.y() ); const double y = yMap.transform( sample.x() ); const double y1 = y - 0.5 * barHeight; const double y2 = y + 0.5 * barHeight; barRect.direction = ( x1 < x2 ) ? QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft; barRect.hInterval = QwtInterval( x1, x2 ).normalized(); barRect.vInterval = QwtInterval( y1, y2 ); } else { const double barWidth = sampleWidth( xMap, canvasRect.width(), boundingInterval.width(), sample.y() ); const double x = xMap.transform( sample.x() ); const double x1 = x - 0.5 * barWidth; const double x2 = x + 0.5 * barWidth; const double y1 = yMap.transform( baseline() ); const double y2 = yMap.transform( sample.y() ); barRect.direction = ( y1 < y2 ) ? QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop; barRect.hInterval = QwtInterval( x1, x2 ); barRect.vInterval = QwtInterval( y1, y2 ).normalized(); } drawBar( painter, index, sample, barRect ); } /*! Draw a bar \param painter Painter \param sampleIndex Index of the sample represented by the bar \param sample Value of the sample \param rect Bounding rectangle of the bar */ void QwtPlotBarChart::drawBar( QPainter *painter, int sampleIndex, const QPointF &sample, const QwtColumnRect &rect ) const { const QwtColumnSymbol *specialSym = specialSymbol( sampleIndex, sample ); const QwtColumnSymbol *sym = specialSym; if ( sym == NULL ) sym = d_data->symbol; if ( sym ) { sym->draw( painter, rect ); } else { // we build a temporary default symbol QwtColumnSymbol sym( QwtColumnSymbol::Box ); sym.setLineWidth( 1 ); sym.setFrameStyle( QwtColumnSymbol::Plain ); sym.draw( painter, rect ); } delete specialSym; } /*! Needs to be overloaded to return a non default symbol for a specific sample \param sampleIndex Index of the sample represented by the bar \param sample Value of the sample \return NULL, indicating to use the default symbol */ QwtColumnSymbol *QwtPlotBarChart::specialSymbol( int sampleIndex, const QPointF &sample ) const { Q_UNUSED( sampleIndex ); Q_UNUSED( sample ); return NULL; } /*! \brief Return the title of a bar In LegendBarTitles mode the title is displayed on the legend entry corresponding to a bar. The default implementation is a dummy, that is intended to be overloaded. \param sampleIndex Index of the bar \return An empty text \sa LegendBarTitles */ QwtText QwtPlotBarChart::barTitle( int sampleIndex ) const { Q_UNUSED( sampleIndex ); return QwtText(); } /*! \brief Return all information, that is needed to represent the item on the legend In case of LegendBarTitles an entry for each bar is returned, otherwise the chart is represented like any other plot item from its title() and the legendIcon(). \return Information, that is needed to represent the item on the legend \sa title(), setLegendMode(), barTitle(), QwtLegend, QwtPlotLegendItem */ QList QwtPlotBarChart::legendData() const { QList list; if ( d_data->legendMode == LegendBarTitles ) { const size_t numSamples = dataSize(); for ( size_t i = 0; i < numSamples; i++ ) { QwtLegendData data; QVariant titleValue; qVariantSetValue( titleValue, barTitle( i ) ); data.setValue( QwtLegendData::TitleRole, titleValue ); if ( !legendIconSize().isEmpty() ) { QVariant iconValue; qVariantSetValue( iconValue, legendIcon( i, legendIconSize() ) ); data.setValue( QwtLegendData::IconRole, iconValue ); } list += data; } } else { return QwtPlotAbstractBarChart::legendData(); } return list; } /*! \return Icon representing a bar or the chart on the legend When the legendMode() is LegendBarTitles the icon shows the bar corresponding to index - otherwise the bar displays the default symbol. \param index Index of the legend entry \param size Icon size \sa setLegendMode(), drawBar(), QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData() */ QwtGraphic QwtPlotBarChart::legendIcon( int index, const QSizeF &size ) const { QwtColumnRect column; column.hInterval = QwtInterval( 0.0, size.width() - 1.0 ); column.vInterval = QwtInterval( 0.0, size.height() - 1.0 ); QwtGraphic icon; icon.setDefaultSize( size ); icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true ); QPainter painter( &icon ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); int barIndex = -1; if ( d_data->legendMode == QwtPlotBarChart::LegendBarTitles ) barIndex = index; drawBar( &painter, barIndex, QPointF(), column ); return icon; } qsstv_8.2.12/qwt/qwt_compass.cpp000664 001750 001750 00000016354 12440612574 016663 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_compass.h" #include "qwt_compass_rose.h" #include "qwt_math.h" #include "qwt_scale_draw.h" #include "qwt_painter.h" #include "qwt_dial_needle.h" #include #include #include /*! \brief Constructor Initializes a label map for multiples of 45 degrees */ QwtCompassScaleDraw::QwtCompassScaleDraw() { enableComponent( QwtAbstractScaleDraw::Backbone, false ); enableComponent( QwtAbstractScaleDraw::Ticks, false ); d_labelMap.insert( 0.0, QString::fromLatin1( "N" ) ); d_labelMap.insert( 45.0, QString::fromLatin1( "NE" ) ); d_labelMap.insert( 90.0, QString::fromLatin1( "E" ) ); d_labelMap.insert( 135.0, QString::fromLatin1( "SE" ) ); d_labelMap.insert( 180.0, QString::fromLatin1( "S" ) ); d_labelMap.insert( 225.0, QString::fromLatin1( "SW" ) ); d_labelMap.insert( 270.0, QString::fromLatin1( "W" ) ); d_labelMap.insert( 315.0, QString::fromLatin1( "NW" ) ); #if 0 d_labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) ); d_labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) ); d_labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) ); d_labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) ); d_labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) ); d_labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) ); d_labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) ); d_labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) ); #endif } /*! \brief Constructor \param map Value to label map */ QwtCompassScaleDraw::QwtCompassScaleDraw( const QMap &map ): d_labelMap( map ) { enableComponent( QwtAbstractScaleDraw::Backbone, false ); enableComponent( QwtAbstractScaleDraw::Ticks, false ); } /*! \brief Set a map, mapping values to labels \param map Value to label map The values of the major ticks are found by looking into this map. The default map consists of the labels N, NE, E, SE, S, SW, W, NW. \warning The map will have no effect for values that are no major tick values. Major ticks can be changed by QwtScaleDraw::setScale \sa labelMap(), scaleDraw(), setScale() */ void QwtCompassScaleDraw::setLabelMap( const QMap &map ) { d_labelMap = map; } /*! \return map, mapping values to labels \sa setLabelMap() */ QMap QwtCompassScaleDraw::labelMap() const { return d_labelMap; } /*! Map a value to a corresponding label \param value Value that will be mapped label() looks in the labelMap() for a corresponding label for value or returns an null text. \return Label, or QString::null \sa labelMap(), setLabelMap() */ QwtText QwtCompassScaleDraw::label( double value ) const { if ( qFuzzyCompare( value + 1.0, 1.0 ) ) value = 0.0; if ( value < 0.0 ) value += 360.0; if ( d_labelMap.contains( value ) ) return d_labelMap[value]; return QwtText(); } class QwtCompass::PrivateData { public: PrivateData(): rose( NULL ) { } ~PrivateData() { delete rose; } QwtCompassRose *rose; }; /*! \brief Constructor \param parent Parent widget Create a compass widget with a scale, no needle and no rose. The default origin is 270.0 with no valid value. It accepts mouse and keyboard inputs and has no step size. The default mode is QwtDial::RotateNeedle. */ QwtCompass::QwtCompass( QWidget* parent ): QwtDial( parent ) { d_data = new PrivateData; setScaleDraw( new QwtCompassScaleDraw() ); setOrigin( 270.0 ); setWrapping( true ); setScaleMaxMajor( 36 ); setScaleMaxMinor( 10 ); setScale( 0.0, 360.0 ); // degrees as default setTotalSteps( 360 ); } //! Destructor QwtCompass::~QwtCompass() { delete d_data; } /*! Draw the contents of the scale \param painter Painter \param center Center of the content circle \param radius Radius of the content circle */ void QwtCompass::drawScaleContents( QPainter *painter, const QPointF ¢er, double radius ) const { QPalette::ColorGroup cg; if ( isEnabled() ) cg = hasFocus() ? QPalette::Active : QPalette::Inactive; else cg = QPalette::Disabled; double north = origin(); if ( isValid() ) { if ( mode() == RotateScale ) north -= value(); } const int margin = 4; drawRose( painter, center, radius - margin, 360.0 - north, cg ); } /*! Draw the compass rose \param painter Painter \param center Center of the compass \param radius of the circle, where to paint the rose \param north Direction pointing north, in degrees counter clockwise \param cg Color group */ void QwtCompass::drawRose( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup cg ) const { if ( d_data->rose ) d_data->rose->draw( painter, center, radius, north, cg ); } /*! Set a rose for the compass \param rose Compass rose \warning The rose will be deleted, when a different rose is set or in ~QwtCompass \sa rose() */ void QwtCompass::setRose( QwtCompassRose *rose ) { if ( rose != d_data->rose ) { if ( d_data->rose ) delete d_data->rose; d_data->rose = rose; update(); } } /*! \return rose \sa setRose() */ const QwtCompassRose *QwtCompass::rose() const { return d_data->rose; } /*! \return rose \sa setRose() */ QwtCompassRose *QwtCompass::rose() { return d_data->rose; } /*! Handles key events Beside the keys described in QwtDial::keyPressEvent numbers from 1-9 (without 5) set the direction according to their position on the num pad. \sa isReadOnly() */ void QwtCompass::keyPressEvent( QKeyEvent *kev ) { if ( isReadOnly() ) return; #if 0 if ( kev->key() == Key_5 ) { invalidate(); // signal ??? return; } #endif double newValue = value(); if ( kev->key() >= Qt::Key_1 && kev->key() <= Qt::Key_9 ) { if ( mode() != RotateNeedle || kev->key() == Qt::Key_5 ) return; switch ( kev->key() ) { case Qt::Key_6: newValue = 180.0 * 0.0; break; case Qt::Key_3: newValue = 180.0 * 0.25; break; case Qt::Key_2: newValue = 180.0 * 0.5; break; case Qt::Key_1: newValue = 180.0 * 0.75; break; case Qt::Key_4: newValue = 180.0 * 1.0; break; case Qt::Key_7: newValue = 180.0 * 1.25; break; case Qt::Key_8: newValue = 180.0 * 1.5; break; case Qt::Key_9: newValue = 180.0 * 1.75; break; } newValue -= origin(); setValue( newValue ); } else { QwtDial::keyPressEvent( kev ); } } qsstv_8.2.12/qwt/qwt_plot_layout.cpp000664 001750 001750 00000125615 12440612574 017572 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_layout.h" #include "qwt_text.h" #include "qwt_text_label.h" #include "qwt_scale_widget.h" #include "qwt_abstract_legend.h" #include #include class QwtPlotLayout::LayoutData { public: void init( const QwtPlot *, const QRectF &rect ); struct t_legendData { int frameWidth; int hScrollExtent; int vScrollExtent; QSize hint; } legend; struct t_titleData { QwtText text; int frameWidth; } title; struct t_footerData { QwtText text; int frameWidth; } footer; struct t_scaleData { bool isEnabled; const QwtScaleWidget *scaleWidget; QFont scaleFont; int start; int end; int baseLineOffset; double tickOffset; int dimWithoutTitle; } scale[QwtPlot::axisCnt]; struct t_canvasData { int contentsMargins[ QwtPlot::axisCnt ]; } canvas; }; /* Extract all layout relevant data from the plot components */ void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect ) { // legend if ( plot->legend() ) { legend.frameWidth = plot->legend()->frameWidth(); legend.hScrollExtent = plot->legend()->scrollExtent( Qt::Horizontal ); legend.vScrollExtent = plot->legend()->scrollExtent( Qt::Vertical ); const QSize hint = plot->legend()->sizeHint(); int w = qMin( hint.width(), qFloor( rect.width() ) ); int h = plot->legend()->heightForWidth( w ); if ( h <= 0 ) h = hint.height(); if ( h > rect.height() ) w += legend.hScrollExtent; legend.hint = QSize( w, h ); } // title title.frameWidth = 0; title.text = QwtText(); if ( plot->titleLabel() ) { const QwtTextLabel *label = plot->titleLabel(); title.text = label->text(); if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) ) title.text.setFont( label->font() ); title.frameWidth = plot->titleLabel()->frameWidth(); } // footer footer.frameWidth = 0; footer.text = QwtText(); if ( plot->footerLabel() ) { const QwtTextLabel *label = plot->footerLabel(); footer.text = label->text(); if ( !( footer.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) ) footer.text.setFont( label->font() ); footer.frameWidth = plot->footerLabel()->frameWidth(); } // scales for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scaleWidget = plot->axisWidget( axis ); scale[axis].isEnabled = true; scale[axis].scaleWidget = scaleWidget; scale[axis].scaleFont = scaleWidget->font(); scale[axis].start = scaleWidget->startBorderDist(); scale[axis].end = scaleWidget->endBorderDist(); scale[axis].baseLineOffset = scaleWidget->margin(); scale[axis].tickOffset = scaleWidget->margin(); if ( scaleWidget->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) { scale[axis].tickOffset += scaleWidget->scaleDraw()->maxTickLength(); } scale[axis].dimWithoutTitle = scaleWidget->dimForLength( QWIDGETSIZE_MAX, scale[axis].scaleFont ); if ( !scaleWidget->title().isEmpty() ) { scale[axis].dimWithoutTitle -= scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX ); } } else { scale[axis].isEnabled = false; scale[axis].start = 0; scale[axis].end = 0; scale[axis].baseLineOffset = 0; scale[axis].tickOffset = 0.0; scale[axis].dimWithoutTitle = 0; } } // canvas plot->canvas()->getContentsMargins( &canvas.contentsMargins[ QwtPlot::yLeft ], &canvas.contentsMargins[ QwtPlot::xTop ], &canvas.contentsMargins[ QwtPlot::yRight ], &canvas.contentsMargins[ QwtPlot::xBottom ] ); } class QwtPlotLayout::PrivateData { public: PrivateData(): spacing( 5 ) { } QRectF titleRect; QRectF footerRect; QRectF legendRect; QRectF scaleRect[QwtPlot::axisCnt]; QRectF canvasRect; QwtPlotLayout::LayoutData layoutData; QwtPlot::LegendPosition legendPos; double legendRatio; unsigned int spacing; unsigned int canvasMargin[QwtPlot::axisCnt]; bool alignCanvasToScales[QwtPlot::axisCnt]; }; /*! \brief Constructor */ QwtPlotLayout::QwtPlotLayout() { d_data = new PrivateData; setLegendPosition( QwtPlot::BottomLegend ); setCanvasMargin( 4 ); setAlignCanvasToScales( false ); invalidate(); } //! Destructor QwtPlotLayout::~QwtPlotLayout() { delete d_data; } /*! Change a margin of the canvas. The margin is the space above/below the scale ticks. A negative margin will be set to -1, excluding the borders of the scales. \param margin New margin \param axis One of QwtPlot::Axis. Specifies where the position of the margin. -1 means margin at all borders. \sa canvasMargin() \warning The margin will have no effect when alignCanvasToScale() is true */ void QwtPlotLayout::setCanvasMargin( int margin, int axis ) { if ( margin < -1 ) margin = -1; if ( axis == -1 ) { for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->canvasMargin[axis] = margin; } else if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->canvasMargin[axis] = margin; } /*! \param axisId Axis index \return Margin around the scale tick borders \sa setCanvasMargin() */ int QwtPlotLayout::canvasMargin( int axisId ) const { if ( axisId < 0 || axisId >= QwtPlot::axisCnt ) return 0; return d_data->canvasMargin[axisId]; } /*! \brief Set the align-canvas-to-axis-scales flag for all axes \param on True/False \sa setAlignCanvasToScale(), alignCanvasToScale() */ void QwtPlotLayout::setAlignCanvasToScales( bool on ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->alignCanvasToScales[axis] = on; } /*! Change the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size, - align with the axis scale ends to control its size. The axisId parameter is somehow confusing as it identifies a border of the plot and not the axes, that are aligned. F.e when QwtPlot::yLeft is set, the left end of the the x-axes ( QwtPlot::xTop, QwtPlot::xBottom ) is aligned. \param axisId Axis index \param on New align-canvas-to-axis-scales setting \sa setCanvasMargin(), alignCanvasToScale(), setAlignCanvasToScales() \warning In case of on == true canvasMargin() will have no effect */ void QwtPlotLayout::setAlignCanvasToScale( int axisId, bool on ) { if ( axisId >= 0 && axisId < QwtPlot::axisCnt ) d_data->alignCanvasToScales[axisId] = on; } /*! Return the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size - align with the axis scale ends to control its size. \param axisId Axis index \return align-canvas-to-axis-scales setting \sa setAlignCanvasToScale(), setAlignCanvasToScale(), setCanvasMargin() */ bool QwtPlotLayout::alignCanvasToScale( int axisId ) const { if ( axisId < 0 || axisId >= QwtPlot::axisCnt ) return false; return d_data->alignCanvasToScales[ axisId ]; } /*! Change the spacing of the plot. The spacing is the distance between the plot components. \param spacing New spacing \sa setCanvasMargin(), spacing() */ void QwtPlotLayout::setSpacing( int spacing ) { d_data->spacing = qMax( 0, spacing ); } /*! \return Spacing \sa margin(), setSpacing() */ int QwtPlotLayout::spacing() const { return d_data->spacing; } /*! \brief Specify the position of the legend \param pos The legend's position. \param ratio Ratio between legend and the bounding rectangle of title, footer, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio ) { if ( ratio > 1.0 ) ratio = 1.0; switch ( pos ) { case QwtPlot::TopLegend: case QwtPlot::BottomLegend: if ( ratio <= 0.0 ) ratio = 0.33; d_data->legendRatio = ratio; d_data->legendPos = pos; break; case QwtPlot::LeftLegend: case QwtPlot::RightLegend: if ( ratio <= 0.0 ) ratio = 0.5; d_data->legendRatio = ratio; d_data->legendPos = pos; break; default: break; } } /*! \brief Specify the position of the legend \param pos The legend's position. Valid values are \c QwtPlot::LeftLegend, \c QwtPlot::RightLegend, \c QwtPlot::TopLegend, \c QwtPlot::BottomLegend. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos ) { setLegendPosition( pos, 0.0 ); } /*! \return Position of the legend \sa setLegendPosition(), QwtPlot::setLegendPosition(), QwtPlot::legendPosition() */ QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const { return d_data->legendPos; } /*! Specify the relative size of the legend in the plot \param ratio Ratio between legend and the bounding rectangle of title, footer, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. */ void QwtPlotLayout::setLegendRatio( double ratio ) { setLegendPosition( legendPosition(), ratio ); } /*! \return The relative size of the legend in the plot. \sa setLegendPosition() */ double QwtPlotLayout::legendRatio() const { return d_data->legendRatio; } /*! \brief Set the geometry for the title This method is intended to be used from derived layouts overloading activate() \sa titleRect(), activate() */ void QwtPlotLayout::setTitleRect( const QRectF &rect ) { d_data->titleRect = rect; } /*! \return Geometry for the title \sa activate(), invalidate() */ QRectF QwtPlotLayout::titleRect() const { return d_data->titleRect; } /*! \brief Set the geometry for the footer This method is intended to be used from derived layouts overloading activate() \sa footerRect(), activate() */ void QwtPlotLayout::setFooterRect( const QRectF &rect ) { d_data->footerRect = rect; } /*! \return Geometry for the footer \sa activate(), invalidate() */ QRectF QwtPlotLayout::footerRect() const { return d_data->footerRect; } /*! \brief Set the geometry for the legend This method is intended to be used from derived layouts overloading activate() \param rect Rectangle for the legend \sa legendRect(), activate() */ void QwtPlotLayout::setLegendRect( const QRectF &rect ) { d_data->legendRect = rect; } /*! \return Geometry for the legend \sa activate(), invalidate() */ QRectF QwtPlotLayout::legendRect() const { return d_data->legendRect; } /*! \brief Set the geometry for an axis This method is intended to be used from derived layouts overloading activate() \param axis Axis index \param rect Rectangle for the scale \sa scaleRect(), activate() */ void QwtPlotLayout::setScaleRect( int axis, const QRectF &rect ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->scaleRect[axis] = rect; } /*! \param axis Axis index \return Geometry for the scale \sa activate(), invalidate() */ QRectF QwtPlotLayout::scaleRect( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) { static QRectF dummyRect; return dummyRect; } return d_data->scaleRect[axis]; } /*! \brief Set the geometry for the canvas This method is intended to be used from derived layouts overloading activate() \sa canvasRect(), activate() */ void QwtPlotLayout::setCanvasRect( const QRectF &rect ) { d_data->canvasRect = rect; } /*! \return Geometry for the canvas \sa activate(), invalidate() */ QRectF QwtPlotLayout::canvasRect() const { return d_data->canvasRect; } /*! Invalidate the geometry of all components. \sa activate() */ void QwtPlotLayout::invalidate() { d_data->titleRect = d_data->footerRect = d_data->legendRect = d_data->canvasRect = QRect(); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->scaleRect[axis] = QRect(); } /*! \return Minimum size hint \param plot Plot widget \sa QwtPlot::minimumSizeHint() */ QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const { class ScaleData { public: ScaleData() { w = h = minLeft = minRight = tickOffset = 0; } int w; int h; int minLeft; int minRight; int tickOffset; } scaleData[QwtPlot::axisCnt]; int canvasBorder[QwtPlot::axisCnt]; int fw; plot->canvas()->getContentsMargins( &fw, NULL, NULL, NULL ); int axis; for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scl = plot->axisWidget( axis ); ScaleData &sd = scaleData[axis]; const QSize hint = scl->minimumSizeHint(); sd.w = hint.width(); sd.h = hint.height(); scl->getBorderDistHint( sd.minLeft, sd.minRight ); sd.tickOffset = scl->margin(); if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) sd.tickOffset += qCeil( scl->scaleDraw()->maxTickLength() ); } canvasBorder[axis] = fw + d_data->canvasMargin[axis] + 1; } for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { ScaleData &sd = scaleData[axis]; if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] ) && scaleData[QwtPlot::yLeft].w ) { int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft]; if ( shiftLeft > scaleData[QwtPlot::yLeft].w ) shiftLeft = scaleData[QwtPlot::yLeft].w; sd.w -= shiftLeft; } if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] ) && scaleData[QwtPlot::yRight].w ) { int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight]; if ( shiftRight > scaleData[QwtPlot::yRight].w ) shiftRight = scaleData[QwtPlot::yRight].w; sd.w -= shiftRight; } } if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) && scaleData[QwtPlot::xBottom].h ) { int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom]; if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset ) shiftBottom = scaleData[QwtPlot::xBottom].tickOffset; sd.h -= shiftBottom; } if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) && scaleData[QwtPlot::xTop].h ) { int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop]; if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset ) shiftTop = scaleData[QwtPlot::xTop].tickOffset; sd.h -= shiftTop; } } } const QWidget *canvas = plot->canvas(); int left, top, right, bottom; canvas->getContentsMargins( &left, &top, &right, &bottom ); const QSize minCanvasSize = canvas->minimumSize(); int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w ) + left + 1 + right + 1; w += qMax( cw, minCanvasSize.width() ); int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h; int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h ) + top + 1 + bottom + 1; h += qMax( ch, minCanvasSize.height() ); const QwtTextLabel *labels[2]; labels[0] = plot->titleLabel(); labels[1] = plot->footerLabel(); for ( int i = 0; i < 2; i++ ) { const QwtTextLabel *label = labels[i]; if ( label && !label->text().isEmpty() ) { // If only QwtPlot::yLeft or QwtPlot::yRight is showing, // we center on the plot canvas. const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft ) && plot->axisEnabled( QwtPlot::yRight ) ); int labelW = w; if ( centerOnCanvas ) { labelW -= scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } int labelH = label->heightForWidth( labelW ); if ( labelH > labelW ) // Compensate for a long title { w = labelW = labelH; if ( centerOnCanvas ) { w += scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } labelH = label->heightForWidth( labelW ); } h += labelH + d_data->spacing; } } // Compute the legend contribution const QwtAbstractLegend *legend = plot->legend(); if ( legend && !legend->isEmpty() ) { if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { int legendW = legend->sizeHint().width(); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) w += d_data->spacing; if ( legendH > h ) legendW += legend->scrollExtent( Qt::Horizontal ); if ( d_data->legendRatio < 1.0 ) legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) ); w += legendW + d_data->spacing; } else // QwtPlot::Top, QwtPlot::Bottom { int legendW = qMin( legend->sizeHint().width(), w ); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) h += d_data->spacing; if ( d_data->legendRatio < 1.0 ) legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) ); h += legendH + d_data->spacing; } } return QSize( w, h ); } /*! Find the geometry for the legend \param options Options how to layout the legend \param rect Rectangle where to place the legend \return Geometry for the legend \sa Options */ QRectF QwtPlotLayout::layoutLegend( Options options, const QRectF &rect ) const { const QSize hint( d_data->layoutData.legend.hint ); int dim; if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { // We don't allow vertical legends to take more than // half of the available space. dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) ); if ( !( options & IgnoreScrollbars ) ) { if ( hint.height() > rect.height() ) { // The legend will need additional // space for the vertical scrollbar. dim += d_data->layoutData.legend.hScrollExtent; } } } else { dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) ); dim = qMax( dim, d_data->layoutData.legend.vScrollExtent ); } QRectF legendRect = rect; switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: legendRect.setWidth( dim ); break; case QwtPlot::RightLegend: legendRect.setX( rect.right() - dim ); legendRect.setWidth( dim ); break; case QwtPlot::TopLegend: legendRect.setHeight( dim ); break; case QwtPlot::BottomLegend: legendRect.setY( rect.bottom() - dim ); legendRect.setHeight( dim ); break; } return legendRect; } /*! Align the legend to the canvas \param canvasRect Geometry of the canvas \param legendRect Maximum geometry for the legend \return Geometry for the aligned legend */ QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect, const QRectF &legendRect ) const { QRectF alignedRect = legendRect; if ( d_data->legendPos == QwtPlot::BottomLegend || d_data->legendPos == QwtPlot::TopLegend ) { if ( d_data->layoutData.legend.hint.width() < canvasRect.width() ) { alignedRect.setX( canvasRect.x() ); alignedRect.setWidth( canvasRect.width() ); } } else { if ( d_data->layoutData.legend.hint.height() < canvasRect.height() ) { alignedRect.setY( canvasRect.y() ); alignedRect.setHeight( canvasRect.height() ); } } return alignedRect; } /*! Expand all line breaks in text labels, and calculate the height of their widgets in orientation of the text. \param options Options how to layout the legend \param rect Bounding rectangle for title, footer, axes and canvas. \param dimTitle Expanded height of the title widget \param dimFooter Expanded height of the footer widget \param dimAxis Expanded heights of the axis in axis orientation. \sa Options */ void QwtPlotLayout::expandLineBreaks( Options options, const QRectF &rect, int &dimTitle, int &dimFooter, int dimAxis[QwtPlot::axisCnt] ) const { dimTitle = dimFooter = 0; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) dimAxis[axis] = 0; int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !( options & IgnoreFrames ) ) backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[ axis ]; if ( !d_data->alignCanvasToScales[axis] ) backboneOffset[axis] += d_data->canvasMargin[axis]; } bool done = false; while ( !done ) { done = true; // the size for the 4 axis depend on each other. Expanding // the height of a horizontal axis will shrink the height // for the vertical axis, shrinking the height of a vertical // axis will result in a line break what will expand the // width and results in shrinking the width of a horizontal // axis what might result in a line break of a horizontal // axis ... . So we loop as long until no size changes. if ( !( ( options & IgnoreTitle ) || d_data->layoutData.title.text.isEmpty() ) ) { double w = rect.width(); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // center to the canvas w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; } int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) ); if ( !( options & IgnoreFrames ) ) d += 2 * d_data->layoutData.title.frameWidth; if ( d > dimTitle ) { dimTitle = d; done = false; } } if ( !( ( options & IgnoreFooter ) || d_data->layoutData.footer.text.isEmpty() ) ) { double w = rect.width(); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // center to the canvas w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; } int d = qCeil( d_data->layoutData.footer.text.heightForWidth( w ) ); if ( !( options & IgnoreFrames ) ) d += 2 * d_data->layoutData.footer.frameWidth; if ( d > dimFooter ) { dimFooter = d; done = false; } } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { const struct LayoutData::t_scaleData &scaleData = d_data->layoutData.scale[axis]; if ( scaleData.isEnabled ) { double length; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { length = rect.width() - dimAxis[QwtPlot::yLeft] - dimAxis[QwtPlot::yRight]; length -= scaleData.start + scaleData.end; if ( dimAxis[QwtPlot::yRight] > 0 ) length -= 1; length += qMin( dimAxis[QwtPlot::yLeft], scaleData.start - backboneOffset[QwtPlot::yLeft] ); length += qMin( dimAxis[QwtPlot::yRight], scaleData.end - backboneOffset[QwtPlot::yRight] ); } else // QwtPlot::yLeft, QwtPlot::yRight { length = rect.height() - dimAxis[QwtPlot::xTop] - dimAxis[QwtPlot::xBottom]; length -= scaleData.start + scaleData.end; length -= 1; if ( dimAxis[QwtPlot::xBottom] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xTop] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xBottom] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xBottom].tickOffset, double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) ); } if ( dimAxis[QwtPlot::xTop] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xTop].tickOffset, double( scaleData.end - backboneOffset[QwtPlot::xTop] ) ); } if ( dimTitle > 0 ) length -= dimTitle + d_data->spacing; } int d = scaleData.dimWithoutTitle; if ( !scaleData.scaleWidget->title().isEmpty() ) { d += scaleData.scaleWidget->titleHeightForWidth( qFloor( length ) ); } if ( d > dimAxis[axis] ) { dimAxis[axis] = d; done = false; } } } } } /*! Align the ticks of the axis to the canvas borders using the empty corners. \param options Layout options \param canvasRect Geometry of the canvas ( IN/OUT ) \param scaleRect Geometries of the scales ( IN/OUT ) \sa Options */ void QwtPlotLayout::alignScales( Options options, QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const { int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !d_data->alignCanvasToScales[axis] ) { backboneOffset[axis] += d_data->canvasMargin[axis]; } if ( !( options & IgnoreFrames ) ) { backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[axis]; } } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( !scaleRect[axis].isValid() ) continue; const int startDist = d_data->layoutData.scale[axis].start; const int endDist = d_data->layoutData.scale[axis].end; QRectF &axisRect = scaleRect[axis]; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft]; const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist; if ( leftScaleRect.isValid() ) { const double dx = leftOffset + leftScaleRect.width(); if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && dx < 0.0 ) { /* The axis needs more space than the width of the left scale. */ const double cLeft = canvasRect.left(); // qreal -> double canvasRect.setLeft( qMax( cLeft, axisRect.left() - dx ) ); } else { const double minLeft = leftScaleRect.left(); const double left = axisRect.left() + leftOffset; axisRect.setLeft( qMax( left, minLeft ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && leftOffset < 0 ) { canvasRect.setLeft( qMax( canvasRect.left(), axisRect.left() - leftOffset ) ); } else { if ( leftOffset > 0 ) axisRect.setLeft( axisRect.left() + leftOffset ); } } const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight]; const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist + 1; if ( rightScaleRect.isValid() ) { const double dx = rightOffset + rightScaleRect.width(); if ( d_data->alignCanvasToScales[QwtPlot::yRight] && dx < 0 ) { /* The axis needs more space than the width of the right scale. */ const double cRight = canvasRect.right(); // qreal -> double canvasRect.setRight( qMin( cRight, axisRect.right() + dx ) ); } const double maxRight = rightScaleRect.right(); const double right = axisRect.right() - rightOffset; axisRect.setRight( qMin( right, maxRight ) ); } else { if ( d_data->alignCanvasToScales[QwtPlot::yRight] && rightOffset < 0 ) { canvasRect.setRight( qMin( canvasRect.right(), axisRect.right() + rightOffset ) ); } else { if ( rightOffset > 0 ) axisRect.setRight( axisRect.right() - rightOffset ); } } } else // QwtPlot::yLeft, QwtPlot::yRight { const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom]; const int bottomOffset = backboneOffset[QwtPlot::xBottom] - endDist + 1; if ( bottomScaleRect.isValid() ) { const double dy = bottomOffset + bottomScaleRect.height(); if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && dy < 0 ) { /* The axis needs more space than the height of the bottom scale. */ const double cBottom = canvasRect.bottom(); // qreal -> double canvasRect.setBottom( qMin( cBottom, axisRect.bottom() + dy ) ); } else { const double maxBottom = bottomScaleRect.top() + d_data->layoutData.scale[QwtPlot::xBottom].tickOffset; const double bottom = axisRect.bottom() - bottomOffset; axisRect.setBottom( qMin( bottom, maxBottom ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && bottomOffset < 0 ) { canvasRect.setBottom( qMin( canvasRect.bottom(), axisRect.bottom() + bottomOffset ) ); } else { if ( bottomOffset > 0 ) axisRect.setBottom( axisRect.bottom() - bottomOffset ); } } const QRectF &topScaleRect = scaleRect[QwtPlot::xTop]; const int topOffset = backboneOffset[QwtPlot::xTop] - startDist; if ( topScaleRect.isValid() ) { const double dy = topOffset + topScaleRect.height(); if ( d_data->alignCanvasToScales[QwtPlot::xTop] && dy < 0 ) { /* The axis needs more space than the height of the top scale. */ const double cTop = canvasRect.top(); // qreal -> double canvasRect.setTop( qMax( cTop, axisRect.top() - dy ) ); } else { const double minTop = topScaleRect.bottom() - d_data->layoutData.scale[QwtPlot::xTop].tickOffset; const double top = axisRect.top() + topOffset; axisRect.setTop( qMax( top, minTop ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xTop] && topOffset < 0 ) { canvasRect.setTop( qMax( canvasRect.top(), axisRect.top() - topOffset ) ); } else { if ( topOffset > 0 ) axisRect.setTop( axisRect.top() + topOffset ); } } } } /* The canvas has been aligned to the scale with largest border distances. Now we have to realign the other scale. */ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { QRectF &sRect = scaleRect[axis]; if ( !sRect.isValid() ) continue; if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { if ( d_data->alignCanvasToScales[QwtPlot::yLeft] ) { double y = canvasRect.left() - d_data->layoutData.scale[axis].start; if ( !( options & IgnoreFrames ) ) y += d_data->layoutData.canvas.contentsMargins[ QwtPlot::yLeft ]; sRect.setLeft( y ); } if ( d_data->alignCanvasToScales[QwtPlot::yRight] ) { double y = canvasRect.right() - 1 + d_data->layoutData.scale[axis].end; if ( !( options & IgnoreFrames ) ) y -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::yRight ]; sRect.setRight( y ); } if ( d_data->alignCanvasToScales[ axis ] ) { if ( axis == QwtPlot::xTop ) sRect.setBottom( canvasRect.top() ); else sRect.setTop( canvasRect.bottom() ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xTop] ) { double x = canvasRect.top() - d_data->layoutData.scale[axis].start; if ( !( options & IgnoreFrames ) ) x += d_data->layoutData.canvas.contentsMargins[ QwtPlot::xTop ]; sRect.setTop( x ); } if ( d_data->alignCanvasToScales[QwtPlot::xBottom] ) { double x = canvasRect.bottom() - 1 + d_data->layoutData.scale[axis].end; if ( !( options & IgnoreFrames ) ) x -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::xBottom ]; sRect.setBottom( x ); } if ( d_data->alignCanvasToScales[ axis ] ) { if ( axis == QwtPlot::yLeft ) sRect.setRight( canvasRect.left() ); else sRect.setLeft( canvasRect.right() ); } } } } /*! \brief Recalculate the geometry of all components. \param plot Plot to be layout \param plotRect Rectangle where to place the components \param options Layout options \sa invalidate(), titleRect(), footerRect() legendRect(), scaleRect(), canvasRect() */ void QwtPlotLayout::activate( const QwtPlot *plot, const QRectF &plotRect, Options options ) { invalidate(); QRectF rect( plotRect ); // undistributed rest of the plot rect // We extract all layout relevant parameters from the widgets, // and save them to d_data->layoutData. d_data->layoutData.init( plot, rect ); if ( !( options & IgnoreLegend ) && plot->legend() && !plot->legend()->isEmpty() ) { d_data->legendRect = layoutLegend( options, rect ); // subtract d_data->legendRect from rect const QRegion region( rect.toRect() ); rect = region.subtracted( d_data->legendRect.toRect() ).boundingRect(); switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: rect.setLeft( rect.left() + d_data->spacing ); break; case QwtPlot::RightLegend: rect.setRight( rect.right() - d_data->spacing ); break; case QwtPlot::TopLegend: rect.setTop( rect.top() + d_data->spacing ); break; case QwtPlot::BottomLegend: rect.setBottom( rect.bottom() - d_data->spacing ); break; } } /* +---+-----------+---+ | Title | +---+-----------+---+ | | Axis | | +---+-----------+---+ | A | | A | | x | Canvas | x | | i | | i | | s | | s | +---+-----------+---+ | | Axis | | +---+-----------+---+ | Footer | +---+-----------+---+ */ // title, footer and axes include text labels. The height of each // label depends on its line breaks, that depend on the width // for the label. A line break in a horizontal text will reduce // the available width for vertical texts and vice versa. // expandLineBreaks finds the height/width for title, footer and axes // including all line breaks. int dimTitle, dimFooter, dimAxes[QwtPlot::axisCnt]; expandLineBreaks( options, rect, dimTitle, dimFooter, dimAxes ); if ( dimTitle > 0 ) { d_data->titleRect.setRect( rect.left(), rect.top(), rect.width(), dimTitle ); rect.setTop( d_data->titleRect.bottom() + d_data->spacing ); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // if only one of the y axes is missing we align // the title centered to the canvas d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] ); d_data->titleRect.setWidth( rect.width() - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] ); } } if ( dimFooter > 0 ) { d_data->footerRect.setRect( rect.left(), rect.bottom() - dimFooter, rect.width(), dimFooter ); rect.setBottom( d_data->footerRect.top() - d_data->spacing ); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // if only one of the y axes is missing we align // the footer centered to the canvas d_data->footerRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] ); d_data->footerRect.setWidth( rect.width() - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] ); } } d_data->canvasRect.setRect( rect.x() + dimAxes[QwtPlot::yLeft], rect.y() + dimAxes[QwtPlot::xTop], rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft], rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { // set the rects for the axes if ( dimAxes[axis] ) { int dim = dimAxes[axis]; QRectF &scaleRect = d_data->scaleRect[axis]; scaleRect = d_data->canvasRect; switch ( axis ) { case QwtPlot::yLeft: scaleRect.setX( d_data->canvasRect.left() - dim ); scaleRect.setWidth( dim ); break; case QwtPlot::yRight: scaleRect.setX( d_data->canvasRect.right() ); scaleRect.setWidth( dim ); break; case QwtPlot::xBottom: scaleRect.setY( d_data->canvasRect.bottom() ); scaleRect.setHeight( dim ); break; case QwtPlot::xTop: scaleRect.setY( d_data->canvasRect.top() - dim ); scaleRect.setHeight( dim ); break; } scaleRect = scaleRect.normalized(); } } // +---+-----------+---+ // | <- Axis -> | // +-^-+-----------+-^-+ // | | | | | | // | | | | // | A | | A | // | x | Canvas | x | // | i | | i | // | s | | s | // | | | | // | | | | | | // +-V-+-----------+-V-+ // | <- Axis -> | // +---+-----------+---+ // The ticks of the axes - not the labels above - should // be aligned to the canvas. So we try to use the empty // corners to extend the axes, so that the label texts // left/right of the min/max ticks are moved into them. alignScales( options, d_data->canvasRect, d_data->scaleRect ); if ( !d_data->legendRect.isEmpty() ) { // We prefer to align the legend to the canvas - not to // the complete plot - if possible. d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect ); } } qsstv_8.2.12/qwt/qwt_compass.h000664 001750 001750 00000004027 12440612574 016322 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COMPASS_H #define QWT_COMPASS_H 1 #include "qwt_global.h" #include "qwt_dial.h" #include "qwt_round_scale_draw.h" #include #include class QwtCompassRose; /*! \brief A special scale draw made for QwtCompass QwtCompassScaleDraw maps values to strings using a special map, that can be modified by the application The default map consists of the labels N, NE, E, SE, S, SW, W, NW. \sa QwtCompass */ class QWT_EXPORT QwtCompassScaleDraw: public QwtRoundScaleDraw { public: explicit QwtCompassScaleDraw(); explicit QwtCompassScaleDraw( const QMap &map ); void setLabelMap( const QMap &map ); QMap labelMap() const; virtual QwtText label( double value ) const; private: QMap d_labelMap; }; /*! \brief A Compass Widget QwtCompass is a widget to display and enter directions. It consists of a scale, an optional needle and rose. \image html dials1.png \note The examples/dials example shows how to use QwtCompass. */ class QWT_EXPORT QwtCompass: public QwtDial { Q_OBJECT public: explicit QwtCompass( QWidget* parent = NULL ); virtual ~QwtCompass(); void setRose( QwtCompassRose *rose ); const QwtCompassRose *rose() const; QwtCompassRose *rose(); protected: virtual void drawRose( QPainter *, const QPointF ¢er, double radius, double north, QPalette::ColorGroup ) const; virtual void drawScaleContents( QPainter *, const QPointF ¢er, double radius ) const; virtual void keyPressEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_axis.cpp000664 001750 001750 00000043327 12440612574 017220 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_math.h" #include "qwt_scale_widget.h" #include "qwt_scale_div.h" #include "qwt_scale_engine.h" class QwtPlot::AxisData { public: bool isEnabled; bool doAutoScale; double minValue; double maxValue; double stepSize; int maxMajor; int maxMinor; bool isValid; QwtScaleDiv scaleDiv; QwtScaleEngine *scaleEngine; QwtScaleWidget *scaleWidget; }; //! Initialize axes void QwtPlot::initAxesData() { int axisId; for ( axisId = 0; axisId < axisCnt; axisId++ ) d_axisData[axisId] = new AxisData; d_axisData[yLeft]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::LeftScale, this ); d_axisData[yRight]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::RightScale, this ); d_axisData[xTop]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::TopScale, this ); d_axisData[xBottom]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::BottomScale, this ); d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" ); d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" ); d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" ); d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" ); #if 1 // better find the font sizes from the application font QFont fscl( fontInfo().family(), 10 ); QFont fttl( fontInfo().family(), 12, QFont::Bold ); #endif for ( axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; d.scaleEngine = new QwtLinearScaleEngine; d.scaleWidget->setTransformation( d.scaleEngine->transformation() ); d.scaleWidget->setFont( fscl ); d.scaleWidget->setMargin( 2 ); QwtText text = d.scaleWidget->title(); text.setFont( fttl ); d.scaleWidget->setTitle( text ); d.doAutoScale = true; d.minValue = 0.0; d.maxValue = 1000.0; d.stepSize = 0.0; d.maxMinor = 5; d.maxMajor = 8; d.isValid = false; } d_axisData[yLeft]->isEnabled = true; d_axisData[yRight]->isEnabled = false; d_axisData[xBottom]->isEnabled = true; d_axisData[xTop]->isEnabled = false; } void QwtPlot::deleteAxesData() { for ( int axisId = 0; axisId < axisCnt; axisId++ ) { delete d_axisData[axisId]->scaleEngine; delete d_axisData[axisId]; d_axisData[axisId] = NULL; } } /*! \return Scale widget of the specified axis, or NULL if axisId is invalid. \param axisId Axis index */ const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! \return Scale widget of the specified axis, or NULL if axisId is invalid. \param axisId Axis index */ QwtScaleWidget *QwtPlot::axisWidget( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! Change the scale engine for an axis \param axisId Axis index \param scaleEngine Scale engine \sa axisScaleEngine() */ void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine ) { if ( axisValid( axisId ) && scaleEngine != NULL ) { AxisData &d = *d_axisData[axisId]; delete d.scaleEngine; d.scaleEngine = scaleEngine; d_axisData[axisId]->scaleWidget->setTransformation( scaleEngine->transformation() ); d.isValid = false; autoRefresh(); } } /*! \param axisId Axis index \return Scale engine for a specific axis */ QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \param axisId Axis index \return Scale engine for a specific axis */ const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \return \c True, if autoscaling is enabled \param axisId Axis index */ bool QwtPlot::axisAutoScale( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->doAutoScale; else return false; } /*! \return \c True, if a specified axis is enabled \param axisId Axis index */ bool QwtPlot::axisEnabled( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->isEnabled; else return false; } /*! \return The font of the scale labels for a specified axis \param axisId Axis index */ QFont QwtPlot::axisFont( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->font(); else return QFont(); } /*! \return The maximum number of major ticks for a specified axis \param axisId Axis index \sa setAxisMaxMajor(), QwtScaleEngine::divideScale() */ int QwtPlot::axisMaxMajor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMajor; else return 0; } /*! \return the maximum number of minor ticks for a specified axis \param axisId Axis index \sa setAxisMaxMinor(), QwtScaleEngine::divideScale() */ int QwtPlot::axisMaxMinor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMinor; else return 0; } /*! \brief Return the scale division of a specified axis axisScaleDiv(axisId).lowerBound(), axisScaleDiv(axisId).upperBound() are the current limits of the axis scale. \param axisId Axis index \return Scale division \sa QwtScaleDiv, setAxisScaleDiv(), QwtScaleEngine::divideScale() */ const QwtScaleDiv &QwtPlot::axisScaleDiv( int axisId ) const { return d_axisData[axisId]->scaleDiv; } /*! \brief Return the scale draw of a specified axis \param axisId Axis index \return Specified scaleDraw for axis, or NULL if axis is invalid. */ const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! \brief Return the scale draw of a specified axis \param axisId Axis index \return Specified scaleDraw for axis, or NULL if axis is invalid. */ QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! \brief Return the step size parameter that has been set in setAxisScale. This doesn't need to be the step size of the current scale. \param axisId Axis index \return step size parameter value \sa setAxisScale(), QwtScaleEngine::divideScale() */ double QwtPlot::axisStepSize( int axisId ) const { if ( !axisValid( axisId ) ) return 0; return d_axisData[axisId]->stepSize; } /*! \brief Return the current interval of the specified axis This is only a convenience function for axisScaleDiv( axisId )->interval(); \param axisId Axis index \return Scale interval \sa QwtScaleDiv, axisScaleDiv() */ QwtInterval QwtPlot::axisInterval( int axisId ) const { if ( !axisValid( axisId ) ) return QwtInterval(); return d_axisData[axisId]->scaleDiv.interval(); } /*! \return Title of a specified axis \param axisId Axis index */ QwtText QwtPlot::axisTitle( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->title(); else return QwtText(); } /*! \brief Enable or disable a specified axis When an axis is disabled, this only means that it is not visible on the screen. Curves, markers and can be attached to disabled axes, and transformation of screen coordinates into values works as normal. Only xBottom and yLeft are enabled by default. \param axisId Axis index \param tf \c true (enabled) or \c false (disabled) */ void QwtPlot::enableAxis( int axisId, bool tf ) { if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled ) { d_axisData[axisId]->isEnabled = tf; updateLayout(); } } /*! Transform the x or y coordinate of a position in the drawing region into a value. \param axisId Axis index \param pos position \return Position as axis coordinate \warning The position can be an x or a y coordinate, depending on the specified axis. */ double QwtPlot::invTransform( int axisId, int pos ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).invTransform( pos ) ); else return 0.0; } /*! \brief Transform a value into a coordinate in the plotting region \param axisId Axis index \param value value \return X or Y coordinate in the plotting region corresponding to the value. */ double QwtPlot::transform( int axisId, double value ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).transform( value ) ); else return 0.0; } /*! \brief Change the font of an axis \param axisId Axis index \param font Font \warning This function changes the font of the tick labels, not of the axis title. */ void QwtPlot::setAxisFont( int axisId, const QFont &font ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setFont( font ); } /*! \brief Enable autoscaling for a specified axis This member function is used to switch back to autoscaling mode after a fixed scale has been set. Autoscaling is enabled by default. \param axisId Axis index \param on On/Off \sa setAxisScale(), setAxisScaleDiv(), updateAxes() \note The autoscaling flag has no effect until updateAxes() is executed ( called by replot() ). */ void QwtPlot::setAxisAutoScale( int axisId, bool on ) { if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) ) { d_axisData[axisId]->doAutoScale = on; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. In updateAxes() the scale engine calculates a scale division from the specified parameters, that will be assigned to the scale widget. So updates of the scale widget usually happen delayed with the next replot. \param axisId Axis index \param min Minimum of the scale \param max Maximum of the scale \param stepSize Major step size. If step == 0, the step size is calculated automatically using the maxMajor setting. \sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize(), QwtScaleEngine::divideScale() */ void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.isValid = false; d.minValue = min; d.maxValue = max; d.stepSize = stepSize; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. The scale division will be stored locally only until the next call of updateAxes(). So updates of the scale widget usually happen delayed with the next replot. \param axisId Axis index \param scaleDiv Scale division \sa setAxisScale(), setAxisAutoScale() */ void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.scaleDiv = scaleDiv; d.isValid = true; autoRefresh(); } } /*! \brief Set a scale draw \param axisId Axis index \param scaleDraw Object responsible for drawing scales. By passing scaleDraw it is possible to extend QwtScaleDraw functionality and let it take place in QwtPlot. Please note that scaleDraw has to be created with new and will be deleted by the corresponding QwtScale member ( like a child object ). \sa QwtScaleDraw, QwtScaleWidget \warning The attributes of scaleDraw will be overwritten by those of the previous QwtScaleDraw. */ void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw ) { if ( axisValid( axisId ) ) { axisWidget( axisId )->setScaleDraw( scaleDraw ); autoRefresh(); } } /*! Change the alignment of the tick labels \param axisId Axis index \param alignment Or'd Qt::AlignmentFlags see \sa QwtScaleDraw::setLabelAlignment() */ void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelAlignment( alignment ); } /*! Rotate all tick labels \param axisId Axis index \param rotation Angle in degrees. When changing the label rotation, the label alignment might be adjusted too. \sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment() */ void QwtPlot::setAxisLabelRotation( int axisId, double rotation ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelRotation( rotation ); } /*! Set the maximum number of minor scale intervals for a specified axis \param axisId Axis index \param maxMinor Maximum number of minor steps \sa axisMaxMinor() */ void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor ) { if ( axisValid( axisId ) ) { maxMinor = qBound( 0, maxMinor, 100 ); AxisData &d = *d_axisData[axisId]; if ( maxMinor != d.maxMinor ) { d.maxMinor = maxMinor; d.isValid = false; autoRefresh(); } } } /*! Set the maximum number of major scale intervals for a specified axis \param axisId Axis index \param maxMajor Maximum number of major steps \sa axisMaxMajor() */ void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor ) { if ( axisValid( axisId ) ) { maxMajor = qBound( 1, maxMajor, 10000 ); AxisData &d = *d_axisData[axisId]; if ( maxMajor != d.maxMajor ) { d.maxMajor = maxMajor; d.isValid = false; autoRefresh(); } } } /*! \brief Change the title of a specified axis \param axisId Axis index \param title axis title */ void QwtPlot::setAxisTitle( int axisId, const QString &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } /*! \brief Change the title of a specified axis \param axisId Axis index \param title Axis title */ void QwtPlot::setAxisTitle( int axisId, const QwtText &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } /*! \brief Rebuild the axes scales In case of autoscaling the boundaries of a scale are calculated from the bounding rectangles of all plot items, having the QwtPlotItem::AutoScale flag enabled ( QwtScaleEngine::autoScale() ). Then a scale division is calculated ( QwtScaleEngine::didvideScale() ) and assigned to scale widget. When the scale boundaries have been assigned with setAxisScale() a scale division is calculated ( QwtScaleEngine::didvideScale() ) for this interval and assigned to the scale widget. When the scale has been set explicitly by setAxisScaleDiv() the locally stored scale division gets assigned to the scale widget. The scale widget indicates modifications by emitting a QwtScaleWidget::scaleDivChanged() signal. updateAxes() is usually called by replot(). \sa setAxisAutoScale(), setAxisScale(), setAxisScaleDiv(), replot() QwtPlotItem::boundingRect() */ void QwtPlot::updateAxes() { // Find bounding interval of the item data // for all axes, where autoscaling is enabled QwtInterval intv[axisCnt]; const QwtPlotItemList& itmList = itemList(); QwtPlotItemIterator it; for ( it = itmList.begin(); it != itmList.end(); ++it ) { const QwtPlotItem *item = *it; if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) ) continue; if ( !item->isVisible() ) continue; if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) ) { const QRectF rect = item->boundingRect(); if ( rect.width() >= 0.0 ) intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() ); if ( rect.height() >= 0.0 ) intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() ); } } // Adjust scales for ( int axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; double minValue = d.minValue; double maxValue = d.maxValue; double stepSize = d.stepSize; if ( d.doAutoScale && intv[axisId].isValid() ) { d.isValid = false; minValue = intv[axisId].minValue(); maxValue = intv[axisId].maxValue(); d.scaleEngine->autoScale( d.maxMajor, minValue, maxValue, stepSize ); } if ( !d.isValid ) { d.scaleDiv = d.scaleEngine->divideScale( minValue, maxValue, d.maxMajor, d.maxMinor, stepSize ); d.isValid = true; } QwtScaleWidget *scaleWidget = axisWidget( axisId ); scaleWidget->setScaleDiv( d.scaleDiv ); int startDist, endDist; scaleWidget->getBorderDistHint( startDist, endDist ); scaleWidget->setBorderDist( startDist, endDist ); } for ( it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item->testItemInterest( QwtPlotItem::ScaleInterest ) ) { item->updateScaleDiv( axisScaleDiv( item->xAxis() ), axisScaleDiv( item->yAxis() ) ); } } } qsstv_8.2.12/qwt/qwt_compass_rose.cpp000664 001750 001750 00000014743 12440612574 017713 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_compass_rose.h" #include "qwt_point_polar.h" #include "qwt_painter.h" #include static QPointF qwtIntersection( QPointF p11, QPointF p12, QPointF p21, QPointF p22 ) { const QLineF line1( p11, p12 ); const QLineF line2( p21, p22 ); QPointF pos; if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection ) return QPointF(); return pos; } class QwtSimpleCompassRose::PrivateData { public: PrivateData(): width( 0.2 ), numThorns( 8 ), numThornLevels( -1 ), shrinkFactor( 0.9 ) { } double width; int numThorns; int numThornLevels; double shrinkFactor; }; /*! Constructor \param numThorns Number of thorns \param numThornLevels Number of thorn levels */ QwtSimpleCompassRose::QwtSimpleCompassRose( int numThorns, int numThornLevels ) { d_data = new PrivateData(); d_data->numThorns = numThorns; d_data->numThornLevels = numThornLevels; const QColor dark( 128, 128, 255 ); const QColor light( 192, 255, 255 ); QPalette palette; palette.setColor( QPalette::Dark, dark ); palette.setColor( QPalette::Light, light ); setPalette( palette ); } //! Destructor QwtSimpleCompassRose::~QwtSimpleCompassRose() { delete d_data; } /*! Set the Factor how to shrink the thorns with each level The default value is 0.9. \param factor Shrink factor \sa shrinkFactor() */ void QwtSimpleCompassRose::setShrinkFactor( double factor ) { d_data->shrinkFactor = factor; } /*! \return Factor how to shrink the thorns with each level \sa setShrinkFactor() */ double QwtSimpleCompassRose::shrinkFactor() const { return d_data->shrinkFactor; } /*! Draw the rose \param painter Painter \param center Center point \param radius Radius of the rose \param north Position \param cg Color group */ void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup cg ) const { QPalette pal = palette(); pal.setCurrentColorGroup( cg ); drawRose( painter, pal, center, radius, north, d_data->width, d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor ); } /*! Draw the rose \param painter Painter \param palette Palette \param center Center of the rose \param radius Radius of the rose \param north Position pointing to north \param width Width of the rose \param numThorns Number of thorns \param numThornLevels Number of thorn levels \param shrinkFactor Factor to shrink the thorns with each level */ void QwtSimpleCompassRose::drawRose( QPainter *painter, const QPalette &palette, const QPointF ¢er, double radius, double north, double width, int numThorns, int numThornLevels, double shrinkFactor ) { if ( numThorns < 4 ) numThorns = 4; if ( numThorns % 4 ) numThorns += 4 - numThorns % 4; if ( numThornLevels <= 0 ) numThornLevels = numThorns / 4; if ( shrinkFactor >= 1.0 ) shrinkFactor = 1.0; if ( shrinkFactor <= 0.5 ) shrinkFactor = 0.5; painter->save(); painter->setPen( Qt::NoPen ); for ( int j = 1; j <= numThornLevels; j++ ) { double step = qPow( 2.0, j ) * M_PI / numThorns; if ( step > M_PI_2 ) break; double r = radius; for ( int k = 0; k < 3; k++ ) { if ( j + k < numThornLevels ) r *= shrinkFactor; } double leafWidth = r * width; if ( 2.0 * M_PI / step > 32 ) leafWidth = 16; const double origin = qwtRadians( north ); for ( double angle = origin; angle < 2.0 * M_PI + origin; angle += step ) { const QPointF p = qwtPolar2Pos( center, r, angle ); const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 ); const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 ); const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 ); const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 ); QPainterPath darkPath; darkPath.moveTo( center ); darkPath.lineTo( p ); darkPath.lineTo( qwtIntersection( center, p3, p1, p ) ); painter->setBrush( palette.brush( QPalette::Dark ) ); painter->drawPath( darkPath ); QPainterPath lightPath; lightPath.moveTo( center ); lightPath.lineTo( p ); lightPath.lineTo( qwtIntersection( center, p4, p2, p ) ); painter->setBrush( palette.brush( QPalette::Light ) ); painter->drawPath( lightPath ); } } painter->restore(); } /*! Set the width of the rose heads. Lower value make thinner heads. The range is limited from 0.03 to 0.4. \param width Width */ void QwtSimpleCompassRose::setWidth( double width ) { d_data->width = width; if ( d_data->width < 0.03 ) d_data->width = 0.03; if ( d_data->width > 0.4 ) d_data->width = 0.4; } /*! \return Width of the rose \sa setWidth() */ double QwtSimpleCompassRose::width() const { return d_data->width; } /*! Set the number of thorns on one level The number is aligned to a multiple of 4, with a minimum of 4 \param numThorns Number of thorns \sa numThorns(), setNumThornLevels() */ void QwtSimpleCompassRose::setNumThorns( int numThorns ) { if ( numThorns < 4 ) numThorns = 4; if ( numThorns % 4 ) numThorns += 4 - numThorns % 4; d_data->numThorns = numThorns; } /*! \return Number of thorns \sa setNumThorns(), setNumThornLevels() */ int QwtSimpleCompassRose::numThorns() const { return d_data->numThorns; } /*! Set the of thorns levels \param numThornLevels Number of thorns levels \sa setNumThorns(), numThornLevels() */ void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels ) { d_data->numThornLevels = numThornLevels; } /*! \return Number of thorn levels \sa setNumThorns(), setNumThornLevels() */ int QwtSimpleCompassRose::numThornLevels() const { return d_data->numThornLevels; } qsstv_8.2.12/qwt/qwt_plot_barchart.h000664 001750 001750 00000006746 12440612574 017513 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_BAR_CHART_H #define QWT_PLOT_BAR_CHART_H #include "qwt_global.h" #include "qwt_plot_abstract_barchart.h" #include "qwt_series_data.h" class QwtColumnRect; class QwtColumnSymbol; /*! \brief QwtPlotBarChart displays a series of a values as bars. Each bar might be customized individually by implementing a specialSymbol(). Otherwise it is rendered using a default symbol. Depending on its orientation() the bars are displayed horizontally or vertically. The bars cover the interval between the baseline() and the value. By activating the LegendBarTitles mode each sample will have its own entry on the legend. The most common use case of a bar chart is to display a list of y coordinates, where the x coordinate is simply the index in the list. But for other situations ( f.e. when values are related to dates ) it is also possible to set x coordinates explicitly. \sa QwtPlotMultiBarChart, QwtPlotHistogram, QwtPlotCurve::Sticks, QwtPlotSeriesItem::orientation(), QwtPlotAbstractBarChart::baseline() */ class QWT_EXPORT QwtPlotBarChart: public QwtPlotAbstractBarChart, public QwtSeriesStore { public: /*! \brief Legend modes. The default setting is QwtPlotBarChart::LegendChartTitle. \sa setLegendMode(), legendMode() */ enum LegendMode { /*! One entry on the legend showing the default symbol and the title() of the chart \sa QwtPlotItem::title() */ LegendChartTitle, /*! One entry for each value showing the individual symbol of the corresponding bar and the bar title. \sa specialSymbol(), barTitle() */ LegendBarTitles }; explicit QwtPlotBarChart( const QString &title = QString::null ); explicit QwtPlotBarChart( const QwtText &title ); virtual ~QwtPlotBarChart(); virtual int rtti() const; void setSamples( const QVector & ); void setSamples( const QVector & ); void setSamples( QwtSeriesData *series ); void setSymbol( QwtColumnSymbol * ); const QwtColumnSymbol *symbol() const; void setLegendMode( LegendMode ); LegendMode legendMode() const; virtual void drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual QwtColumnSymbol *specialSymbol( int sampleIndex, const QPointF& ) const; virtual QwtText barTitle( int sampleIndex ) const; protected: virtual void drawSample( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QPointF& sample ) const; virtual void drawBar( QPainter *, int sampleIndex, const QPointF& point, const QwtColumnRect & ) const; QList legendData() const; QwtGraphic legendIcon( int index, const QSizeF & ) const; private: void init(); class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_compass_rose.h000664 001750 001750 00000004245 12440612574 017354 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COMPASS_ROSE_H #define QWT_COMPASS_ROSE_H 1 #include "qwt_global.h" #include class QPainter; /*! \brief Abstract base class for a compass rose */ class QWT_EXPORT QwtCompassRose { public: //! Destructor virtual ~QwtCompassRose() {}; //! Assign a palette virtual void setPalette( const QPalette &p ) { d_palette = p; } //! \return Current palette const QPalette &palette() const { return d_palette; } /*! Draw the rose \param painter Painter \param center Center point \param radius Radius of the rose \param north Position \param colorGroup Color group */ virtual void draw( QPainter *painter, const QPointF ¢er, double radius, double north, QPalette::ColorGroup colorGroup = QPalette::Active ) const = 0; private: QPalette d_palette; }; /*! \brief A simple rose for QwtCompass */ class QWT_EXPORT QwtSimpleCompassRose: public QwtCompassRose { public: QwtSimpleCompassRose( int numThorns = 8, int numThornLevels = -1 ); virtual ~QwtSimpleCompassRose(); void setWidth( double w ); double width() const; void setNumThorns( int count ); int numThorns() const; void setNumThornLevels( int count ); int numThornLevels() const; void setShrinkFactor( double factor ); double shrinkFactor() const; virtual void draw( QPainter *, const QPointF ¢er, double radius, double north, QPalette::ColorGroup = QPalette::Active ) const; static void drawRose( QPainter *, const QPalette &, const QPointF ¢er, double radius, double origin, double width, int numThorns, int numThornLevels, double shrinkFactor ); private: class PrivateData; PrivateData *d_data; }; #endif qsstv_8.2.12/qwt/qwt_plot_layout.h000664 001750 001750 00000006224 12440612574 017231 0ustar00jomajoma000000 000000 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_LAYOUT_H #define QWT_PLOT_LAYOUT_H #include "qwt_global.h" #include "qwt_plot.h" /*! \brief Layout engine for QwtPlot. It is used by the QwtPlot widget to organize its internal widgets or by QwtPlot::print() to render its content to a QPaintDevice like a QPrinter, QPixmap/QImage or QSvgRenderer. \sa QwtPlot::setPlotLayout() */ class QWT_EXPORT QwtPlotLayout { public: /*! Options to configure the plot layout engine \sa activate(), QwtPlotRenderer */ enum Option { //! Unused AlignScales = 0x01, /*! Ignore the dimension of the scrollbars. There are no scrollbars, when the plot is not rendered to widgets. */ IgnoreScrollbars = 0x02, //! Ignore all frames. IgnoreFrames = 0x04, //! Ignore the legend. IgnoreLegend = 0x08, //! Ignore the title. IgnoreTitle = 0x10, //! Ignore the footer. IgnoreFooter = 0x20 }; //! Layout options typedef QFlags